Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.93/40: Рейтинг темы: голосов - 40, средняя оценка - 4.93
4 / 4 / 0
Регистрация: 12.11.2018
Сообщений: 511

Организация работы FREERTOS и LWIP

12.08.2020, 10:47. Показов 9478. Ответов 17

Студворк — интернет-сервис помощи студентам
Имеется проект на stm32f746 в котором настроена FREERTOS и LWIP (TCP эхо сервер). LWIP и задачи FREERTOS (опрос АЦП, мигание светодиодами и тд) независимо друг от друга работают хорошо. Теперь возникла проблема в том, как организовать их совместную работу, например: принять по TCP пакет данных, обработать его, в зависимости от содержимого пакета забрать данные АЦП и отправить по TCP, помигать светодиодом, отправить данные по USART и тд, т.е. выполнить какое либо действие. Сейчас реализован эхо сервер, данные пришли, вывелись на дисплей и отправились обратно. Но я не знаю как сделать так, чтобы данные можно было вынести из функции соединения TCP обработать и, как уже писал выше, например передать по TCP данные АЦП.
Код реализации соединения TCP:
Кликните здесь для просмотра всего текста
C
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
63
static void tcp_thread(void *arg)
{
    struct_out *qstruct;                 // Structure for output the string into LCD with help of queue
    err_t err, recv_err;                 // Variables for arguments (errors)
    struct netconn *conn;                // Structure for connection
    struct netbuf *inbuf;                // Pointer to connection buffer
    struct netconn *newconn;             // Pointer to new connection
    struct_sock *arg_sock;               // Pointer to arguments of task
    arg_sock = (struct_sock*) arg;
    conn = arg_sock->conn;
    u16_t buflen;
    char* buf;
    TFT_SetTextColor(LCD_COLOR_BLUE);
    for(;;)
    {
      err = netconn_accept(conn, &newconn); // Binding the socket struck for sending data and TCP struck
      if (err == ERR_OK)
      {
        netconn_write(newconn, "READY", 5, NETCONN_COPY);            // Sending "READY"
        for(;;)
        {
          recv_err = netconn_recv(newconn, &inbuf);                  // Receiving the socket data in inbuf
          if (recv_err == ERR_OK)
          {
            netbuf_data(inbuf, (void**)&buf, &buflen);               // Data transfer of the inbuf data to buf
            if((buf[0]==0x0D)||(buf[0]==0x0A))                       // Checking of the data ending
            {
              netbuf_delete(inbuf);
              continue;
            }
            qstruct = osMailAlloc(strout_Queue, osWaitForever);
            qstruct->y_pos = arg_sock->y_pos;
            strncpy(str_buf,buf,buflen);
            str_buf[buflen]=0;
            sprintf(qstruct->str,"%-20s", str_buf);
            osMailPut(strout_Queue, qstruct);
            osMailFree(strout_Queue, qstruct);
            str_buf[buflen] = '\r';
            str_buf[buflen+1] = '\n';
            netconn_write(newconn, str_buf, buflen+2, NETCONN_COPY);
            uint8_t DataSignal = 0;
            DataSignal = str_buf[0] - '0';
            if (DataSignal == 5)
            {
                HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
            }
            netbuf_delete(inbuf);
          }
          else
          {
            netbuf_delete(inbuf);
            netconn_close(newconn);
            netconn_delete(newconn);
            break;
          }
        }
      }
      else
      {
        osDelay(1);
      }
    }
}


