0

I have been having a heck of a time getting my Arduino Uno Rev2 application to work as intended, which is to parse commands from multiple clients sending in ASCII-based commands over WiFi in order to control and read remote I/O from various I/O->ethernet servers.

The code compiles and runs, but it seems to be distributing my incoming client->read() character pulls across my full 2D array that I am calling inputs[][], which was intended to store the full contiguous message from a single client in one row of the array.

#include <stdlib.h>
#include <SPI.h>
#include <WiFiNINA.h>

char ssid[] = "***";                // House -- Network SSID (name)
char pass[] = "***";              // House -- SSID password (WPA2-PSK)

#define MAX_CLIENTS 5
#define MAX_LINE_LEN 50 
char inputs[MAX_CLIENTS][MAX_LINE_LEN] = {0}; // Instantiate 2D array of 
client/received data
int msg_array[] = {0,0};
int net_status = WL_IDLE_STATUS;              // The Wifi radio's status
WiFiServer server(80);           // Create server object on port of WiFi 
                                 // server, which will be used to 
                                 // respond to commands

WiFiClient *clients[MAX_CLIENTS] = {NULL};    // Create client objects 
                                              // limited to size of 
                                              // MAX_CLIENTS


byte mac[] = {0xDE,0xAD,0xBE,0xEF,0xFE,0xED}; // Arduino's physical MAC
byte ip[] = {192,168,9,25};              // IP of this controller 
byte gateway[] = {192,168,0,1};          // Router address (internet)
byte subnet[] = {255,255,0,0};           // Subnet mask

unsigned long wd_Dside, wd_Cside = millis();   // Gather current tstamp
unsigned long wd_Delap, wd_Celap = 0;          // Create an elapsed time 
                                               //counter 


void setup(){

   pinMode(4, OUTPUT);                 // pin selected to control D SIDE
   pinMode(5, OUTPUT);                 // pin selected to control C SIDE

   //enable serial data print 
   Serial.begin(9600); 
   while (!Serial){
       Serial.println("No serial.");
   }

      Serial.println("Serial.begin was initiated."); 


   if (WiFi.status() == WL_NO_SHIELD) {  // check for the WiFi module:
      Serial.println("Wi-Fi: Communication with NINA has failed!");
      // do nothing here
      while (true);
   }

   String fv = WiFi.firmwareVersion();
   if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
      Serial.println("Please upgrade the firmware");
   }

   while (net_status != WL_CONNECTED) {
      Serial.print("Attempting to connect to WPA SSID: ");
      Serial.println(ssid);

      // Connect to WPA/WPA2 network:
      net_status = WiFi.begin(ssid, pass); // Attempt to join this SSID

      // wait 5 seconds for connection:
      delay(5000);

      listNetworks(); 

      server.begin();                      // Start Wi-Fi server
      Serial.print("Server started on ");
      Serial.println(WiFi.localIP()); 
    }
}


void loop() {

    delay(5);

    WiFiClient newClient = server.available(); // Begin listening for  
                                               // client messages 
    if (newClient) {
        Serial.println("New client discovered."); // Could use this as 
                                                  // an ACK/handshake on 
                                                  // client-side host 
        for (int i=0; i<MAX_CLIENTS; i++) {
          if (clients[i] == NULL) {
            clients[i] = new WiFiClient(newClient);
            break;
      }
   }
}

    for (int i=0; i<MAX_CLIENTS; i++){    // Check client for data
      if (clients[i] != NULL && clients[i]->available()){   
              // If the data isn't garbage and the data is available..
        char newChar = clients[i]->read();         // Read the data 

        if (newChar == '\0') {  // Check for termination char for separation
          char delimiters[] = ",";   // Parse to get command parameterization
          char* valIndex;
          valIndex = strtok(inputs[i], delimiters);
          for (int j=0; j < 2; j++){   
            // Expand later to largest anticipated character count
            msg_array[j] = atoi(valIndex); 
            Serial.print(msg_array[j]);
            valIndex = strtok(NULL, delimiters);
          }

          switch(msg_array[0]) {          
          // Determine type of message received (Character 0 parsed as 
          // Message Type) 

            case '3':                                                 
            // Examine string for client cmds to turn sides on or off. 
            if(msg_array[1] == '1')                                   
            // Msg type 3, Instruction 1: Turn D side ON
              {     
                // Last good heartbeat from client device on D side. 
              }
            if(msg_array[1] == '2')                                   
            // Msg type 3, Instruction 2: Turn D side OFF
              {                            
                // Last good heartbeat from client device on D side. 
              } 
            if(msg_array[1] == '3')                                   
                // Msg type 3, Instruction 3: Turn C side ON
              {                                 
                // Last good heartbeat from client device on C side. 
              }
            if(msg_array[1] == '4')                                   
                // Msg type 3, Instruction 4: Turn C side OFF
              {                                 
                // Last good heartbeat from client device on C side. 
              }
            break;

            case '6':

                // Examine string for another message type TBD 
            break; 

            default: 
              Serial.println("Default break. Received crap.");
            break;

          }

        for (int m=0; m<2; m++){
        Serial.print("Characters detected as: ");
        Serial.print(msg_array[m]);
        }
        Serial.println();
        inputs[i][0] = '\0';                                          
        // Clear out this array element for the next message
        // clients[i]->stop();                                         
        // By default, kill client session, just wait for new TCP open
        // delete clients[i];                                          
        // Remove client element's data
        // clients[i] = NULL;                                          
        // Reset to NULL 

        }

        else {

           if (strlen(inputs[i]) > MAX_LINE_LEN) {                    
                // First check for size compliance
           Serial.println("Max line length exceeded from client.");
           inputs[i][0] = '0';                                        
                // Clear out this array element for the next message
           }
           else {
           size_t l = strlen(inputs[i]);  
           inputs[i][l] = newChar;    
           inputs[i][l + 1] = 0;                               
                // Add character to the received string
           }

          Serial.print("inputs[i]:");
          Serial.println(inputs[i]);
        }
      }
   } 
}

