You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
11 KiB
C#
257 lines
11 KiB
C#
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<RXPacket> _responseTask;
|
|
private List<byte> _responseByteBuffer = new List<byte>();
|
|
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<byte> packet = new List<byte> { 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<bool> 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<bool> 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<RXPacket> 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<RXPacket>();
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|