Кликните здесь для просмотра всего текста
C
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
void StartDefaultTask(void const * argument)
{
  /* init code for LWIP */
  MX_LWIP_Init();
  /* USER CODE BEGIN 5 */
  //-----------------------------------------------------------
  struct netconn *conn;
  err_t err;
  sock01.y_pos = 60;
  sock02.y_pos = 180;
  conn = netconn_new(NETCONN_TCP);
  if(conn!=NULL)
  {
    sock01.conn = conn;
    sock02.conn = conn;
    err = netconn_bind(conn, NULL, 80);
    if (err == ERR_OK)
    {
      netconn_listen(conn);
      sys_thread_new("tcp_thread1", tcp_thread, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
      sys_thread_new("tcp_thread2", tcp_thread, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
    }
    else
    {
      netconn_delete(conn);
    }
  }
  //-----------------------------------------------------------
  /* Infinite loop */
  for(;;)
  {
      osDelay(1);
  }
  /* USER CODE END 5 */ 
}
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
12.08.2020, 10:47
Ответы с готовыми решениями:

FreeRTOS+LwIP на TE-STM32F207
Доброго времени суток, такая ситуация: необходимо плату использовать как определенный сетевой узел который будет одновременно общяться с...

LPC2368 + FreeRTOS + LwIP
Реально ли запустить на стек lwip на камне LPC2368 с ROM на борту 32 кБ? При этом нужна поддержка протоколов PPP, IP, TCP. Я собрал...

STM32 + ENC28J60 + LwIP + FreeRTOS
Всем привет! Собственно, есть необходимость запустить сабж. Знаю, что глупо, но STM32F107 и физика где-то далеко, а дискавери и ENC лежат...

17
76 / 52 / 26
Регистрация: 23.01.2019
Сообщений: 134
13.08.2020, 15:16
Привет.
Используй очереди сообщений.
Когда через tcp приходит очередная команда, то tcp_thread должен ее расшифровать, сформировать соответствующее сообщение и запихнуть его в очередь сообщений.
Другой же поток должен постоянно мониторить очередь сообщений и, при появлений оных, выбирать их и выполнять команды.
У вас в коде потока tcp_thread уже даже есть зачатки этого процесса
C
1
2
3
4
5
6
7
            qstruct = osMailAlloc(strout_Queue, osWaitForever);
            qstruct->y_pos = arg_sock->y_pos;
            strncpy(str_buf,buf,buflen);
            str_buf[buflen]=0;
            sprintf(qstruct->str,"%-20s", str_buf);
            osMailPut(strout_Queue, qstruct);
            osMailFree(strout_Queue, qstruct);
Только функцию osMailFree должен вызывать поток который принимает сообщения, после того, как он его обработает.
C
1
2
3
4
5
6
7
8
9
10
11
12
void dispatcher_thread (void const *argument) {
  osEvent  evt;
  for (;;) {
    evt = osMailGet(strout_Queue, osWaitForever);   // Ожидание сообщения
    if (evt.status == osEventMail) {
      
      //Обработка сообщения
 
      osMailFree(strout_Queue, evt.value.p);  // Освобождение памяти 
    }
  }
}
1
4 / 4 / 0
Регистрация: 12.11.2018
Сообщений: 511
14.08.2020, 06:57  [ТС]
yatrim, спасибо за ответ, тоже пытаюсь что-то с очередями сделать, но у меня пока возникают вопросы:
1) В чем различия создания очереди таким образом
C
1
send_data = xQueueCreate(1, sizeof(uint16_t));
и таким
C
1
2
  osMailQDef(strhandlerqueue, MAIL_SIZE, struct_handler);
  handler_Queue = osMailCreate(osMailQ(strhandlerqueue), NULL);
2) Правильно ли я понимаю, что при приеме данных из очереди
C
1
xQueueReceive(send_data, &adcSendData, portMAX_DELAY);
код, расположенный под данной сточкой, будет выполняться только в случае появления данных в очереди? Если да, то как тогда реализовать прием данных из очереди где-нибудь посередине функции, т.е. чтобы xQueueReceive можно было расположить не в конце функции, а где-нибудь посередине:
C
1
2
3
4
5
6
7
8
9
10
void Task(void const * argument)
{
  for(;;)
  {
     // Программный код
     xQueueReceive(send_data, &adcSendData, portMAX_DELAY);
     //Код выполняемый при извлечении данных из очереди
     // Программный код
  }
}
3) Функция tcp_thread создается кода появляется новое соединение, и в цикле for(; ожидает приема данных recv_err = netconn_recv(newconn, &inbuf);
Т.е. я принимаю данные, передаю их с помощью очереди в другой поток и вроде все нормально, но возникает вопрос как передать данные из потока в tcp_thread. Например работает АЦП по таймеру, и каждую секунду хочет отправлять по TCP измеренное значение, тут надо организовать какую-то проверку наличия соединения TCP? И в какую часть кода tcp_thread потом передать данные из очереди? Сейчас у меня получилось сделать только так, что данные с АЦП берутся и отправляются только если есть входящее сообщение TCP

Добавлено через 11 минут
4) Еще такой вопрос, если я создаю очередь на один элемент: send_data = xQueueCreate(1, sizeof(uint16_t));
дальше отправляю данные из потока xQueueSend(send_data, &adcData, portMAX_DELAY);,
а считываю эти данные xQueueReceive(send_data, &adcSendData, portMAX_DELAY); и xQueueReceive(send_data, &adcSendDataTCP, portMAX_DELAY); т.е. из двух разных потоков, так можно делать или при первом xQueueReceive помещенные в очередь данные удалятся?
0
76 / 52 / 26
Регистрация: 23.01.2019
Сообщений: 134
14.08.2020, 14:14
1. Разница в том, что Mail Queue - это надстройка над Message Queue, в которой элементами очереди являются указатели на блоки памяти.

