Я писал на С#,делал на BackgroungWorker. Грубо вырезанный кусок кода....
private void TransferWorker_DoWork(object sender, DoWorkEventArgs e)
{
// переменная для снятия из очереди
Packet pkt;
// массив для передачи
byte[] wr_buf = new byte[6];
// массив для приема
byte[] rd_buf = new byte[6];
// цикл до отмены работы или опустошения очереди запросов
/// TODO теперь не выходит по завершению очереди - уменьшить на переключение контекста задач
while ((_TransferWorker.CancellationPending == false))// && (_toTransfer.Count != 0))
{
case Mode_transfer.Read_ADC:// Чтение данных
Массив data = pkt.obj as Массив;
// читаем АЦП
wr_buf[0] = Convert.ToByte('A');
wr_buf[1] = (byte)0;
// Пишем отправляеммый пакет
_Serial.Write(wr_buf, 0, 2);
// ждем пока весь пакет уйдет или запросят отбой
while ((_TransferWorker.CancellationPending == false) && (_Serial.BytesToWrite != 0)) ;
// попытка поймать заголовок
try
{
int dummy = 0, lenghtReadingPacket;
bool end = false;
int counter =0;
while (end != true){
dummy = _Serial.BytesToRead;
if (dummy <= 3)
{
System.Threading.Thread.Sleep(1);
if (counter++ > _Serial.ReadTimeout)
{
_dataLostArgs.ErrorPreambulaLen++;
throw new TimeoutException("Preambula not full!");
}
}
else end = true;
}
dummy = _Serial.Read(rd_buf, 0, 3);
var dummy2 = dummy;
if ((dummy != 3))
{
_dataLostArgs.ErrorPreambulaLen++;
throw new TimeoutException("Preambula not full!");
}
if (rd_buf[(int)ADC_Packet.Name] != 'D'){
_dataLostArgs.PreambulaLost ++;
throw new TimeoutException("Data preambula lost!");
}
// длина пакета в словах
lenghtReadingPacket = rd_buf[(int)ADC_Packet.LenghtOfPacket];
byte[] rd_buf_ADC = new byte[lenghtReadingPacket * 2 + 1];
end = false;
counter = 0;
while (end != true){
dummy = _Serial.BytesToRead;
if (dummy < (lenghtReadingPacket * 2 + 1))
{
System.Threading.Thread.Sleep(1);
if (counter++ > _Serial.ReadTimeout + 100)
{
var dummy3 = _Serial.Read(rd_buf_ADC, 0, lenghtReadingPacket * 2 + 1);
_dataLostArgs.PoorPacket++;
throw new TimeoutException();
}
}
else end = true;
}
dummy = _Serial.Read(rd_buf_ADC, 0, lenghtReadingPacket * 2 + 1);
if (dummy == (lenghtReadingPacket * 2 + 1))
for (Int32 i = 0; i < lenghtReadingPacket * 2 ; i += 2)
{
int a = rd_buf_ADC[i];
int b = rd_buf_ADC[i + 1];
if (a != 0 || b != 0) data.Add(rd_buf_ADC[i] * 256 + rd_buf_ADC[i + 1]);
}
else {
_dataLostArgs.PoorPacket++;
throw new TimeoutException("Not all bytes received!");
}
}
catch (TimeoutException)
{
/// TODO ПОдумать при зависании считывания АЦП
OnADCDataLost(this, _dataLostArgs);
}
finally
{
// Чистим за собой
_Serial.DiscardInBuffer();
_Serial.DiscardOutBuffer();
}
break;
Работало на пределе из-за скорости 510416 Бод на RS485. Код довольно грязный... Но смысл был в том что, первое чтение возвращало не весь пакет. Надо ВСЕГДА проверять возвращаемые значения функций чтения. И что-то делать если пакет приходит не весь и кусками. И с задержкой, ставить timeout Exception что бы не провалится в Read навсегда.