Плата LWIP не может поддерживать соединение с другой платой - PullRequest
0 голосов
/ 26 июня 2019

У меня странная проблема. Некоторое время я пытался заменить небольшой конвертер протоколов (в основном двухсторонний последовательный порт на 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);
    }
}

Остальная часть кода идентична. Единственное, что меняется, это поток операций.

  1. Подключение к серверу
  2. Ждите пакета
  3. отправить через серийный номер
  4. ожидание тайм-аута ответа (тот же тайм-аут, что и у сервера, он рассчитывает, что подсчет начинается по-другому ... сервер запускается после получения одного байта, а клиент - после отправки чего-либо через последовательный порт)
  5. получить ответ и отправить его на сервер

Наблюдение

Ошибка связи не обнаружена. После некоторого тестирования кажется, что количество обменов не приводит к зависанию. Это происходит через некоторое время. На мой взгляд, это звучит как проблема разъединения или ошибка тайм-аута, но разъединение не происходит и пакеты не принимаются. Когда я прекращаю отладку и проверяю сокеты, ничего необычного не обнаруживается.

1 Ответ

1 голос
/ 26 июня 2019

Если я правильно понял ваш вопрос, у вас есть компьютер с двумя последовательными портами, на каждом из которых работает клиент и сервер Modbus. С каждого из этих концов вы затем переходите к платам STM32, которые получают данные через свои последовательные порты, и пересылаете их в TCP по сети Ethernet, соединяя их друг с другом.

Трудно сказать, но, исходя из описанных вами симптомов, определенно похоже, что у вас есть одна или несколько проблем timeout , вероятно, на последовательной стороне. Я думаю, вам будет нелегко помочь вам точно определить, что именно не так с вашим кодом, без его тестирования, и уж точно, если вы не сможете показать полный функциональный фрагмент.

Но что вы можете улучшить, так это способ отладки на конечных сторонах. Вы можете попробовать заменить modbustools на что-то более подробное.

Самое простое решение для получения дополнительной информации об отладке - использовать pymodbus , вам просто нужно установить библиотеку с pip и использовать клиент и сервер, поставляемые с примеры . Единственное, что вам нужно, это заменить их на последовательный интерфейс, комментируя и раскомментируя пару строк. Это даст вам очень полезную информацию для отладки.

Если на вашем компьютере есть среда разработки C, лучше перейдите на libmodbus . Эта библиотека имеет фантастический набор модульных тестов . Опять же, вам просто нужно отредактировать код, чтобы задать имя вашего последовательного порта и запустить сервер и клиент.

Наконец, я не знаю, насколько это может быть полезно для вас, но вы можете взглянуть на SerialPCAP . С помощью этого инструмента вы можете нажать на шину RS-485 и увидеть все запросы и ответы, выполняемые на ней. Я предполагаю, что у вас есть RS-232, который является двухточечным и не будет работать с тремя устройствами в шине. Если это так, вы можете попробовать перенаправление портов .

РЕДАКТИРОВАТЬ: Читая ваш вопрос более внимательно, я нахожу это предложение особенно неприятным:

... обнаружение одного полученного байта, начало тайм-аута, когда тайм-аут заканчивается, отправьте все, что было получено через сокет TCP, уже подключенный к серверу ...

Зачем вам нужно вводить эту искусственную задержку? В Modbus у вас есть очень хорошо определенные пакеты, которые вы можете идентифицировать по минимальному интервалу в 3,5 кадра, это то, что вы подразумеваете под timeout ?

Не имеет отношения, но я также вспомнил, что есть пример серийного перенаправителя с pymodbus , который может как-то помочь вам (может быть, вы можете использовать его для эмуляции одной из ваших плат? ).

...