2. Да, если в функции xQueueReceive параметр таймаута установлен portMAX_DELAY, то функция вернет результат, только когда в очереди появиться очередной элемент.
Насчет расположения в теле функции я не понял, что вы имели ввиду. Ничто не мешает вам расположить ее в любом месте.

3. Для отправки данных через TCP соединение лучше создать отдельный поток, который при появлении данных которые следует передать, проверял бы наличие соединения и передавал данные.

4. Функция xQueueReceive удаляет элемент из очереди, чтоб выбрать элемент и оставить его в очереди нужно вызывать функцию xQueuePeek
1
4 / 4 / 0
Регистрация: 12.11.2018
Сообщений: 511
14.08.2020, 14:30  [ТС]
yatrim,
1) Я правильно понимаю, что передавая массивы данных через очереди, лучше будет использовать Mail Queue?
2) Тут я имел ввиду следующую ситуацию: есть какая-либо функция мигания светодиодами
C
1
2
3
4
5
6
7
8
9
10
void Task(void const * argument)
{
  for(;;)
  {
     Мигаем сетодиодом 1
     xQueueReceive(send_data, &adcSendData, portMAX_DELAY);
     Мигаем сетодиодом 2
     Мигаем сетодиодом 3
  }
}
При таком написании кода мы попадем в цикл, помигаем светодиодом 1 и будем ждать попадания данных в очередь xQueueReceive(send_data, &adcSendData, portMAX_DELAY);
Кода это произойдет выполнится оставшийся код: мигание 2 и 3 светодиодами.
Однако как сохранив такую же конструкцию кода сделать так, чтобы в цикле for мы мигали 1 светодиодом, потом 3м, а когда получим данные в очередь xQueueReceive, то вторым?
Ну либо похожая ситуация, но в цикле будут находится две очереди:
C
1
2
3
4
5
6
7
8
9
10
11
void Task(void const * argument)
{
  for(;;)
  {
     Мигаем сетодиодом 1
     xQueueReceive(send_data, &adcSendData, portMAX_DELAY);
     Код 1
     xQueueReceive(send_data2, &adcSendData2, portMAX_DELAY);
     Код 2
  }
}
Если поступят данные во вторую очередь send_data2, то выполнится ли код 2?
3) С TCP пока только разбираюсь, может у Вас есть похожий код для реализации?
Цитата Сообщение от yatrim Посмотреть сообщение
создать отдельный поток, который при появлении данных которые следует передать, проверял бы наличие соединения и передавал данные
Поток еще создать может получиться, попробую по аналогии с тем кодом, который уже есть
4) А используя xQueuePeek при поступлении новых данных они перезапишут те, что уже есть в очереди?
0
76 / 52 / 26
Регистрация: 23.01.2019
Сообщений: 134
14.08.2020, 15:50
1. Да, именно для таких случаев Mail Queue и предназначена

