У меня странная проблема. Некоторое время я пытался заменить небольшой конвертер протоколов (в основном двухсторонний последовательный порт на Ethernet ... главный и подчиненный), который у меня есть, на что-то, что имеет больше возможностей.
Предыстория
После большого количества реверс-инжиниринга я узнал, как работает устройство, и я пытался воспроизвести его, и я успешно подключил свою плату к устройству ... Я попытался подключить оригинал как master и моя плата как slave и наоборот, и все работает отлично, на самом деле это лучше, так как на более высоких скоростях больше нет потерь пакетов (подключение двух оригинальных устройств приведет к потерям пакетов).
Однако, когда я попытался подключить свое устройство как ведущее, а другое - как подчиненное ..., запустив точно такой же фрагмент кода, он работает для 2 или 3 обменов, а затем останавливается ... в конечном итоге ИНОГДА через несколько минут он попытается еще 2 или 3 раза.
Как были проведены испытания
- Я подключил Modbus Master и Slave (modbustools, два разных экземпляра). Ведущий - это Modbus с последовательным RTU, а ведомый - это Modbus с последовательным RTU;
- Я настраиваю одно из моих устройств в качестве главного и подключаю его к последовательному порту, чтобы он получал последовательный протокол Modbus и отправлял протокол на подключенное к нему устройство;
- Я настраиваю свое ведомое устройство так, чтобы оно подключалось через последовательный порт к ведомому Modbus. По сути, он работает, создавая сокет и подключаясь к IP-адресу мастера, затем ожидает передачи мастера через Ethernet, отправляет его через последовательный порт на подчиненный модуль Modbus (modbustools), получает ответ, отправляет его своему мастеру, а затем отправляет его на мастер Modbus (modbustools);
Я немного сбиваю с толку, но вот как это работает ... мой мастер ждет соединения с сокетом, а затем начинается связь между ними, потому что так работают старые.
Я написал эхо-клиент для проверки соединения. Теперь мой код подключается к серверу (моему мастеру), он получает пакет, а затем отвечает тем же пакетом, который получил. Когда я пытаюсь подключить это к моим 2 платам, они не работают. Это больше того же, 2 или 3 обмена, а затем он останавливается, но когда я подключаю его к исходному устройству, он продолжает работать без помех.
Источники
Вот моя инициализация мастера TCP (фактически сервера):
void initClient() {
if(tcp_modbus == NULL) {
tcp_modbus = tcp_new();
previousPort = port;
tcp_bind(tcp_modbus, IP_ADDR_ANY, port);
tcp_sent(tcp_modbus, sent);
tcp_poll(tcp_modbus, poll, 2);
tcp_setprio(tcp_modbus, 128);
tcp_err(tcp_modbus, error);
tcp_modbus = tcp_listen(tcp_modbus);
tcp_modbus->so_options |= SOF_KEEPALIVE; // enable keep-alive
tcp_modbus->keep_intvl = 1000; // sends keep-alive every second
tcp_accept(tcp_modbus, acceptmodbus);
isListening = true;
}
}
static err_t acceptmodbus(void *arg, struct tcp_pcb *pcb, err_t err) {
tcp_arg(pcb, pcb);
/* Set up the various callback functions */
tcp_recv(pcb, modbusrcv);
tcp_err(pcb, error);
tcp_accepted(pcb);
gb_ClientHasConnected = true;
}
//receives the packet, puts it in an array "ptransparentmessage->data"
//states which PCB to use in order to reply and the length that was received
static err_t modbusrcv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) {
if(p == NULL) {
return ERR_OK;
} else if(err != ERR_OK) {
return err;
}
tcp_recved(pcb, p->len);
memcpy(ptransparent.data, p->payload,p->len);
ptransparent->pcb = pcb;
ptransparent->len = p->len;
}
Серийный прием в основном такой:
обнаружение одного полученного байта, начало тайм-аута, когда тайм-аут заканчивается, отправьте все, что было получено через сокет TCP, который уже был подключен к серверу. Затем он получает пакет через функцию acceptmodbus и отправляет его через последовательный порт.
Это код моего клиента (ведомого):
void init_slave() {
if(tcp_client == NULL) {
tcp_client = tcp_new();
tcp_bind(tcp_client, IP_ADDR_ANY, 0);
tcp_arg(tcp_client, NULL);
tcp_recv(tcp_client, modbusrcv);
tcp_sent(tcp_client, sent);
tcp_client->so_options |= SOF_KEEPALIVE; // enable keep-alive
tcp_client->keep_intvl = 100; // sends keep-alive every 100 mili seconds
tcp_err(tcp_client, error);
err_t ret = tcp_connect(tcp_client, &addr, portCnt, connected);
}
}
Остальная часть кода идентична. Единственное, что меняется, это поток операций.
- Подключение к серверу
- Ждите пакета
- отправить через серийный номер
- ожидание тайм-аута ответа (тот же тайм-аут, что и у сервера, он рассчитывает, что подсчет начинается по-другому ... сервер запускается после получения одного байта, а клиент - после отправки чего-либо через последовательный порт)
- получить ответ и отправить его на сервер
Наблюдение
Ошибка связи не обнаружена. После некоторого тестирования кажется, что количество обменов не приводит к зависанию. Это происходит через некоторое время. На мой взгляд, это звучит как проблема разъединения или ошибка тайм-аута, но разъединение не происходит и пакеты не принимаются. Когда я прекращаю отладку и проверяю сокеты, ничего необычного не обнаруживается.