using AwInitilizer.Model; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace AwInitilizer.Assist { public class SerialPortocol : INotifyPropertyChanged { private static int TimeoutDuration = 1 * 1000; public event EventHandler OnMsgReceived; public event PropertyChangedEventHandler PropertyChanged; public string LatestErrorMessage { get; private set; } private Interface.ISerialPort _serialPort; private SemaphoreQueue receivedBufferLock = new SemaphoreQueue(1, 1); private byte[] receivedBuffer = new byte[0]; private bool IsSerialPortAvaliable { get { if (_serialPort == null || _serialPort.ConnectStatus != Interface.ConnectStatus.Connected) return false; return true; } } public void Open() => _serialPort?.Open(); public void Close() => _serialPort?.Close(); public Interface.ConnectStatus ConnectStatus => _serialPort == null ? Interface.ConnectStatus.Cleared : _serialPort.ConnectStatus; public SerialPortocol(Interface.ISerialPort serialPort) { _serialPort = serialPort; _serialPort.OnDataReceived += _serialPort_OnDataReceived; _serialPort.PropertyChanged += _serialPort_PropertyChanged; } public async Task GetModelName() { return await SendAndWait(0x24, SimpleStringParser); } public async Task SetModelName(string modelName) { var param = Encoding.ASCII.GetBytes(modelName); return await SendAndWait(0x83, SimpleResultParser, parameter: param); } public async Task GetSerialNumber() { return await SendAndWait(0x23, SerialNumberParser); string SerialNumberParser(byte[] parameter) { if (parameter == null || parameter.Length < 19) return null; var snBytes = parameter.Skip(8).ToArray(); return SimpleStringParser(snBytes); } } public async Task SetSerialNumber(string serialNumber) { DateTime nowTime = DateTime.Now.ToUniversalTime(); var DataString = nowTime.ToString("yyyyMMdd"); var dateTimeParam = Encoding.ASCII.GetBytes(DataString); var snParam = Encoding.ASCII.GetBytes(serialNumber); var param = new byte[dateTimeParam.Length + snParam.Length]; Array.Copy(dateTimeParam, 0, param, 0, dateTimeParam.Length); Array.Copy(snParam, 0, param, dateTimeParam.Length, snParam.Length); return await SendAndWait(0x82, SimpleResultParser, parameter: param); } public async Task GetUTCTime() { return await SendAndWait(0x26, TimeParser); DateTime? TimeParser(byte[] parameter) { if (parameter == null || parameter.Length < 14) return null; string rawDateString = Encoding.ASCII.GetString(parameter); var year = int.Parse(rawDateString.Substring(0,4)); var month = int.Parse(rawDateString.Substring(4, 2)); var day = int.Parse(rawDateString.Substring(6, 2)); var hour = int.Parse(rawDateString.Substring(8, 2)); var minut = int.Parse(rawDateString.Substring(10, 2)); var sec = int.Parse(rawDateString.Substring(12, 2)); try { DateTime dateTime = new DateTime(year, month, day, hour, minut, sec); return dateTime; } catch { return null; } } } public async Task SetUTCTime(DateTime dateTime) { var DataString = dateTime.ToString("yyyyMMddHHmmss"); var param = Encoding.ASCII.GetBytes(DataString); return await SendAndWait(0x87, SimpleResultParser, parameter: param); } public async Task GetFourGenModuleVersion() { return await SendAndWait(0x31, SimpleStringParser, WaitSec: 5); } public async Task GetSimStatus() { return await SendAndWait(0x34, SimStatusParser); SimStatus SimStatusParser(byte[] param) { if(param==null || param.Length != 39) { return null; } SimStatus toReturn = new SimStatus(); toReturn.IsInstalled = param[0] == 0x01; toReturn.ICCID = param.Skip(1).Take(22).ToArray(); toReturn.IMSI = param.Skip(22).Take(16).ToArray(); return toReturn; } } public async Task SettingChangeConfirm() { return await SendAndWait(0x91, SimpleResultParser, WaitSec: 10); } private void _serialPort_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(Interface.ISerialPort.ConnectStatus)) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SerialPortocol.ConnectStatus))); } } private async Task SendAndWait(byte command, Func ParserFunction, byte[] parameter = null, T defauit = default(T), int WaitSec = -1) { if (!IsSerialPortAvaliable) return defauit; T result = defauit; SemaphoreSlim signal = new SemaphoreSlim(0, 1); OnMsgReceived += EvseSerialProtocal_OnMsgReceived; if (SendMessage(command, parameter)) { if (WaitSec < 0) await signal.WaitAsync(TimeoutDuration); else await signal.WaitAsync(WaitSec * 1000); } OnMsgReceived -= EvseSerialProtocal_OnMsgReceived; if (signal.CurrentCount == 0) { //timeout LatestErrorMessage = "Serial portocol timeout"; } return result; void EvseSerialProtocal_OnMsgReceived(object sender, EvseSerialResponseModel e) { if (e.Command == command) { result = ParserFunction(e.Parameter); signal.Release(); } } } private bool SendMessage(byte command, byte[] parameter = null) { if (!IsSerialPortAvaliable) return false; int parameterLength = parameter == null ? 0 : parameter.Length; int messagLength = parameterLength + 7; byte[] message = new byte[parameterLength + 7]; message[0] = 0xAA; message[1] = 0x10; //Master message[2] = 0xFF; //broadcast message[3] = command; message[4] = (byte)(parameterLength % 256); message[5] = (byte)(parameterLength / 256); if (parameter != null && parameter.Length > 0) Array.Copy(parameter, 0, message, 6, parameter.Length); byte chksum = 0x00; for (int idx = 0; idx < parameterLength; idx++) chksum ^= message[6 + idx]; message[6 + parameterLength] = chksum; _serialPort?.WriteData(message); //_serialPort?.WriteData(message); return true; } private void _serialPort_OnDataReceived(object sender, byte[] e) { receivedBufferLock.Wait(); { var tmp = new byte[e.Length + receivedBuffer.Length]; Array.Copy(receivedBuffer, 0, tmp, 0, receivedBuffer.Length); Array.Copy(e, 0, tmp, receivedBuffer.Length, e.Length); //receivedBuffer = tmp; receivedBuffer = ParseReceive(tmp, out List reponseModels); foreach (EvseSerialResponseModel responseModel in reponseModels) { OnMsgReceived?.Invoke(this, responseModel); } } receivedBufferLock.Release(); } private bool SimpleResultParser(byte[] parameter) { if (parameter == null || parameter.Length != 1) return false; var resultByte = parameter[0]; return resultByte == 0x01; } private string SimpleHexStringParser(byte[] parameter) { if (parameter == null) { return default; } return BitConverter.ToString(parameter).Replace("-", " "); } private string SimpleStringParser(byte[] parameter) { if(parameter == null) { LatestErrorMessage = "parameter null exception"; return string.Empty; } if (parameter.Length <= 1) { LatestErrorMessage = $"parameter legnth {parameter.Length} error"; return string.Empty; } if(parameter.ToList().Contains(0x00)) { int endIndex = Array.FindIndex(parameter, (x) => { return x == 0x00; }); //int endIndex = parameter.FindIndex((x) => { return x == 0x00; }); if (endIndex != default) { parameter = parameter.Take(endIndex).ToArray(); } } while (parameter.Length != 0 && parameter[parameter.Length - 1] < 32) { parameter = parameter.Take(parameter.Length - 1).ToArray(); } try { var result = Encoding.ASCII.GetString(parameter); return result; } catch(Exception e) { LatestErrorMessage = $"string parse exception : {e.Message}"; return string.Empty; } } private byte[] ParseReceive(byte[] parseData, out List reponseModels) { reponseModels = new List(); while (true) { int stIndex = -1; //find first 0xff 0xff for (int index = 0; index < parseData.Length - 1; index++) { if (parseData[index] == 0xAA) { stIndex = index; break; } } //int index = Array.IndexOf(receivedBuffer, startChar); if (stIndex < 0) break; //discard data before 0xaa parseData = parseData.Skip(stIndex).ToArray(); //response msg is at leat 6 bytes if (parseData.Length < 6) break; var msgLength = parseData[5] * 256 + parseData[4]; if (parseData.Length < msgLength + 6) break; //Add handle data reponseModels.Add(new EvseSerialResponseModel() { Source = parseData[1], Destination = parseData[2], Command = parseData[3], Parameter = parseData.Skip(6).Take(msgLength).ToArray() }); parseData = parseData.Skip(msgLength + 6).ToArray(); } return parseData; } } }