2. В таком случае нужно использовать в функции xQueueReceive таймауты
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void Task(void const * argument)
{
  uint32_t timeout = 10; //Таймаут в миллисекундах
  for(;;)
  {
     Мигаем светодиодом 1
     if(xQueueReceive(send_data, &adcSendData, pdMS_TO_TICKS(timeout)) == pdPASS){
       // Получено сообщение 
       // Код 1
     }
     if(xQueueReceive(send_data2, &adcSendData2, pdMS_TO_TICKS(timeout)) == pdPASS){
       // Получено сообщение 
       // Код 2
     }
     
     // Еще код
  }
}
4. Смотря как будешь посылать сообщения в очередь. Если при помощи функции xQueueSend, то перезаписи не будет и если очередь будет заполнена полностью, то функция завершиться с ошибкой errQUEUE_FULL. А если использовать функцию xQueueOverwrite, то при заполненной очереди будет вытираться самое старое сообщение.
1
4 / 4 / 0
Регистрация: 12.11.2018
Сообщений: 511
15.08.2020, 10:31  [ТС]
yatrim, С очередями вроде разобрался, спасибо за помощь. Можете подсказать по потокам?
Цитата Сообщение от yatrim Посмотреть сообщение
Для отправки данных через TCP соединение лучше создать отдельный поток, который при появлении данных которые следует передать, проверял бы наличие соединения и передавал данные.
Поток на прослушивание TCP соединения создается в задаче StartDefaultTask
Кликните здесь для просмотра всего текста
C
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
void StartDefaultTask(void const * argument)
{
  /* init code for LWIP */
  MX_LWIP_Init();
  /* USER CODE BEGIN 5 */
  //-----------------------------------------------------------
  struct netconn *conn;
  err_t err;
  sock01.y_pos = 60;
  sock02.y_pos = 180;
  conn = netconn_new(NETCONN_TCP);
  if(conn!=NULL)
  {
    sock01.conn = conn;
    sock02.conn = conn;
    err = netconn_bind(conn, NULL, 80);
    if (err == ERR_OK)
    {
      netconn_listen(conn);
      sys_thread_new("tcp_thread1", tcp_thread, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
      sys_thread_new("tcp_thread2", tcp_thread, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
 
      // Send thread
      sys_thread_new("tcp_thread_send1", tcp_thread_send, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
      sys_thread_new("tcp_thread_send2", tcp_thread_send, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
    }
    else
    {
      netconn_delete(conn);
    }
  }
  //-----------------------------------------------------------
  /* Infinite loop */
  for(;;)
  {
      osDelay(1);
  }
  /* USER CODE END 5 */ 
}


Потоки для приема данных по двум TCP соединениям
C
1
2
      sys_thread_new("tcp_thread1", tcp_thread, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
      sys_thread_new("tcp_thread2", tcp_thread, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
До установки TCP соединения все равно данные передавать клиенту не получится, поэтому я полагаю, что тут же можно создать так же два потока с теми же агрументами как и для tcp_thread, но уже для отправки данных:
C
1
2
      sys_thread_new("tcp_thread_send1", tcp_thread_send, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
      sys_thread_new("tcp_thread_send2", tcp_thread_send, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
По идее при первом подключении клиента (ПК) к серверу (МК), должен создаться поток на прослушивание TCP (tcp_thread1) и поток на передачу (tcp_thread_send1).
Дальше просто пытаюсь передать пробный массив в созданном потоке но ничего не выходит
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static void tcp_thread_send(void *arg)
{
    struct netconn *conn;                // Structure for connection
    struct netbuf *inbuf;                // Pointer to connection buffer
    struct netconn *newconn;             // Pointer to new connection
    struct_sock *arg_sock;               // Pointer to arguments of task
    arg_sock = (struct_sock*) arg;
    conn = arg_sock->conn;
 
    if (netconn_accept(conn, &newconn) == ERR_OK)
    {
    for(;;)
    {
        char send_TCP_buf[10] = {0,1,2,3,4,5,6,7,8,9};
        netconn_write(newconn, send_TCP_buf, 10, NETCONN_COPY);
        HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
        osDelay(100);
    }
    }
}
Где я что-то понимаю не так?

Приведу еще используемые структуры:
C
1
2
3
4
5
typedef struct struct_sock_t {
  uint16_t y_pos;
  struct netconn *conn;
} struct_sock;
struct_sock sock01, sock02;
0
76 / 52 / 26
Регистрация: 23.01.2019
Сообщений: 134
15.08.2020, 14:30
Я бы создавал потоки уже после подключения клиента, то есть после netconn_accept
C
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
void StartDefaultTask(void const * argument)
{
  int i = 0;
  /* init code for LWIP */
  MX_LWIP_Init();
  /* USER CODE BEGIN 5 */
  //-----------------------------------------------------------
  struct netconn *conn;
  struct netconn *newConn;
  err_t err;
  sock01.y_pos = 60;
  sock02.y_pos = 180;
  conn = netconn_new(NETCONN_TCP);
  if(conn!=NULL)
  {
    err = netconn_bind(conn, NULL, 80);
    if (err == ERR_OK)
    {
      netconn_listen(conn);
      for(i = 0; i < 2; i ++){
        if (netconn_accept(conn, &newconn) == ERR_OK)
        {
           if(i == 0){
              // Подключился первый клиент
              sock01.conn = newconn;
              sys_thread_new("tcp_thread1", tcp_thread, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
              sys_thread_new("tcp_thread_send1", tcp_thread_send, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
           }
           else{
              // Подключился второй клиент
              sock02.conn = newconn;
              sys_thread_new("tcp_thread2", tcp_thread, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
              sys_thread_new("tcp_thread_send2", tcp_thread_send, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
           }
        } 
      }
    }
    else
    {
      netconn_delete(conn);
    }
  }
  //-----------------------------------------------------------
  /* Infinite loop */
  for(;;)
  {
      osDelay(1);
  }
  /* USER CODE END 5 */ 
}
А в потоке уже использовать соединение, переданное ему через аргумент
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static void tcp_thread_send(void *arg)
{
    struct netconn *conn;                // Structure for connection
    struct netbuf *inbuf;                // Pointer to connection buffer
    struct_sock *arg_sock;               // Pointer to arguments of task
    arg_sock = (struct_sock*) arg;
    conn = arg_sock->conn;
 
    for(;;)
    {
        char send_TCP_buf[10] = {0,1,2,3,4,5,6,7,8,9};
        netconn_write(conn, send_TCP_buf, 10, NETCONN_COPY);
        HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
        osDelay(100);
    }
}
1
4 / 4 / 0
Регистрация: 12.11.2018
Сообщений: 511
16.08.2020, 17:27  [ТС]
yatrim, Спасибо, использовал предложенный Вами код, данные от МК (буфер send_TCP_buf[10] = {0,1,2,3,4,5,6,7,8,9}, правда теперь появилась следующая проблема: соединение между ПК и МК устанавливается, однако МК данные не принимает, если смотреть Wireshark, то некоторые данные от ПК до МК доходят без ошибок, но МК их никак не обрабатывает (раньше выводил на дисплей, мигал светодиодами), некоторые данные идут с ошибками, так же МК не отвечает на сигнал об завершении соединения. Пока не нашел в чем может быть причина, буду благодарен если подбросите какие-либо идеи

Добавлено через 14 минут
Так же второе соединение не подключается, только первое
0
76 / 52 / 26
Регистрация: 23.01.2019
Сообщений: 134
16.08.2020, 18:11
DmitryDDDD,
Покажи как сейчас у тебя выглядит поток приема данных по tcp
0
4 / 4 / 0
Регистрация: 12.11.2018
Сообщений: 511
17.08.2020, 11:57  [ТС]
yatrim,
IP 192.168.1.195 - МК
IP 192.168.1.125 - ПК
1 изображение - установление соединения от клиента (ПК)
2 - сообщение от МК к ПК (массив 0,1,2,3,4,5,6,7,8,9)
3 - сообщение от ПК к МК (Hi!!!)
4 - сообщение с ошибкой и некорректное завершение соединения от клиента
Миниатюры
Организация работы FREERTOS и LWIP   Организация работы FREERTOS и LWIP   Организация работы FREERTOS и LWIP  

Организация работы FREERTOS и LWIP  
0
4 / 4 / 0
Регистрация: 12.11.2018
Сообщений: 511
17.08.2020, 12:09  [ТС]
yatrim, Вот небольшая сессия с кодом до добавления потока передачи данных, т.е. тут идет передача только от ПК к МК
Миниатюры
Организация работы FREERTOS и LWIP  
0
76 / 52 / 26
Регистрация: 23.01.2019
Сообщений: 134
17.08.2020, 18:53
DmitryDDDD,
Извини, я походу неточно выразился.
Я хотел попросить показать, как сейчас у тебя выглядит код программы Stm32, где обрабатывается прием данных по tcp.
0
4 / 4 / 0
Регистрация: 12.11.2018
Сообщений: 511
17.08.2020, 20:06  [ТС]
yatrim,
C
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
63
void StartDefaultTask(void const * argument)
{
  /* init code for LWIP */
  MX_LWIP_Init();
  /* USER CODE BEGIN 5 */
  //-----------------------------------------------------------
  int i = 0;
  struct netconn *conn;
  struct netconn *newconn;
  err_t err;
  sock01.y_pos = 60;
  sock02.y_pos = 180;
  conn = netconn_new(NETCONN_TCP);
  if(conn!=NULL)
  {
      err = netconn_bind(conn, NULL, 80);
      if (err == ERR_OK)
      {
        netconn_listen(conn);
        for(i = 0; i < 2; i ++)
        {
          if (netconn_accept(conn, &newconn) == ERR_OK)
          {
             if(i == 0)
             {
                // 1 client connected
                sock01.conn = newconn;
                sys_thread_new("tcp_thread1", tcp_thread, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
                sys_thread_new("tcp_thread_send1", tcp_thread_send, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
             }
             else
             {
                // 2 client connected
                sock02.conn = newconn;
                sys_thread_new("tcp_thread2", tcp_thread, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
                sys_thread_new("tcp_thread_send2", tcp_thread_send, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
             }
          }
        }
      }
      else
      {
        netconn_delete(conn);
      }
    // Закоментирован код который был до изменений
    //sock01.conn = conn;
    //sock02.conn = conn;
    //err = netconn_bind(conn, NULL, 80);
    //if (err == ERR_OK)
    //{
      //netconn_listen(conn);
      //sys_thread_new("tcp_thread1", tcp_thread, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
      //sys_thread_new("tcp_thread2", tcp_thread, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
 
      // Send thread
      //sys_thread_new("tcp_thread_send1", tcp_thread_send, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
      //sys_thread_new("tcp_thread_send2", tcp_thread_send, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
    //}
    //else
    //{
      //netconn_delete(conn);
    //}
  }
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static void tcp_thread_send(void *arg)
{
    struct netconn *conn;                // Structure for connection
    struct_sock *arg_sock;               // Pointer to arguments of task
    struct netbuf *inbuf;
    arg_sock = (struct_sock*) arg;
    conn = arg_sock->conn;
 
    for(;;)
    {
        char send_TCP_buf[10] = {0,1,2,3,4,5,6,7,8,9};
        netconn_write(conn, send_TCP_buf, 10, NETCONN_COPY);
        HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
        osDelay(5000);
    }
}
C
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
static void tcp_thread(void *arg)
{
    struct_out *qstruct;                 // Structure for output the string into LCD with help of queue
    err_t err, recv_err;                 // Variables for arguments (errors)
    struct netconn *conn;                // Structure for connection
    struct netbuf *inbuf;                // Pointer to connection buffer
    struct netconn *newconn;             // Pointer to new connection
    struct_sock *arg_sock;               // Pointer to arguments of task
    struct_handler *qstructhandler;      // Handler Queue
    arg_sock = (struct_sock*) arg;
    conn = arg_sock->conn;
    u16_t buflen;
    char* buf;
    TFT_SetTextColor(LCD_COLOR_BLUE);
    for(;;)
    {
      err = netconn_accept(conn, &newconn); // Binding the socket struck for sending data and TCP struck
      if (err == ERR_OK)
      {
        netconn_write(newconn, "READY", 5, NETCONN_COPY);            // Sending "READY"
        for(;;)
        {
          recv_err = netconn_recv(newconn, &inbuf);                  // Receiving the socket data in inbuf
          if (recv_err == ERR_OK)
          {
            netbuf_data(inbuf, (void**)&buf, &buflen);               // Data transfer of the inbuf data to buf
            if((buf[0]==0x0D)||(buf[0]==0x0A))                       // Checking of the data ending
            {
              netbuf_delete(inbuf);
              continue;
            }
            qstruct = osMailAlloc(strout_Queue, osWaitForever);
            qstructhandler = osMailAlloc(handler_Queue, osWaitForever);      // Handler Queue
            qstruct->y_pos = arg_sock->y_pos;
            strncpy(str_buf,buf,buflen);
            str_buf[buflen]=0;
            sprintf(qstruct->str,"%-20s", str_buf);
            osMailPut(strout_Queue, qstruct);
            sprintf(qstructhandler->handler_str,"%-20s", str_buf);           // Handler Queue
            osMailPut(handler_Queue, qstructhandler);                        // Handler Queue
            str_buf[buflen] = '\r';
            str_buf[buflen+1] = '\n';
            netconn_write(newconn, str_buf, buflen+2, NETCONN_COPY);
            netbuf_delete(inbuf);
 
          }
          else
          {
            netbuf_delete(inbuf);
            netconn_close(newconn);
            netconn_delete(newconn);
            break;
          }
        }
      }
      else
      {
        osDelay(1);
      }
    }
}
0
76 / 52 / 26
Регистрация: 23.01.2019
Сообщений: 134
17.08.2020, 20:25
Лучший ответ Сообщение было отмечено DmitryDDDD как решение

Решение

Тебе в потоке tcp_thread уже не нужно вызывать netconn_accept ведь подключение уже совершается в StartDefaultTask. Из-за этого получается, что поток зависает на netconn_accept до подключения следующего клиента.

C
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
static void tcp_thread(void *arg)
{
    struct_out *qstruct;                 // Structure for output the string into LCD with help of queue
    err_t err, recv_err;                 // Variables for arguments (errors)
    struct netconn *conn;                // Structure for connection
    struct netbuf *inbuf;                // Pointer to connection buffer
    struct_sock *arg_sock;               // Pointer to arguments of task
    struct_handler *qstructhandler;      // Handler Queue
    arg_sock = (struct_sock*) arg;
    conn = arg_sock->conn;
    u16_t buflen;
    char* buf;
    TFT_SetTextColor(LCD_COLOR_BLUE);
    for(;;)
    {
        // Убрали newconn и далее в вызовах функций меняем ее на conn
        netconn_write(conn, "READY", 5, NETCONN_COPY);            // Sending "READY"
        for(;;)
        {
          recv_err = netconn_recv(conn, &inbuf);                  // Receiving the socket data in inbuf
          if (recv_err == ERR_OK)
          {
            netbuf_data(inbuf, (void**)&buf, &buflen);               // Data transfer of the inbuf data to buf
            if((buf[0]==0x0D)||(buf[0]==0x0A))                       // Checking of the data ending
            {
              netbuf_delete(inbuf);
              continue;
            }
            qstruct = osMailAlloc(strout_Queue, osWaitForever);
            qstructhandler = osMailAlloc(handler_Queue, osWaitForever);      // Handler Queue
            qstruct->y_pos = arg_sock->y_pos;
            strncpy(str_buf,buf,buflen);
            str_buf[buflen]=0;
            sprintf(qstruct->str,"%-20s", str_buf);
            osMailPut(strout_Queue, qstruct);
            sprintf(qstructhandler->handler_str,"%-20s", str_buf);           // Handler Queue
            osMailPut(handler_Queue, qstructhandler);                        // Handler Queue
            str_buf[buflen] = '\r';
            str_buf[buflen+1] = '\n';
            netconn_write(conn, str_buf, buflen+2, NETCONN_COPY);
            netbuf_delete(inbuf);
 
          }
          else
          {
            netbuf_delete(inbuf);
            break;
          }
        }
      }
 
    }
}
1
4 / 4 / 0
Регистрация: 12.11.2018
Сообщений: 511
18.08.2020, 11:19  [ТС]
yatrim, отлично, код заработал, правда если оставить так:
Цитата Сообщение от yatrim Посмотреть сообщение
else
          {
            netbuf_delete(inbuf);
            break;
          }
то завершение соединения не происходит, если добавить
C
1
2
3
4
5
6
7
          else
          {
            netbuf_delete(inbuf);
                netconn_close(conn);
            netconn_delete(conn);
            break;
          }
тогда соединение завершается нормально.
netconn_close(conn); и netconn_delete(conn); лучше оставить здесь или их можно перенести в задачу void StartDefaultTask(void const * argument) где создается соединение? В эту часть кода:
C
1
2
3
4
      else
      {
        netconn_delete(conn);
      }
Еще вопрос по FREERTOS: надо ли в функциях static void tcp_thread_send(void *arg) и static void tcp_thread(void *arg) добавлять в конце osDelay(1)?

Добавлено через 15 минут
yatrim, зачем эту часть кода помещать в цикл for(i = 0; i < 2; i ++)?
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        for(i = 0; i < 2; i ++)
        {
          if (netconn_accept(conn, &newconn) == ERR_OK)
          {
             if(i == 0)
             {
                // 1 client connected
                sock01.conn = newconn;
                sys_thread_new("tcp_thread1", tcp_thread, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
                sys_thread_new("tcp_thread_send1", tcp_thread_send, (void*)&sock01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
             }
             else
             {
                // 2 client connected
                sock02.conn = newconn;
                sys_thread_new("tcp_thread2", tcp_thread, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
                sys_thread_new("tcp_thread_send2", tcp_thread_send, (void*)&sock02, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );
             }
          }
        }
Добавлено через 38 минут
yatrim, еще сейчас обнаружил, что при попытке подключить второе соединение, оно не создается, пока не нашел в чем может быть проблема

Добавлено через 12 минут
yatrim, точнее оно создается, но данные идут с ошибками, соединение периодически обрывается, и данные не выводятся на дисплей как при первом соединении

Добавлено через 1 час 17 минут
yatrim, Сразу еще спрошу, пока пытаюсь разобраться в вопросе передачи из задачи в функцию static void tcp_thread_send(void *arg)
АЦП в отдельной задаче раз с секунду оцифровывает входной сигнал
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void StartAdcTask(void const * argument)
{
  /* USER CODE BEGIN StartAdcTask */
  /* Infinite loop */
  //-------------------------------------------------------
  uint16_t adcData = 0;                       // ADC data
  for(;;)
  {
    HAL_ADC_Start(&hadc3);
    HAL_ADC_PollForConversion(&hadc3, 100);
    adcData = HAL_ADC_GetValue(&hadc3);
    HAL_ADC_Stop(&hadc3);
    osDelay(1000);
  }
Чтобы передать значение АЦП в функцию передачи данных TCP я могу использовать очереди или нет?
Пока попробовал настроить передачу через очередь osMail, мк зависает
C
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
osMailQId adc_Queue; 
typedef struct struct_adc_t {                      // ADC transmission struct
    uint16_t adc_str;
} struct_adc;
uint16_t adc_data = 0;
#define MAIL_ADC_SIZE (uint16_t) 1
 
  osMailQDef(stradcqueue, MAIL_ADC_SIZE, struct_adc);              // ADC transmission struct
  adc_Queue = osMailCreate(osMailQ(stradcqueue), NULL);
 
void StartAdcTask(void const * argument)
{
  /* USER CODE BEGIN StartAdcTask */
  /* Infinite loop */
  //-------------------------------------------------------
  uint16_t adcData = 0;                       // ADC data
  struct_adc *qstructadc;                     // ADC transmission struct
  for(;;)
  {
    HAL_ADC_Start(&hadc3);
    HAL_ADC_PollForConversion(&hadc3, 100);
    adcData = HAL_ADC_GetValue(&hadc3);
    HAL_ADC_Stop(&hadc3);
 
    qstructadc = osMailAlloc(adc_Queue, osWaitForever);              // ADC transmission struct
    sprintf(qstructadc->adc_str,"%-16s", adcData);                   // ADC transmission struct
    osMailPut(adc_Queue, qstructadc);                                // ADC transmission struct
    osDelay(1000);
  }
  //-------------------------------------------------------
  /* USER CODE END StartAdcTask */
}
 
static void tcp_thread_send(void *arg)
{
    struct netconn *conn;                // Structure for connection
    struct_sock *arg_sock;               // Pointer to arguments of task
    struct netbuf *inbuf;
    arg_sock = (struct_sock*) arg;
    conn = arg_sock->conn;
 
    osEvent adcevent;                    // ADC transmission struct
    struct_adc *qstructadc;              // ADC transmission struct
 
    for(;;)
    {
        adcevent = osMailGet(adc_Queue, osWaitForever);
        if (adcevent.status == osEventMail)
        {
            qstructadc = adcevent.value.p;
            netconn_write(conn, adc_data, 2, NETCONN_COPY);
            osMailFree(adc_Queue, adcevent.value.p);
        }
        osDelay(1);
    }
}
0
76 / 52 / 26
Регистрация: 23.01.2019
Сообщений: 134
18.08.2020, 20:19
1. Логичнее чтоб подключение закрывал и открывал один и тот же поток.
И обрати внимание, что функция netconn_recv может вернуть ошибку не только при потере подключения, но и, например,по таймауту. Если в течение определенного интервала времени не поступит новых данных, то функция вернет ошибку ERR_TIMEOUT. Не факт, что в таком случае нужно закрывать соединение.

2. osDelay(1) добавлять не обязательно.

3. Цикл for(i = 0; i < 2; i ++) я сделал просто для примера двух подключений. Сначала ожидается первое подключение. Когда оно происходит, то для него запускаются потоки чтения и записи. Потом тоже делается для второго. На самом деле реальная логика должна быть сложнее и зависит от приложения. Например диспетчер должен следить за состоянием подключений, и если происходит разрыв, то давать возможность заново подключаться.

4. У тебя поле adc_str структуры struct_adc имеет целочисленный тип uint16_t
C
1
2
3
typedef struct struct_adc_t {                      // ADC transmission struct
    uint16_t adc_str;
} struct_adc;
А ты с ним обращаешься как со строкой - получаешь нарушение доступа к памяти с непредсказуемыми последствиями.

C
1
sprintf(qstructadc->adc_str,"%-16s", adcData);
0
4 / 4 / 0
Регистрация: 12.11.2018
Сообщений: 511
19.08.2020, 08:16  [ТС]
yatrim,
1)
Цитата Сообщение от yatrim Посмотреть сообщение
функция netconn_recv может вернуть ошибку не только при потере подключения, но и, например,по таймауту
Странно что в качестве аргумента к функции netconn_recv нет возможности задать тот самый таймаут
Цитата Сообщение от yatrim Посмотреть сообщение
Логичнее чтоб подключение закрывал и открывал один и тот же поток
Если функции закрытия и удаления соединения
C
1
2
            netconn_close(conn);
            netconn_delete(conn);
перенести в задачу StartDefaultTask где происходит создание соединения, то соединения закрывается с ошибкой, возможно некорректно делаю обработку закрытия соединения
4) Спасибо за подсказку, с типами данных в очередях пока проблема
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
19.08.2020, 08:16
Помогаю со студенческими работами здесь

LwIP + NXP + freeRtos трабл
LwIP + NXP1769 + freeRtos, HTTP server падает через определённое количество запросов. Количество запросов прямопропорцианально от...

stm32f2 ethernet lwip freeRtos
Доброго времени! Наблюдается следующая проблема в данной конфигурации: подаем питание, контроллер запускается, работает нное количество...

stm32f107vc + ethernet + freertos + IAR + lwIP
Добрый день всем. Взял я пример вот с этого сайта. catethysis.ru/stm32-lan8720-freertos-iar/ У меня точно такая же платка. (как я...

STM32F4+PHY+FREERTOS+LWIP+UDP скорость
Кто-нибудь тестировал максимальную скорость передачи данных при использовании STM32F4+PHY+FREERTOS+LWIP+UDP? У меня получилось 24 Мб\с, не...

Одновременная работа LWIP и USB HS FreeRTOS STM32F407
Такая проблема, есть задачи которые должен решать контроллер - прочитать файл с USB флешки и передать его по Ethernet Ethernet отдельно...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru