convert ascii bytes to uint8 via udp and apply to function

hello

I,m sending some variable in size ascii string to arduino mega and ethernet shield via udp library.

the messages are multiples of 5 and maximum of 512 and this will be one :

1823202122 in ascii

i would like to get this char array from udp and convert it into uint8 to apply to a function for example analogWrite.

so the first 18 will be apply to
analogWrite(0,uint8Byte[0]; this will be 18
analogWrite(0,uint8Byte[1]; this will be 23
analogWrite(0,uint8Byte[2]); this will be 20
and so on.

i tried different things i saw the most used way is the atoi but tried with no success .

void loop() {
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if(packetSize)
  {
    // read the packet into packetBufffer
    Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);

   for ( int i = 0; i <MAX_DATA_ELEMENTS; i++) {
   //int input = atoi(&packetBuffer[i]);
   input[i] = atoi(&packetBuffer[i]);
   //input[i] = packetBuffer[i];
   // for (i=0; i<strlen(str); i++)

   analogWrite(5,input[0]); //Test for the Analog Pin 5

    }

    delay(2);
}
}

could you please show me the right way to do it so i can use incoming string as an array of uint8?
cheers

think it should be this, not tried,
but it seems to me that you cannot read UDP_TX_PACKET_MAX_SIZE bytes when only packetSize bytes have been received.

void loop() 
{
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
   // read the packet into packetBuffer
    Udp.read(packetBuffer, packetSize);   // UDP_TX_PACKET_MAX_SIZE);

   for ( int i = 0; i < packetSize; i++) 
  {
    input[i] = packetBuffer[i];
  }
  analogWrite(5, input[0]);
}

Hi robtillaart thank you for your response

i tried your suggestion and some other but did not get it right what other things could i try ?

#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>       
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 2, 12);
unsigned int localPort = 10000;      // local port to listen on
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
//////////////
void setup() {
  // start the Ethernet and UDP:
  Ethernet.begin(mac,ip);
  Udp.begin(localPort);

  Serial.begin(9600);
}

void loop() 
{
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
    int input[packetSize];
   // read the packet into packetBuffer
    Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);   // UDP_TX_PACKET_MAX_SIZE);

   for ( int i = 0; i < packetSize; i++) 
  {
    //input[i] = atoi(packetBuffer);
    input[i] = atoi(&packetBuffer[i]);
    Serial.print(atoi(packetBuffer));
    Serial.print(" ");
    Serial.print(packetBuffer[0]);//this seems to show only first part of the number like 22 shows only 2
    Serial.print(" ");
    Serial.print(packetBuffer);//this is the only one that shows the similar string of incoming values 
    Serial.print(" ");
    Serial.print(input[0]); 
    Serial.println();
 
  //analogWrite(5, input[0]);
  analogWrite(5,packetBuffer[0]);
  }
}
}

atoi works through an array of char converting it to integer until it comes across a character that doesn't belong. Your packet data has ten digits so it'll try to convert them all into a single number, which will then overflow.

You will need to copy two digits at a time into a null terminated buffer and run the atoi on that instead.

hello wildbill

thanks for your reply.
could you show me an example of your idea ?
i read some staff that you have to add one more value int intLength = intData.length() + 1 in the case of a string.
but did no get right how to do the whole loop.

cheers :slight_smile:

btw just to clarify the values are comes in ascii and represent uint8 not bigger than 32 in the case is different for this occasion.

here, I build up strings ( in this case upto 11 chars long into an array called wrapper[].

my Udp class is called mpTunnel from this working snippet.

    uint8_t pos = 0;
    char c = mpTunnel.read();

    while( c > 0 ) {
        // we hold max of 11 user bytes as we need \0 on the end, normally we look for '|' to end string
        if ( c == '|' || pos == 11 ) {
            wrapper[pos] = '\0';
            break;
        }
        else {
            wrapper[pos++] = c;
        }
        c = mpTunnel.read();
    }

Here's a way to do it:

void loop() 
{
int packetSize = Udp.parsePacket();
if (packetSize)
  {
  int input[packetSize];
  Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);

  for (int i = 0,idx=0; i < packetSize; i+=2,idx++) 
    {
    char buf[3];
    memcpy(buf,&packetBuffer[i],2);
    buf[2]=0;
    input[idx] = atoi(buf);
    Serial.print(buf);
    Serial.print(" ");
    Serial.print(packetBuffer[0]);
    Serial.print(" ");
    Serial.print(packetBuffer);
    Serial.print(" ");
    Serial.print(input[idx]); 
    Serial.println();
    analogWrite(5,input[idx]);
    }
  }
}

If you don't mind overwriting the packet data, you could write nulls into the packet data directly and use atoi on it. You would need to start from the end of the packet and work backwards though. Also, you'd need to ensure the buffer was big enough to add a null at the end.

memcpy could be considered overkill to copy two bytes, you might want to do it explicitly with two assignments.

