|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
Здравствуйте. Заранее прошу прощение за длинное вступление с исходными данными, но дьявол, как известно кроется в деталях..( Есть устройство подключенное через COM-порт RS-232С, нужно посредством своей программы передать и получить ответ только для одной команды (вообще их там много, но смогу понять принцип и подтянуть другие уже самостоятельно). Есть спецификация (ниже), из минусов: знаний- 0, всегда сторонился COM и иже с ним.. Также нет возможности опробовать код "в деле". Но показалось, что шаги довольно чётко расписаны в доках, - посему понадеялся на лучшее (в след.комментарии, то что наваял в Delphi). Вроде бы все норм., но есть сомнения.. Посмотрите пожалуйста профессиональным взлядом, все-ли правильно в коде (с точки зрения синтаксиса, т.е понятное дело, - все компилируется в Delphi 10.1), а то реально нет пока возможности затестить все это хозяйство в паре с купюрораздатчиком.. Прикрепил на всякий случай исходники и оригинальный PDF-файл спецификации, откуда почерпнул вводную информацию ниже по тексту. Вводные данные Общ. схема взаимодействия Клиент-Сервера:
Метод передачи - полудуплексный режим (HDM). Когда диспенсер работает, сообщение с верхнего уровня (ПК) игнорируется. Основные передаваемые символы приведены ниже. Код: sql 1. 2. 3. 4. 5. 6. 7.
В случае передачи физическое "рукопожатие" не используется. Соблюдаются только RXD и TXD спецификация, определеные в RS-232C Оригинальный текст: In case of transmission, physical handshake is not used. Only RXD and TXD defined in RS-232C specification is observed. Основные тайминги (Минимум - Макс.): Код: sql 1. 2. 3. 4.
Протокол сообщений: Протокол сообщений немного варьируется в зависимости от команды запроса или ответа. Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
Вот с этим "беда" на вскидку, не могу сообразить.. Код: sql 1. 2. 3. 4.
Далее сама команда, которую "собрал" в коде: Описание из документации (постарался привести к читабельному виду): Команда приведет к выдаче запрошенного количества банкнот из выбранной кассеты. Диспенсер проверит толщину и длину банкнот, которые соотносятся с OPACITY и LENGTH, а затем решит, выдать ли банкноты или отклонить. Во время процесса другие параметры, такие как необходимое расстояние между купюрами и перекос самих банкнот также влияют на выдачу и отклонение. Количество запрошенных банкнот для выдачи не должно превышать 20. Поле SERIAL предназначено для последовательного подсчета и играет роль идентификации команды дозатора. Если текущий SERIAL такой же, как и у предыдущей команды, произойдет ошибка(0x3D). Чтобы избежать неожиданной путаницы в команде «Раздать», хост должен посылать разные числа или последовательные номера каждый раз на SERIAL, когда он отправляет команду Disapnese в VCDM. Команда "DISPENSE" (Multi-Cassette Dispense) Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31.
////////////////////////////////////////////////////////////////////////// //Сам код, что удалось пока интуитивно "склеить" //////////////// Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 03:45 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
Оборудование должно быть под рукой, иначе будете несколько лет отлаживать работу с диспенсером. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 07:34 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
скелА Вот с этим "беда" на вскидку, не могу сообразить.. Код: sql 1. 2. 3. 4.
Это контрольный байт, полученный XOR-ом всех предыдущих Т.е. пишешь что-то вроде Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9.
... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 08:27 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
автор with TimeOuts do begin { Понял, что это тайминги (отметил их в комментарии выше), не знаю нужно-ли их вообще трогать здесь, подскажите пожалуйста} ReadIntervalTimeout := 1; ReadTotalTimeoutMultiplier := 0; ReadTotalTimeoutConstant := 1; WriteTotalTimeoutMultiplier := 2; WriteTotalTimeoutConstant := 2; end; Тайминги нужны, а как же без них! Но думаю, должно быть как-то так (кто этим пользуется, поправьте меня, если я не прав!): Код: pascal 1. 2. 3. 4. 5. 6. 7.
... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 09:51 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
скелА, 1. Ты, конечно, переводишь всё в байты перед посылкой, но это не нужно, используй сразу AnsiString/AnsiChar, раз уж склеиваешь команду, и его же и передавай. В переводе ответа в юникод я тоже смысла не вижу. 2. ReadFile/WriteFile в синхронном режиме (как у тебя) будут зависать навечно, ожидая выполнения. Необходимо использовать Overlapped структуру. И WaitCommEvent. Иначе корректно работать будет только иногда и случайно. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 10:47 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
скелА Код: sql 1.
... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 10:50 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
YuRock скелА, 2. ReadFile/WriteFile в синхронном режиме (как у тебя) будут зависать навечно, ожидая выполнения. Необходимо использовать Overlapped структуру. И WaitCommEvent. Иначе корректно работать будет только иногда и случайно. Я кстати так же думал, однако функция SetCommTimeouts должна решать эту проблему. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 13:44 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
DmSer YuRock скелА, 2. ReadFile/WriteFile в синхронном режиме (как у тебя) будут зависать навечно, ожидая выполнения. Необходимо использовать Overlapped структуру. И WaitCommEvent. Иначе корректно работать будет только иногда и случайно. Я кстати так же думал, однако функция SetCommTimeouts должна решать эту проблему. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 15:39 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
YuRock, Попробую, вдруг прокатит.. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 16:17 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
Забыл прикрепить исходник ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 16:18 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
Соколинский Борис, Понял, спасибо! p.s Стал искать откуда ноги ростут у "absolute", думаю простые любители в целом редко им пользуются и нарыл в далеком 2005 такую ветку на форуме, там ответчики интеллигентно стебутся над автором, но общий дух разглагольствований со всеми "заморозками" и "кристаллической структурой" наталкивает на некий DANGER в ее использовании. Так-ли это, или лучше все-же найти некий аналог.. Вообщем хотелось-бы чтобы все работало) http://delphimaster.net/view/14-1125268629/all ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 16:19 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
Большое спасибо за ценные замечания, сейчас сяду купировать все это хозяйство.. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 16:21 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
Запамятовал уточнить.. InQueue, OutQueue в 2048 не аукнится ? Код: pascal 1. 2. 3. 4. 5. 6.
... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 16:44 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
авторTransmission Rate - 9600 bps Character Length - 8 bits Parity bits - Even Stop bits - 1 stop bit Flow Control - None И вот это "Flow Control = None" - т.е видимо, тоже должен быть отд.флаг для DCB (в функции SetCommStatus), если не ошибаюсь ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 16:58 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
YuRock DmSer пропущено... Я кстати так же думал, однако функция SetCommTimeouts должна решать эту проблему. У ТС ожидание ответа может быть до 90 сек. авторDelay to send Response after Command: 0 - 90 sec Видимо, когда устройство выдаст купюры, тогда отчитывается. Тут на мой взгляд стоит использовать конечно асинхронное чтение. Или же делать тупой поллинг с разумным таймаутом. скелА, вот вам еще пара советов про работу с портом. Запись/структуру DCB можно не заполнять самому всю, а сначала получить её текущее состояние, потом изменить нужные поля и потом задать их. Т.е. Сначала вызываете GetCommState (он выдаст DCB с текущими параметрами), потом меняете нужные параметры, а потом вызываете SetCommState. Протокол обмена, как вы описали, бинарный, причем структура запроса и ответа для команды "DISPENSE", которую вы посылаете, известна. На мой взгляд тут нет никакой необходимости преобразовывать это все в Char и строки. Байты задаёте, байты посылаете, байты получаете и байты интерпретируете. Можно объявить Packed record со структурой данных как в запросе и как в ответе и передавать в функции WriteFile и ReadFile их, мне кажется, так проще и нагляднее. Но можно этого и не делать, просто использовать массивы байтов. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 17:10 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
s62 wroteТут на мой взгляд стоит использовать конечно асинхронное чтение. Или же делать тупой поллинг с разумным таймаутом. Или выделить отдельный поток, который только и делает, что читает. Как раз на случай неожиданных посылок по инициативе самого устройства (например, нажатия кнопки на нём). Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 17:56 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
Понял, благодарю за подробный ответ, действительно так проще и вероятности на ошибку будет наверно меньше, с GetCommState имею ввиду, вместе (с нормальным бинарным представлением в коде), но тут больше вопрос удобства внешнего восприятия кода, как я понимаю, т.е. работать оно должно и так. Да, там именно так все и устроено, диспенсер перестраховывается, удастся ему выдать эти "клочки" или нет (понял что не самое лучшее состояние бумаги) Тут насколько я понимаю "узкое" место с кучей итераций для ReadFile будет именно до получения того единственного байта успеха ACK (0x06) от диспенсера. По идее, когда он его вернул, сообщив что все в порядке и команда принята к рассм.(readACK = ReadFile(F, Temp, 1, 1, nil) в таймере) - остается еще максимум 90 сек. на ответ. Отсюда вопрос, безопасней ли будет, с точки зрения всех этих подводных течений с синхронизацией, выставить таймер на эти 90 сек. и просто проверить по истечении этого максимума, пришел-ли основной пакет в буфер. Ну т.е имею ввиду, - он ведь там останется, никуда не перезапишется за это время, с учетом, что устройство по протоколу не должно более ничего посылать, пока я не отправлю ему новую порцию данный (пакет). Вообщем поправте, если ошибаюсь, давненько не работал с API .. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 18:16 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
Dimitry Sibiryakov, Ага, все-таки может значит, что-то отправить без запросов.. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 18:17 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
Dimitry Sibiryakov, я не писал, но да, что синхронное чтение, что асинхронное с WaitCommEvent, как YuRock написал, стоит делать в отдельном потоке. Я правда писал синхронный обмен и в основном потоке, но по неопытности, плюс быстрый ответ устройства не создавал проблем. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 18:24 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
скелААга, все-таки может значит, что-то отправить без запросов.. Может и не может, в стартовом посте об этом не упомянуто. Но странно было бы видеть банкомат без кнопок выдающий купюры исключительно по пинку "изнутри". Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 18:35 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
а почему бы ТС не взять какую-то готовую реализацию библиотеки для работы с ком-портом ? разве что ему не задачу надо решить, а поизучать возможности апи с созданием своего велосипеда ... |
|||
:
Нравится:
Не нравится:
|
|||
17.09.2021, 20:33 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
defecator, в приоритете конечно стабильность, пусть даже придется сделать вполне приличный скутер из этого самоката, - тобишь даже если кода увеличится в-разы.. Буду безмерно признателен за такую специфичную библиотеку ... |
|||
:
Нравится:
Не нравится:
|
|||
18.09.2021, 00:17 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
скелА defecator, в приоритете конечно стабильность, пусть даже придется сделать вполне приличный скутер из этого самоката, - тобишь даже если кода увеличится в-разы.. Буду безмерно признателен за такую специфичную библиотеку Из классики TPApro . ... |
|||
:
Нравится:
Не нравится:
|
|||
18.09.2021, 01:34 |
|
Работа с COM. Отправка одной команды (пакета) и получение ответа
|
|||
---|---|---|---|
#18+
northener, Спасибо, кажется идеально.. Ставлю. Выдержка: Особенно порадовало - авторКомпонент TApdDataPacket обеспечивает автоматическую доставку пакетов данных из входящего потока данных на основе простых свойств, установленных в компоненте. Пакет данных можно рассматривать как расширенный триггер данных. Пакеты автоматически собирают данные из входящего потока данных на основе критериев, указанных в свойствах компонента пакета данных, и доставляют данные, когда критерии соблюдены. В отличие от традиционных триггеров данных, пакеты данных выполняют собственную буферизацию. Это означает, что пакеты данных не имеют тех же ограничений, что и триггеры данных (эти данные могут больше не быть доступны во входном буфере для обработки при срабатывании триггера данных). Обычно вы используете пакеты данных вместо триггеров данных, когда данные, которые вы ищете, имеют фиксированную длину или начинаются или заканчиваются известной строкой данных. Эти условия могут быть установлены в компоненте пакета данных во время разработки или выполнения. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.09.2021, 12:51 |
|
|
start [/forum/topic.php?fid=58&msg=40098369&tid=2037020]: |
0ms |
get settings: |
9ms |
get forum list: |
14ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
38ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
52ms |
get tp. blocked users: |
2ms |
others: | 13ms |
total: | 145ms |
0 / 0 |