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.

213 lines
9.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BirdyFlash.Lib {
public class CommPortSerial : CommPort {
private string portName;
private SerialPort port;
private byte _readState = 0x00;
private RXPacket tempPacket;
private TaskCompletionSource<RXPacket> _responseTask;
private List<byte> _responseByteBuffer = new List<byte>();
public CommPortSerial(string portName) {
this.port = new SerialPort
{
PortName = portName,
BaudRate = 57600,
DtrEnable = true,
RtsEnable = true,
Parity = Parity.None,
DataBits = 8,
StopBits = StopBits.One,
ReadTimeout = 5,
WriteTimeout = 5,
};
this.port.DataReceived += Port_DataReceived;
}
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 = BirdyComm.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 {0}", this.portName);
}
this.port.Dispose();
this._responseByteBuffer.Clear();
this._readState = 0x00;
Console.WriteLine("Init {0}@{1}bps", this.portName, 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 override string ToString() {
return "serial://" + this.portName;
}
public async override void ForceGotoProg() {
//int bdBefore = this.port.BaudRate;
this.ResetReOpen(9600);
for (int i = 0; i < 2; i++) {
this.SendRawSimplex(Encoding.ASCII.GetBytes("GOTOPROG"));
this.SendRawSimplex(Encoding.ASCII.GetBytes("GOTOPROG"));
this.SendRawSimplex(Encoding.ASCII.GetBytes("GOTOPROG"));
//await Task.Delay(320);
}
this.ResetReOpen(19600);
for (int i = 0; i < 3; i++) {
this.SendRawSimplex(Encoding.ASCII.GetBytes("GOTOPROG"));
this.SendRawSimplex(Encoding.ASCII.GetBytes("GOTOPROG"));
this.SendRawSimplex(Encoding.ASCII.GetBytes("GOTOPROG"));
//await Task.Delay(320);
}
this.ResetReOpen();
}
public override async Task<bool> SwitchHighspeed() {
if (this.port.BaudRate == 115200) return false;
Console.WriteLine("AskHighspeed {0}", this.portName);
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 override async Task<bool> SwitchLowspeed() {
if (this.port.BaudRate == 57600) return false;
Console.WriteLine("AskLowspeed {0}", this.portName);
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 override void SendRawSimplex(byte[] data) {
if (this.port.IsOpen == false) {
Console.WriteLine("Open {0}", this.portName);
this.port.Open();
this.port.DiscardInBuffer();
this.port.DiscardOutBuffer();
}
this.port.BaseStream.Write(data, 0, data.Length);
this.port.BaseStream.Flush();
Console.WriteLine("TXR {0}", BitConverter.ToString(data));
}
public override TaskCompletionSource<RXPacket> SendCommand(byte[] cmd) {
if (this.port.IsOpen == false) {
Console.WriteLine("Open {0}", this.portName);
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] = BirdyComm.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;
}
public override void Dispose() {
Console.WriteLine("Disposing");
if (this.port.IsOpen == true) {
this.port.DiscardInBuffer();
this.port.DiscardOutBuffer();
this.port.Close();
}
this.port.Dispose();
this._responseByteBuffer.Clear();
//this._responseTask.Task.Dispose();
}
}
}