I usually end up with the following output. This is from just one single device submitting the text ",3,2\0" over TCP. I try to tokenize the ",3,2" portion using strtok and then detect "\0" to signal the system to begin parsing the tokens. My apologies for utilizing the code box, but the quote box was not displaying it how I'd prefer:

Serial.begin was initiated.
Please upgrade the firmware
Attempting to connect to WPA SSID: ATT7YLd4JE
Server started on 192.168.1.98
** Scan Networks **
number of available networks:6
0) ATT7YLd4JE   Signal: -61 dBm Encryption: WPA2
1) DIRECT-F8-HP OfficeJet 4650  Signal: -62 dBm Encryption: WPA2
2) mocha        Signal: -87 dBm Encryption: WPA2
3) Scott        Signal: -92 dBm Encryption: WPA2
4) a5231978     Signal: -92 dBm Encryption: WPA2
5) LReusserWifi_EXT     Signal: -94 dBm Encryption: WPA2
New client discovered.
Client: 0
Triggered NULL client
inputs[i]:,
New client discovered.
Client: 0
Client: 1
Triggered NULL client
inputs[i]:,3
inputs[i]:,
New client discovered.
Client: 0
Client: 1
Client: 2
Triggered NULL client
inputs[i]:,32
00Default break encountered. Received gibberish.
Characters detected as: 0Characters detected as: 0
inputs[i]:,32,
inputs[i]:3
inputs[i]:,
New client discovered.
Client: 0
Client: 1
Client: 2
Client: 3
Triggered NULL client
inputs[i]:,32,2
30Default break encountered. Received gibberish.
Characters detected as: 3Characters detected as: 0
inputs[i]:,
New client discovered.
Client: 0
Client: 1
Client: 2
Client: 3
Client: 4
Triggered NULL client
inputs[i]:,32,23
inputs[i]:,
inputs[i]:,2
00Default break encountered. Received gibberish.
Characters detected as: 0Characters detected as: 0
New client discovered.
Client: 0
Client: 1
Client: 2
Client: 3
Client: 4
inputs[i]:,32,23,
inputs[i]:,3
inputs[i]:,2,
inputs[i]:2
00Default break encountered. Received gibberish.
Characters detected as: 0Characters detected as: 0

..and so forth. Is there a graceful way to confine all the data to one row of the array so I can proceed with parsing it as it should look? I feel like I'll need to store additional information coming from my targets, such as their MAC, so I know how to append each character to the appropriate row.

Thanks, Hopeless

  • I am afraid server.available always returns the first client in 'connected' state. test it with WiFiChatServer example. Ethernet library has server.accept presented in AdvancedChatServer example. – Juraj Aug 20 '19 at 9:05
  • If I could control the devices sending data, perhaps starting n number of servers across unique ports would resolve the issue? – user8585939 Aug 20 '19 at 16:36
  • does it always return the same first client? (I can't test it right now) – Juraj Aug 20 '19 at 16:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.