Функция, возвращающая тип структуры, ничего не возвращает каждый раз, когда вызывается - PullRequest
0 голосов
/ 11 ноября 2019

Я пишу программу для получения SSID и пароля через BlueTooth в ESP32 (Arduino Framework). Функция BTSerialRcvBuffer () ожидает BlueTooth, когда она получает строку, она возвращает базовый адрес и размер строки через переменную типа struct Buffer_return. Функция возвращает SSID, но не пароль. Не знаю почему? Нужно ли выделять память для Var.rtn_addr или достаточно памяти для переменных buff1 и buff2?

#include <Arduino.h>
#include <stdlib.h>
#include <BluetoothSerial.h>
#include <WiFi.h>

#define btrcv_buffer_size 256

BluetoothSerial SerialBT;

typedef struct
{
  char *rtn_addr;
  int buff_len;
} Buffer_return;


Buffer_return* BTSerialRcvBuffer() {

  static int i = 0;
  static char rcv_buffer[ btrcv_buffer_size ];
  static Buffer_return Var;

  memset(rcv_buffer,0, btrcv_buffer_size);

  while (!SerialBT.available());
  delayMicroseconds(500);

  while(SerialBT.available()) {
    rcv_buffer[i] = SerialBT.read();
    i++;
  }
  rcv_buffer[i-1] = '\0';
  rcv_buffer[i-2] = '\0';
  SerialBT.flush();

  Var.rtn_addr = rcv_buffer;  //<------------Do I have to allocate memory for Var.rtn_addr?
  Var.buff_len = i-1;

  return &Var;
} 

void WiFiConfig() {

  //WiFi.printDiag(Serial);

  Serial.println("Enter SSID");
  Buffer_return *buff1 = BTSerialRcvBuffer();
  char *ssid = (char*) malloc((buff1->buff_len) * sizeof(char));  
  strcpy(ssid,buff1->rtn_addr);
  Serial.println(ssid);  

  Serial.println("Enter Password");
  Buffer_return *buff2 = BTSerialRcvBuffer();
  char *pass = (char*) malloc((buff2->buff_len) * sizeof(char));  
  strcpy(pass,buff2->rtn_addr);
  Serial.println(pass); 
  //Serial.println(buff2->buff_len);  


  free(ssid)
  free(pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Establishing connection to WiFi..");
    Serial.printf("Connection status: %d\n", WiFi.status());
  }  
}

void setup() {

  Serial.begin(115200);
  //WiFi.disconnect(true);
  SerialBT.begin("ESP32_INO"); //Bluetooth device name
  WiFi.mode(WIFI_STA);
  Serial.println("The device started, now you can pair it with bluetooth!");

  WiFiConfig();

  Serial.println("Connected to network");
  Serial.println(WiFi.macAddress());
  Serial.println(WiFi.localIP());
}

void loop() {

  }

Вывод:

Enter SSID
Airtel_5G             <----- prints fine!
Enter Password
                      <----- Problem!
Establishing connection to WiFi..
Connection status: 6
Establishing connection to WiFi..
Connection status: 6
Establishing connection to WiFi..
Connection status: 6

Ответы [ 2 ]

2 голосов
/ 11 ноября 2019

Код использует следующую последовательность для копирования входных данных в буфер.

  Buffer_return *buff1 = BTSerialRcvBuffer();
  char *ssid = (char*) malloc((buff1->buff_len) * sizeof(char));  
  strcpy(ssid,buff1->rtn_addr);

Напомним, что строки заканчиваются NUL, так что распределение должно включать дополнительный байт !. Простое обновление для вызова malloc:

char *ssid = (char*) malloc((buff1->buff_len+1) * sizeof(char));

Для каждого входа из @lundin malloc не рекомендуется для Arduino. Лучше использовать автоматическое распределение.

См. Также: https://arduino.stackexchange.com/questions/682/is-using-malloc-and-free-a-really-bad-idea-on-arduino

  char ssid[buff2->buff_len+1] ;
  strcpy(ssid, buff2->rtn_addr) ;

Обновление 1: ошибка в BTSerialRcvBuffer

BTSerialRcvBuffer использует статическое для многих переменных, включаяi. Напомним, что статические переменные инициализируются один раз (при запуске программы). Предлагая удалить «static» из i - чтобы исправить инициализацию, так как нет необходимости делать ее статичной.

Кроме того, неясно, почему последние 2 позиции rcv_buffer обнуляются?

1 голос
/ 11 ноября 2019

В вашем коде много плохой практики и медленных вызовов функций. Имейте в виду, что это 8-битный MCU, поэтому он ужасно медленный. Некоторые вещи, которые нужно исправить:

  • Нет необходимости каждый раз обнулять буфер rx. Просто следите за тем, какая большая часть содержит действительные данные. Вызов memset для 256 байтов очень дорогой.
  • Обычной практикой является двойной буфер rx-буферов, чтобы один буфер можно было использовать для приема, а другой для декодирования одновременно. Вы не используете прерывания, так что, возможно, это не проблема. В любом случае, 256 байтов - это много оперативной памяти, поэтому для двойной буферизации может потребоваться более мощный MCU, если вам необходимо хранить такое количество данных. В любом случае я буду использовать приведенный ниже пример двойного буфера, чтобы показать, как это можно сделать.
  • delayMicroseconds(500); ничего не делает, кроме зависания вашей программы на 500 мс. Удалите это.
  • Ошибка: вы не проверяете переполнение буфера во время приема.

#define BT_RXBUF_SIZE 256

const char* BTSerialReceive (size_t* size_rec) 
{
  static char buf1 [BT_RXBUF_SIZE];
  static char buf2 [BT_RXBUF_SIZE];
  static char* buf = buf1;

  buf = (buf == buf1) ? buf2 : buf1; // swap rx buffers


  while (!SerialBT.available())
    ;


  size_t i=0;
  for(; SerialBT.available() && i<BT_RXBUF_SIZE; i++)
  {
    buf[i] = SerialBT.read();
  }
  buf[i] = '\0';

  SerialBT.flush();

  *size_rec = i;
  return buf;
} 

Замена указателя с двойными буферами устраняет необходимость в memcpy/ strcpy которые медленные и дорогие. Если вы использовали прерывания UART, вам пришлось бы использовать такой дизайн по причинам повторного входа.

Еще одна вещь, которую вы должны избегать, это malloc. Это медленно и бессмысленно, см. . При работе со встроенными системами вы всегда должны использовать буферы фиксированной длины и детерминированные объемы памяти. Избавление от malloc означает, что вы можете избавиться от целого сегмента кучи в сценарии компоновщика, что высвободит много ценного ОЗУ.

...