Перенос последовательного порта Win32 (RS232) на POSIX

В настоящее время я портирую приложение Win32 на POSIX. Само программное обеспечение было выпущено пару десятилетий назад и использовалось для обновления проприетарных машин.

Хотя большинство функций было относительно легко заменить простыми макросами и некоторыми более мелкими функциями, вызывающими функции POSIX, функции, связанные с коммуникацией RS232, оказались трудными.

Приложение использует эти функции для связи через RS232:

BOOL GetCommState(HANDLE comPort, DCB* dataControlBlock);

BOOL SetCommState(HANDLE comPort, DCB* dataControlBlock);

BOOL GetCommTimeouts(HANDLE comPort, LPCOMMTIMEOUTS comTimeouts);

BOOL SetCommTimeouts(HANDLE comPort, LPCOMMTIMEOUTS comTimeouts);

BOOL SetCommMask(HANDLE comPort, DWORD eventMask);

BOOL GetCommMask(HANDLE comPort, LPDWORD eventMask);

BOOL WaitCommEvent(HANDLE comPort, LPDWORD eventMask, LPOVERLAPPED overlapped);

Наряду со следующими структурами:

typedef struct _DCB { /*...*/ } DCB, *LPDCB;

typedef struct _COMMTIMEOUTS { /*...*/ } COMMTIMEOUTS, *LPCOMMTIMEOUTS;

Во время поиска я наткнулся на эту ссылку, в которой упоминаются termios.h и sys / select .h, но структура этих заголовков, на мой взгляд, слишком отличается. В других ответах упоминалось использование Wine, что просто не вариант из-за оборудования, на которое переносится приложение.

Если возможно, я хотел бы реализовать более простое решение и сохранить структуры, которые в настоящее время используются приложением - в попытке сохранить все перекрестную совместимость.

Есть ли способ добиться этого?
Или я застрял с переписыванием брутто-частей приложения?


person SimonC    schedule 20.12.2018    source источник
comment
RS232 в Linux уже реализован в файловой системе. Что собираетесь архивировать?   -  person 0___________    schedule 20.12.2018
comment
Я надеюсь использовать структуру, уже предоставленную в приложении, поэтому мне не придется переписывать слишком много приложения. По сути, мне нужно использовать RS232 для отправки (сырых) данных в соответствующий ECU для обновления его прошивки. Аппаратное обеспечение, которое изначально использовалось для запуска программного обеспечения, больше не производится, поэтому нам / мне нужно перенести его на другое оборудование.   -  person SimonC    schedule 20.12.2018
comment
Рассмотрите возможность использования boost::asio. Работает как для Windows, так и для Linux. Но перед тем как начать, проверьте, можете ли вы собрать boost для своей целевой машины. В общем, возможно - мы запускаем boost даже на ARMv5 процессорах.   -  person grapes    schedule 20.12.2018
comment
RS232 to send (raw) data to a proprierary ECU и в чем проблема?   -  person 0___________    schedule 20.12.2018
comment
@P__J__ Проблема в том, что приложение написано для Win32. Возникает вопрос, есть ли способ сохранить структуру Win32 на машинах POSIX, чтобы приложение могло оставаться почти нетронутым. По сути, если есть простой способ создать интерфейс между системными вызовами Win32 и POSIX. Я проверил GtkTerm, но это тоже не сильно помогает.   -  person SimonC    schedule 20.12.2018
comment
@grapes К сожалению, я ограничен C для этого порта, поэтому Boost не вариант. Если нет другого выхода, я подумаю о внесении изменений. Я использовал только Boost, не компилируя его для текущего оборудования, но это не должно быть проблемой для его компиляции.   -  person SimonC    schedule 20.12.2018
comment
Это так просто. Судя по названиям функций (Подождите ....) все в синхронном режиме. termio (для тайм-аутов) - хорошее направление. вероятно, всего будет меньше 100 строк.   -  person 0___________    schedule 20.12.2018
comment
@P__J__ Не могли бы вы добавить это в качестве ответа, возможно, с несколькими строками примерного кода?   -  person SimonC    schedule 20.12.2018


Ответы (1)


В зависимости от сложности вашего приложения я вижу два возможных решения:

  1. Замените вызовы Win32 эквивалентным вызовом POSIX, как упоминалось в комментариях P__J__. Если вы это сделаете, эквивалентные вызовы, вероятно, будут примерно такими:

GetCommState : tcgetattr

SetCommState : tcsetattr

Get/SetCommTimeouts: Вы все равно бы установили это с помощью tcsetattr, измените запись c_cc[VTIME] в struct termios

Set/GetCommMask: К сожалению, в POSIX API нет эквивалента этой функции. Если вам нужно позаботиться об управляющих сигналах (CTS, DSR, RING), вам необходимо считывать статус линии в цикле. Если вас интересует только чтение возвращающихся байтов, вам не нужно об этом беспокоиться.

WaitCommEvent: эквивалент в POSIX будет либо select (старый стиль), либо poll (более современный). Однако, аналогично CommMask, описанному выше, select/poll будет возвращаться, когда есть данные для чтения, а не при изменении контрольных строк.

  1. Если вы не хотите пытаться самостоятельно решать кроссплатформенные проблемы, есть несколько библиотек (на языке C), которые поддерживают кроссплатформенность. Вот краткий список:

..и это все, что я знаю. Все остальные библиотеки, о которых я знаю, предназначены для C ++.

person rm5248    schedule 20.12.2018
comment
Спасибо, я сначала проверю эти библиотеки и посмотрю, смогу ли я соответствующим образом переписать приложение. К сожалению, это довольно сложное приложение. - person SimonC; 21.12.2018