hi guys thank you for your examples ;D

@wildbil

i tested your code and work partly, like if i send decimal number from 10-99 seems to affect ok some little interferences, i guess because signal is not clean. but if i send same values in ascii which is what i need then it does not translate it right , do you know why and how to change that ?
also when sending bigger amount of values like dinamicly do i need to change the char Amount ?

buf[3];// here ? or it does automaticly ? 
    memcpy(buf,&packetBuffer[i],2);
    buf[2]=0;

i tried changing all values when it seems packages are not receive fully sometimes is there a way to make sure it gets the actual one i was thinking of this header first byte and maybe end byte of the message to check not to sure how to do until i get values correctly i guess like darryl suggested.

@darryl

i tried your code like that and other ways :

void loop() 
{
int packetSize = Udp.parsePacket();
if (packetSize)
  {
  uint8_t input[packetSize];
  Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
  
    uint8_t pos = 0;
    char c = Udp.read();
    char wrapper[11] ;
    while( c > 0 ) {
        // we hold max of 11 user bytes as we need \0 on the end, normally we look for '|' to end string
        if ( c == '|' || pos == 11 ) {
            wrapper[pos] = '\0';
            break;
        }
        else {
            wrapper[pos++] = c;
          
        }
            c = Udp.read();
            Serial.print(pos);
            Serial.print(" ");
            Serial.print(wrapper);
            Serial.print(" ");
            Serial.print(c);
            Serial.println();
            //analogWrite(5,atoi( ));
    }
            
   
    }
  }

probably in the wrong way ?, i was sending 10 values in ascii + CR so 11 , i did also try other format but i could not get anything printed i guess i have this conversion problem as your code looks like what i need to clean the signal and combine with wildbil one.

thanks again for help and patience :slight_smile:

Hello

This seems to do the filtering fine for now at least in the tests i could send a maximum of 734 values at same time from the pc with reasonable speed ,i changed the maximum size in line #define UDP_TX_PACKET_MAX_SIZE 3072 in the EthernetUdp.h

#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>       
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 2, 12);
unsigned int localPort = 10000;      // local port to listen on
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
//////////////
void setup() {
  // start the Ethernet and UDP:
  Ethernet.begin(mac,ip);
  Udp.begin(localPort);
  //Serial.begin(115200);
}

void loop() 
{
int packetSize = Udp.parsePacket();
if (packetSize > 0 )
{
//if (packetSize > 0  && packetSize==24 )
  
  uint8_t input[packetSize];
  Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
  if( packetBuffer[0]=='<' && packetBuffer[packetSize-1]=='>'){
    
  for (int i = 0,idx=0; i < packetSize; i+=2,idx++) 
    {
    char buf[3];
    memcpy(buf,&packetBuffer[i],2);
    buf[2]=0;
    input[idx] = atoi(buf);
//    Serial.print(packetSize);
//    Serial.print(" ");
//    Serial.print(packetBuffer[0]);
//    Serial.print(" ");
//    Serial.print(packetBuffer);
//    Serial.print(" ");
//    Serial.print(input[0]); 
//    Serial.println();
    analogWrite(5,(input[1]));
    analogWrite(6,(input[2]));
    }
   }
  }
}

what is this maximum of 734 values i could send related to ? ,it,s Arduino Mega memory that runs out of mem or to the udp protocol will it help sending in 2 difference instances of udp , or other parameter i could change ?

i would need to send 512 X 5 + header and ending byte will Mega cope with it ?

i still have 2 main problems in the code

1-one is the heading and ending < >
i send from the computer <<23312310>> so i would like to get rid of the heading and ending bytes from the calculation so index 0 will be value = 23 and index 3 = 10 in this : <<23312310>> how can i do that ?

2-i have to send decimal values from the computer in the range of (10-99) for this to work. somehow it does not understand the encoding when i send ascii , right now i use utf-8 any ideas ?

tips to optimized the code very welcome.

cheers

I think you will find the maximum packet size for the w5100 is 1500 bytes due to the size of its buffers. I believe you must leave room for the header, so the actual payload will be less than 1500 bytes.

hello SurferTim thanks

yes makes sense as i send 734 values but it interpreters as double as sending a decimal like 10 it convert to a Hex 31 30 which takes 2 bytes so 734 x 2 is around the 1500 bytes limit.

which is the actual thing i need to sort to send only one byte per value i need.

i need arduino atoi and memcpy to interpret the ascii hex as decimal values so if i send in ascii :

<<5%2:>>
[Header][Payload][End]
[<<][5%2:][>>]
being the hex representation
3C 3C 35 25 32 3A 3E 3E
[3C 3C ][ 35 25 32 3A][3E 3E ]
it should calculate the decimal value of
[3C 3C ][53 37 50 58][3E 3E ]
Payload in Hex : 35 25 32 3A
Payload in Decimal :4 independent uint8 53, 37, 50, 58

