using System; using System.Collections.Generic; using System.IO; using System.IO.Ports; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; namespace RemoteBirdyPort { public struct RXPacket { public bool valid; public byte dataLength; public byte readLength; public byte[] data; public byte crc; public byte rcrc; } class Program { private byte _readState = 0x00; private RXPacket tempPacket; private TaskCompletionSource _responseTask; private List _responseByteBuffer = new List(); private SerialPort port; static void Main(string[] args) { try { Task.WaitAny(Task.Run(()=> new Program().Run())); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.WriteLine("dead"); Console.ReadLine(); } public Program() { } public async void Run() { Console.WriteLine("Hello World!"); this.port = new SerialPort { PortName = "COM5", BaudRate = 57600, DtrEnable = true, RtsEnable = true, Parity = Parity.None, DataBits = 8, StopBits = StopBits.One, ReadTimeout = 5, WriteTimeout = 5, }; port.DataReceived += Port_DataReceived; TcpListener portServer = new TcpListener(IPAddress.Any, 33333); portServer.Start(); while (true) { try { TcpClient client = portServer.AcceptTcpClient(); BinaryReader rx = new BinaryReader(client.GetStream()); BinaryWriter tx = new BinaryWriter(client.GetStream()); this.ResetReOpen(115200); try { var task = this.SwitchLowspeed(); await Task.WhenAny(task, Task.Delay(500)); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } this.ResetReOpen(57600); Console.WriteLine("ready"); while (client.Connected) { Console.WriteLine("Wait RX"); if (rx.PeekChar() == -1) continue; var packetType = rx.ReadByte(); Console.WriteLine("Got Packet {0:X2}", packetType); var packetLength = rx.ReadByte() << 8 | rx.ReadByte(); Console.WriteLine("Length= {0}", packetLength); var packetPayload = rx.ReadBytes(packetLength); Console.WriteLine("RX= {0}", BitConverter.ToString(packetPayload)); byte responseType = 0x29; byte[] response = new byte[] {}; switch (packetType) { case 0x30: // IdentifierRequest responseType = 0x31; response = System.Text.Encoding.ASCII.GetBytes("BirdyRemotePort v0.1"); break; case 0x31: // EchoRequest responseType = 0x30; response = packetPayload; break; case 0x32: // SerialRequest responseType = 0x33; var tsk = SendCommand(packetPayload); Task.WaitAll(tsk.Task); response = tsk.Task.Result.data; break; case 0x34: { // SerialRequest responseType = 0x35; bool succ = false; if (packetLength == 1 && packetPayload[0] == 0x00) succ = await SwitchLowspeed(); if (packetLength == 1 && packetPayload[0] == 0x01) succ = await SwitchHighspeed(); response = new byte[] { (byte)(succ ? 0x01 : 0x00) }; } break; } List packet = new List { responseType, (byte)(response.Length >> 8 & 0xFF), (byte)(response.Length & 0xFF) }; packet.AddRange(response); tx.Write(packet.ToArray()); tx.Flush(); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } public async Task SwitchHighspeed() { if (this.port.BaudRate == 115200) return false; Console.WriteLine("AskHighspeed"); var task = this.SendCommand(new byte[] { 0x25, 0x01 }); await task.Task; var res = task.Task.Result; bool succ = (res.dataLength == 0x01 && res.data[0] == 0x06); if (succ) { Console.WriteLine("ChangeSpeed result {0}", res.data[0]); await Task.Delay(250); this.ResetReOpen(115200); } return succ; } public async Task SwitchLowspeed() { if (this.port.BaudRate == 57600) return false; Console.WriteLine("AskLowspeed"); var task = this.SendCommand(new byte[] { 0x25, 0x00 }); await task.Task; var res = task.Task.Result; bool succ = (res.dataLength == 0x01 && res.data[0] == 0x06); if (succ) { Console.WriteLine("ChangeSpeed result {0}", res.data[0]); await Task.Delay(250); this.ResetReOpen(57600); } return succ; } public TaskCompletionSource SendCommand(byte[] cmd) { if (this.port.IsOpen == false) { Console.WriteLine("Open"); this.port.Open(); this.port.DiscardInBuffer(); this.port.DiscardOutBuffer(); } this._responseByteBuffer.Clear(); this._responseTask = new TaskCompletionSource(); var tx = new byte[2 + cmd.Length + 2 + 1]; tx[0x00] = 0x02; tx[0x01] = (byte)(cmd.Length & 0xFF); cmd.CopyTo(tx, 0x02); tx[cmd.Length + 0x02] = 0x03; tx[cmd.Length + 0x03] = Program.Checksum(tx, cmd.Length + 0x03); tx[cmd.Length + 0x04] = 0x04; this.port.BaseStream.Write(tx, 0, tx.Length); this.port.BaseStream.Flush(); Console.WriteLine("TX {0}", BitConverter.ToString(tx)); return this._responseTask; } private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { byte bte; try { do { bte = (byte)this.port.ReadByte(); switch (_readState) { case 0x00: if (bte == 0x02) { //start of data this._readState = 0x01; this.tempPacket = new RXPacket(); _responseByteBuffer.Clear(); _responseByteBuffer.Add(0x02); } break; case 0x01: tempPacket.dataLength = bte; tempPacket.readLength = 0x00; _responseByteBuffer.Add(tempPacket.dataLength); tempPacket.data = new byte[tempPacket.dataLength]; this._readState = 0x02; break; case 0x02: tempPacket.data[tempPacket.readLength++] = bte; if (tempPacket.readLength == tempPacket.dataLength) { Console.WriteLine("RXP[l={0}] {1}", tempPacket.dataLength, BitConverter.ToString(tempPacket.data)); _responseByteBuffer.AddRange(tempPacket.data); this._readState = 0x03; } break; case 0x03: if (bte == 0x03) { //start of crc this._readState = 0x04; _responseByteBuffer.Add(0x03); } break; case 0x04: tempPacket.crc = bte; tempPacket.rcrc = Program.Checksum(_responseByteBuffer.ToArray(), _responseByteBuffer.Count); tempPacket.valid = tempPacket.crc == tempPacket.rcrc; Console.WriteLine(BitConverter.ToString(_responseByteBuffer.ToArray())); Console.WriteLine("crcP {0} - crcR {1}", tempPacket.crc, tempPacket.rcrc); _responseByteBuffer.Add(tempPacket.crc); this._readState = 0x05; break; case 0x05: if (bte == 0x04) { //end of paclet _responseByteBuffer.Add(0x04); _responseTask.TrySetResult(tempPacket); this._readState = 0x00; } break; } } while (this.port.IsOpen && this.port.BytesToRead > 0); } catch (TimeoutException timeoutError) { Console.WriteLine(timeoutError.ToString()); } } public void ResetReOpen(int baudrate = 57600) { if (this.port.IsOpen == true) { this.port.DiscardInBuffer(); this.port.DiscardOutBuffer(); this.port.Close(); Console.WriteLine("Reset"); } this.port.Dispose(); this._responseByteBuffer.Clear(); this._readState = 0x00; Console.WriteLine("Init @{0}bps", baudrate); this.port = new SerialPort { PortName = this.port.PortName, BaudRate = baudrate, DtrEnable = true, RtsEnable = true, Parity = Parity.None, DataBits = 8, StopBits = StopBits.One, ReadTimeout = 5, WriteTimeout = 5, }; this.port.DataReceived += Port_DataReceived; } public static byte Checksum(byte[] data, int length) { byte r = 0x00; for (int i = 0; i < length; i++) r = (byte)((r + data[i] % 0x100) & 0xFF); return r; } } }