Стартовая страница › Форумы › Разработка и интеграция › Время ожидания или Timeout
- В этой теме 69 ответов, 3 участника, последнее обновление 7 месяцев назад сделано
Mikhail.
-
АвторСообщения
-
20.01.2023 в 17:02 #27113
JurasskPark
УчастникВ драйвере что я разрабатываю дошел до отправки и получения данных.
//Отправка запроса Connection.Write(bufferSender, 0, bufferSender.Length, ProtocolFormat.Hex, out logText); //Временный буфер countArray = Connection.Read(tmpbufferReceiver, 0, tmpbufferReceiver.Length, channel.ReadTimeout, ProtocolFormat.Hex, out logText);
Всё бы ничего, но драйвер ждет время, которое я передаю в Timeout, даже если данные давным давно пришли.
И я всё не могу понять, как мне сделать, чтобы Timeout весь не ждал, пошел смотреть исходники./// <summary> /// Reads data. /// </summary> public override int Read(byte[] buffer, int offset, int count, int timeout, ProtocolFormat format, out string logText) { try { int readCnt = 0; NetStream.ReadTimeout = timeout; // timeout is not maintained if all available data has been read Stopwatch stopwatch = Stopwatch.StartNew(); while (readCnt < count && stopwatch.ElapsedMilliseconds <= timeout) { // read data try { if (NetStream.DataAvailable) // checking DataAvailable is critical on Linux readCnt += NetStream.Read(buffer, readCnt + offset, count - readCnt); } catch (IOException) { } // accumulate data in the internal connection buffer if (readCnt < count) Thread.Sleep(DataAccumDelay); } logText = BuildReadLogText(buffer, offset, count, readCnt, format); if (readCnt > 0) UpdateActivityTime(); return readCnt; } catch (Exception ex) { throw new ScadaException(CommPhrases.ReadDataError + ": " + ex.Message, ex); } }
while (readCnt < count
А я вот не знаю сколько мне ожидать байт в ответе. В протоколе такого нет.
Может сделать еще одно условие, где количество ожидаемых байт не передаётся?public override int Read(byte[] buffer, int offset, int timeout, ProtocolFormat format, out string logText) { try { int readCnt = 0; NetStream.ReadTimeout = timeout; // timeout is not maintained if all available data has been read Stopwatch stopwatch = Stopwatch.StartNew(); while (readCnt > 0 && stopwatch.ElapsedMilliseconds <= timeout) { // read data try { if (NetStream.DataAvailable) // checking DataAvailable is critical on Linux readCnt += NetStream.Read(buffer, readCnt + offset, count - readCnt); } catch (IOException) { } } logText = BuildReadLogText(buffer, offset, readCnt, format); if (readCnt > 0) UpdateActivityTime(); return readCnt; } catch (Exception ex) { throw new ScadaException(CommPhrases.ReadDataError + ": " + ex.Message, ex); } }
-
Эта тема была изменена 8 месяцев, 2 недели назад от
JurasskPark.
-
Эта тема была изменена 8 месяцев, 2 недели назад от
JurasskPark.
20.01.2023 в 22:18 #27122JurasskPark
УчастникВот что мне нужно
/// <summary> /// Reads data. /// </summary> public override int Read(byte[] buffer, int offset, int timeout, ProtocolFormat format, out string logText) { try { int readCnt = 0; NetStream.ReadTimeout = timeout; // timeout is not maintained if all available data has been read Stopwatch stopwatch = Stopwatch.StartNew(); while (readCnt == 0 && stopwatch.ElapsedMilliseconds <= timeout) { // read data try { if (NetStream.DataAvailable) // checking DataAvailable is critical on Linux readCnt += NetStream.Read(buffer, offset, buffer.Length); } catch (IOException) { } } logText = BuildReadLogText(buffer, offset, readCnt, format); if (readCnt > 0) { Array.Resize(ref buffer, readCnt); logText = BuildReadLogText(buffer, offset, readCnt, format); UpdateActivityTime(); } return readCnt; } catch (Exception ex) { throw new ScadaException(CommPhrases.ReadDataError + ": " + ex.Message, ex); } }
21.01.2023 в 12:50 #27123manjey73
УчастникКакое у вас устройство? с последовательным портом?
Есть идентификаторы окончания пакета?21.01.2023 в 12:59 #27124manjey73
УчастникВ драйверах есть возможность остановки по байту, по массиву байт, по массивам байт при необходимости.
21.01.2023 в 15:29 #27126JurasskPark
УчастникКакое у вас устройство? с последовательным портом?
Есть идентификаторы окончания пакета?https://forum.rapidscada.ru/?topic=system-io-ports#post-27051
Протокол ModbusRTU доработанный производителем, что там три входных параметра, но количество и адрес регистра — нету.21.01.2023 в 15:31 #27127JurasskPark
УчастникВ драйверах есть возможность остановки по байту, по массиву байт, по массивам байт при необходимости.
А можете рассказать как для маленького ребёнка? Поподробнее. А то может и придётся Михаила дорабатывать. 🙂
21.01.2023 в 19:06 #27128manjey73
УчастникЕсли конец пакета можно идентифицировать, то механизм остановки по массиву байт реализован в драйверах. BinStopCondition в 5-й версии. В 6-й он немного изменился по вызову, но примерно то же самое. По крайней мере я не сильно изменял свой код.
Могу свой пример выложить, так как тоже когда-то столкнулся с протоколом, где нет длины, но можно идентифицировать пакет по определенному массиву байт + дочитать CS или CRC
21.01.2023 в 19:09 #27129manjey73
Участникв смысле механизм остановки реализован в ядре Scada, вы просто его реализовываете в драйвере по своему усмотрению
21.01.2023 в 19:27 #27130manjey73
Участникprivate static byte[] crlf = new byte[] { 0x0D, 0x0A }; private static byte[] drlf = new byte[] { 0x8D, 0x0A }; private static byte[] etx = new byte[] { 0x03 }; private static byte[] ack = new byte[] { 0x06 }; private readonly static MyStopCondition StopCond; private static List<byte[]> stopList = new List<byte[]>();
public class MyStopCondition : BinStopCondition // TEST логики остановки по двум или более массивам BinStopCondition { public MyStopCondition(List<byte[]> stopL) { Stop = stopL; } public List<byte[]> Stop { get; private set; } public override bool CheckCondition(byte[] buffer, int index) { foreach (var stop in Stop) { StopSeq = stop; if (base.CheckCondition(buffer, index)) return true; } return false; } }
static DevXXXXXLogic() { stopList.AddRange(new[] { drlf, crlf, etx, ack }); StopCond = new MyStopCondition(stopList); }
Тут сложный вымученный код, можно упростить
/// <summary> /// Считать ответ из последовательного порта /// </summary> private void ReadAnswer(byte[] buffer, byte lastByte, out int readCnt, out string logText) { // считывание данных до получения массивов остановки bool stopReceived = false; bool checkWhile; readCnt = 0; // Чтение после 0x0D 0x0A если первый символ STX do { checkWhile = false; int readCnt1 = Connection.Read(buffer, readCnt, MaxRxDLen, PollingOptions.Timeout, StopCond, out stopReceived, ProtocolFormat.String, out logText); readCnt += readCnt1; if (!prog7e1) { if (stopReceived && readCnt < MaxRxDLen && StopCond.StopSeq.SequenceEqual(crlf) && buffer[0] == stx) { checkWhile = true; } } else { if (stopReceived && readCnt < MaxRxDLen && StopCond.StopSeq.SequenceEqual(drlf) && buffer[0] == dtx) { checkWhile = true; } } } while (checkWhile); // считывание последнего байта после ETX if (stopReceived && readCnt < MaxRxDLen && StopCond.StopSeq.SequenceEqual(etx)) { string logText2; int readCnt2 = Connection.Read(buffer, readCnt, 1, PollingOptions.Timeout, ProtocolFormat.String, out logText2); if (readCnt2 > 0) { readCnt += readCnt2; } } // При программной эмуляции 7-E-1 сбрасывать старший бит if (prog7e1) { for (int i = 0; i < readCnt; i++) { buffer[i] = Convert.ToByte(buffer[i] & 0x7F); } } // ----------------------------- logText = BuildReadLogText(buffer, 0, readCnt, ProtocolFormat.String); }
BuildReadLogText — а это надо повторить, так как прямого доступа как в 5-й нет
/// <summary> /// Builds a log text about reading data. /// </summary> protected static string BuildReadLogText(byte[] buffer, int offset, int readCnt, ProtocolFormat format) { return $"{CommPhrases.ReceiveNotation} ({readCnt}): " + ScadaUtils.BytesToString(buffer, offset, readCnt, format == ProtocolFormat.Hex); }
Вроде ничего не забыл, но если будет на что ругаться, пишите, найду в коде. Ну и из-за того, что по нескольким разным массивам идет остановка у меня там цикл проверок… Если всегда одинаковое, то можно упростить
21.01.2023 в 19:32 #27131manjey73
УчастникБлин, вам всего этого не надо…. у вас есть
ADR КФ N Байт 1 Байт 2 … … Байт N CRCМЛ CRCСТ
Размер блока передаваемых данных. Суть та же, что и в Modbus, считали первые три байта, узнали размер блока + CRC и дочитали остальное…
21.01.2023 в 19:35 #27132manjey73
Участник// Прием заголовка buf_in = new byte[4]; Connection.Read(buf_in, 0, buf_in.Length, PollingOptions.Timeout, ProtocolFormat.Hex, out logText); //считать значение из порта Log.WriteLine(logText); // TEST TEST TEST костыль - повтор кода при приеме // Прием тела ответа с CRC и завершающим символом buf_in_res = new byte[buf_in[1] + 2]; // Буфер тела ответа TEST TEST readcnt = Connection.Read(buf_in_res, 0, buf_in_res.Length, PollingOptions.Timeout, ProtocolFormat.Hex, out logText); //считать значение из порта Log.WriteLine(logText);
В нужном байте у вас размер, добавляете +2 байта на контрольную сумму. Ну и входной буфер у вас должен быть по размеру, который вам надо прочесть и определить размер
21.01.2023 в 21:54 #27133JurasskPark
УчастникРазмер блока передаваемых данных. Суть та же, что и в Modbus, считали первые три байта, узнали размер блока + CRC и дочитали остальное…
Нет там такого. 🙂
21.01.2023 в 22:05 #27134manjey73
УчастникГде нет? в Modbus или у вас в протоколе? вроде и там и там есть, я же показал N это и есть байт размера блока данных
N – размер блока передаваемых данных (от 1 до 255);
Из pdf по вашему вычислителю, страница 6, Общий вид ответа
21.01.2023 в 22:11 #27137manjey73
УчастникПри чем вам надо принимать 6 байт, проверять ответил ли прибор ошибкой на запрос, если не ошибкой, то смотреть 3-й байт ответа (2-й массива), рассчитывать длину и делать тут же запрос на оставшуюся часть ответа, выполняя остановку. Тогда таймаут мешать вам не будет.
21.01.2023 в 22:29 #27138manjey73
УчастникДля других ответов N у вас X4 то есть вам надо в зависимости от запросов понимать что из себя представляет N, просто количество или количество параметров х 4 байта.
-
Эта тема была изменена 8 месяцев, 2 недели назад от
-
АвторСообщения
- Вы должны авторизироваться для ответа в этой теме.