somehow arduino is only converting to the char itself not to the value that represent in ascii or hex.

I tried to change the code like that but no luck :

void loop() 
{
int packetSize = Udp.parsePacket();
if (packetSize > 0 )
{
  uint8_t input[packetSize];
  Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
  if( packetBuffer[0]=='<' && packetBuffer[packetSize-1]=='>'){
    
  for (int i = 0; i < packetSize; i++) 
    {
    char buf[1];
    memcpy(buf,&packetBuffer[i],1);
    //buf[1]=0;
    input[i] = atoi(buf);

      Serial.print(packetBuffer);
      Serial.print(" ");
      Serial.print(input[2],HEX); 
      Serial.print(" ");
      Serial.print(input[4],HEX); 
      Serial.println();
    analogWrite(5,(input[2]));
    analogWrite(6,(input[4]));
    }
   }
  }
}

what am i doing wrong ?
regards

I see that you have added start and end packet markers '<' and '>'. What are the '%' and ':' for?

In the example you give, '5%2:', what number(s) are expecting your code to parse?

hi

yes the parsing should be :
from this ASCII: 5%2: to this decimal 53 37 50 58
or in other words from this hex
35 25 32 3A to this decimal 53 37 50 58
the message it is like that :
[Header][Payload][End]
[<<][5%2:][>>]
being the hex representation
3C 3C 35 25 32 3A 3E 3E
[3C 3C ][ 35 25 32 3A][3E 3E ]
it should calculate the decimal value of the ASCII character
[3C 3C ][53 37 50 58][3E 3E ]
Payload in Hex : 35 25 32 3A
Payload in Decimal :4 independent uint8 53, 37, 50, 58

the payload will be as bigger as possible so maybe 1400bytes to be treated as independent values

like when you do the conversion in an online converter ASCII Converter - Hex, decimal, binary, base64, and ASCII converter you will see the representation of the decimal value from 5%2:

there might be something to do in arduino to interpret the ASCII as its representative decimal value ?

I really don't understand what you're trying to do. However, if you want to see the ascii value of a character you can cast it to an int and print it:

char buf[]="5%2:";
for(int i=0;i<4;i++)
  Serial.println((int)buf[i]);

hi

i,m trying to do exactly what you did but instead of Serial printing use this representative value in a function like analogWrite();

so the printing value is the actual same value to be used in the function.

you see what i mean ?

Then all you need is:

if (packetSize)
  {
  Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);   // UDP_TX_PACKET_MAX_SIZE);

  for ( int i = 0; i < packetSize; i++) 
    {
      analogWrite(5,packetBuffer[i]);
    }
  }

You might want to declare packetBuffer to be unsigned char rather than char.

Hello wildbill haha ;D in the end it was much simpler than we tried before. thank you very much.

i paste the code for someone else, as soon as i get something cool with it i,ll paste some link here.

now i can send a max of 1470 values to arduino and seem fast. i still need to get to 2560 so have to think how to minimized data more as i dont use the whole uint8 as 3 parameters use range[0-16] and other 2 parameters [0,32] i have to find the way to encode more values in an efficient way. i,ll play a bit and open new post for that.

thanks all for helping.

#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>       
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 2, 12);
unsigned int localPort = 10000;      // local port to listen on
// buffers for receiving and sending data
unsigned char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
//////////////
uint8_t HeaderSize = 1;//'<'
uint8_t HeaderEndSize = 2;//'<''>'

void setup() {
  // start the Ethernet and UDP:
  Ethernet.begin(mac,ip);
  Udp.begin(localPort);
  //Serial.begin(115200);

}

void loop() 
{
int packetSize = Udp.parsePacket();
if (packetSize > 0 )
{
//if (packetSize > 0  && packetSize==24 )
  
  uint8_t input[packetSize];
  Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
  if( packetBuffer[0]=='<' && packetBuffer[packetSize-1]=='>'){

unsigned char CleanBuffer [packetSize-HeaderEndSize];
    memcpy(CleanBuffer,packetBuffer+HeaderSize,packetSize-HeaderEndSize);
    uint8_t input[packetSize-HeaderEndSize];
    
  //for (int i = 0,idx=0; i <packetSize-2; i+=2,idx++) 
  for (int i = 0; i <packetSize-2; i++) 
    {
//
//    char buf[3];
//    memcpy(buf,&CleanBuffer[i],2);
//    
//    buf[2]=0;
//    
//    input[idx] = atoi(buf);
//    Serial.print(packetSize);
//    Serial.print(" ");
//    Serial.print(packetBuffer[0]);
//    Serial.print(" ");
//    Serial.print(packetBuffer);
//    Serial.print(" ");
//    Serial.print(input[0]); 
//    Serial.println();
    analogWrite(5,(CleanBuffer[0]));
    analogWrite(6,(CleanBuffer[1]));
    }
   }
  }
}