Reading TCP binary as HEX, then reading HEX in parts

Hello All,
This is definitely a rookie question, but i am trying to read a tcp packet as a HEX string then use the different byte sets to perform different commands or functions. ex:

Listen to port
IF 1st HEX is AA do something
Then if 2nd HEX is BB do something else
Then if 3rd Hex etc...

I am new to this all together so i'm not even sure where to start, but this is what i have so far:

void loop() { 

  {WiFiClient client = server.available();
    if (client.connected()) {
      Serial.println("Connected to client");
      String line = client.readStringUntil('\r'); 
      
      byte b[6];
   Serial.println("Incoming command Set: ");
   Serial.println(client.read(),HEX);
   Serial.print(b[0]); Serial.print(" ");
   Serial.print(b[1]); Serial.print('\n'); 
   {  if (b[0] == 0xAA){functionOne();         Serial.print("One");}
       if (b[0] == 0xBB){functionTwo();       Serial.print("Two");}
}

All I get out of the serial monitor when sending any HEX codes to it is:

Incoming command Set:
FFFFFFFF
0 0

What am i missing? Cheers in advance!

Serial.println(client.read(),HEX);

If you read that when nothing is there to read you get a -1, otherwise written as 0xFF. You should be checking available to see if there is anything to read before you try to read it.

Ymunk:
I am new to this all together so i'm not even sure where to start, but this is what i have so far:

You ought to read: WiFi reference

and check out client.available()

Yours,
TonyWilk

Thanks guys for the reply,
Ive looked in the WiFI library examples as well as the Arduino reference for client.available. Ive tried the codes in the examples which gave me the same output (-1).

I did find an example in the ESP8266WiFi library which works better by checking if available as you said, my output is now in ASCII but any hex comes out as follows:

void loop() { 
  WiFiClient client = server.available();
  if (client)         // wait for a client (web browser) to connect
  {
    Serial.println("\n[Client connected]");
    while (client.connected())
    {
      if (client.available())             // read line by line what the client (web browser) is requesting
      {
        Serial.println("Incoming command Set: ");
        String line = client.readStringUntil('\r');
        Serial.print(line);
      
    uint8_t b1 = client.read();
    uint8_t b2 = client.read();
 
  Serial.print(client.read(),HEX);
  Serial.print(b1); Serial.print(" ");
  Serial.print(b2); Serial.print('\n'); 
}}}}

Output:
[Client connected]
Incoming command Set:
⸮⸮⸮
FFFFFFFF
255 255

So i guess now how would i take the "line" or client.read and convert it into HEX that i can pick out?

Do you mean you want to take that ascii which is in hex and turn it into a number?

You keep talking about the term hex like it changes the number somehow. Hex is just a way to write a number. You don't convert numbers to or from hex. A number is just a number and how you write it doesn't change it.

        Serial.println("Incoming command Set: ");
        String line = client.readStringUntil('\r');
        Serial.print(line);
     
    uint8_t b1 = client.read();
    uint8_t b2 = client.read();
 
  Serial.print(client.read(),HEX);

Printing a string without delimiters, even a carriage return and/or line feed is not the brightest idea. You've learned nothing about what is in the line object.

You now KNOW that there is data to read, so you can call ONE function to read data. After that, you MUST assume that there is no more data to read, and stop trying to read when you don't KNOW that there IS data to be read.

What im trying to do is read all the binary coming through in a hexadecimal format. When i send text it gets displayed as text but when i send a hexadecimal packet it displays -1 or FFFF. I would like to send it a packet containing ex :

AA 11 22 33 BB etc...

and it reads the int as AA and then performs a program based on each block of characters after.
I think that the whole String line might not be the way to do it at all, but to be honest this is my first real program outside of blinky lights and servos lol.

im using serial.print just for debugging and to see what different outputs i get. Im sure the use of uint8-t makes it worse in this example.

Is there something better than using the string.line approach, like just read it as integers and output as hex representation?

Hi,
I've tried to comment your code from above to describe what is actually happening:

    while (client.connected())
    {
      if (client.available())             // read line by line what the client (web browser) is requesting
      {

        //--> we get here if *something* is available, we don't know what or how much yet

        Serial.println("Incoming command Set: ");

        //--> the readStringUntil() function *waits for stuff to arrive* until it gets a '\r' character

        String line = client.readStringUntil('\r');

        //--> if readStringUntil() did not find a '\r' character in time, it gives up and returns anyway

        Serial.print(line);

        //--> at his point we've maybe read some string, but that is all we know
        //--> we DO NOT KNOW if anything else is ready to read 
      
        //--> these read()'s are most likely returning -1 meaning *there is no character available*
        uint8_t b1 = client.read();
        uint8_t b2 = client.read();

Even if those problems were fixed, the program reads as if you want to send something like:

   "This is a string\r####"      where the #'s are single byte values

I'm guessing this is not what you want.

However, I'm not sure what you do want. To send values you could mean either:

   "2A413D"    the text string representing 3 hex values 0x2A, 0x41 and 0x3D as character pairs
or
   "*A="   3 byte values shown here as characters whose ASCII values are 0x2A, 0x41 and 0x3D

Yours,
TonyWilk

      if (client.available())             // read line by line what the client (web browser) is requesting

That is NOT what that code is doing. The available() method reports how many characters are waiting to be read. There is nothing about that information that relates to "lines".

        //--> we get here if *something* is available, we don't know what or how much yet

We may not know what, but we COULD, by capturing the value that available() returned, know how much.

So basically everything up to if client.available is ok? lol

Cool, thats actually what i was wondering since i could only seem to be able to send an ASCII message but not receive anything nearly decipherable in HEX.

What i want to send and have received are HEX values, not text, at various lengths 0x2A, 0xCC, 0x21, 0x2A
and the esp reads it as 0x2A, 0xCC, 0x21, 0x2A, and breaks them into separate HEX or byte sets.

So, Other than String how would i capture that?

if client.available
something = client.read
convert binary bytes to hex string? > byte 0, byte 1, byte 2
if byte 0(as HEX)...
if byte 1...

Ymunk:
Cool, thats actually what i was wondering since i could only seem to be able to send an ASCII message but not receive anything nearly decipherable in HEX.

That makes no sense. The only way it can be "HEX" is if it is being sent as ascii. HEX only exists in the world of representing numbers with symbols. If you're just sending a number then it is just a number. Show us how you are sending it. Maybe that will help.

Show us how you are sending it.

And, tell us what is sending the data. If what is sending the data is sending text, you have no choice but to read the data AS TEXT.

Im using an app called Packet Sender at the moment to test my signals. It lets you send either an ASCII message or HEX. I know that ASCII, Hex, Dec are all just different representations of binary 1s and 0s.

So i guess i should be asking how to make the ESP see the binary thats coming in as HEX representation.

If i can keep it as sending numbers and that makes it easier than i am all for it!
255 = FF
100 = 64 etc

I think MQTT is the closest thing to what im trying to do, just without a server.

OKIE DOKE!

So ive tried one thing different which has gotten me one step closer. The bytes are coming through read as HEX and DEC but not in any kind of order for me to pick out.

int inCommand; //< placed before void setup

void loop() {

   WiFiClient client = server.available();
  
  if (client)                   // wait for a client (web browser) to connect
    {Serial.println("\n[Client connected]");
      while (client.connected()){

       if (client.available() ???? )     // <--- I know there's something missing here that puts the int into a 
                                                 //         single string format 

      {Serial.println("Incoming command Set: ");
       
        uint8_t inCommand = client.read(????);    // <--- and probably something here 

         
         Serial.println(inCommand, HEX);
         Serial.println(inCommand);

Message Sent:

0xFF 0x64 0xAA 0xEE

Serial Output:

[Client connected]
Incoming command Set:
FF
255
Incoming command Set:
64
100
Incoming command Set:
AA
170
Incoming command Set:
EE
238

Hi,

Ymunk:
The bytes are coming through read as HEX and DEC but not in any kind of order for me to pick out.

You also said earlier:

I think MQTT is the closest thing to what im trying to do, just without a server.

If you look at the MQTT specification, it is a packet protocol within TCP/IP.
It is intended that you get a packet of bytes and then decode it... in the case of MQTT, bytes of the packet are in the simplest case:

           1 byte packet type     \ these 2 bytes are the packet header
           1 byte length          /
    length bytes of data

You can do the same sort of thing like:

      if (client.available() == 2)        // wait for packet header bytes
      {
        uint8_t pktType = client.read();  // read the header information
        uint8_t dataLen = client.read();

        Serial.print("Packet type: 0x"); Serial.print(pktType, HEX );
        Serial.print("  data length: "; Serial.println( dataLen );
   
        while( client.available() < dataLen ){
             // wait for data bytes to be available
        }

        if( client.available >= dataLen ){
           for( int dataBytes= 0; dataBytes<dataLen; dataBytes++ ){
              uint8_t oneByte= client.read();
              Serial.print( oneByte, HEX ); Serial.print("  ");
           }
         }
      }

Then send a message like: 0x42 0x03 0x11 0x22 0x33

Note that the code above will probably work... just. It will not work well if you ever send the wrong length or any byte gets missed in a transmission. The problem being that you want a 'packet protocol' like MQTT, but your interface using client.available() and client.read() is a stream, more like serial data.

Ideally you need to implement a State Machine to receive the data, see: How to process incoming serial data without blocking

Yours,
TonyWilk

       if (client.available() ???? )     // <--- I know there's something missing here that puts the int into a
                                                 //         single string format

That comment suggests that you STILL don't understand what available() does. Would it help if the function was called howManyBytesCanBeRead()? Then, would you put such non-sense comments next to that function call?

PaulS,

I get what available() does. What i didnt understand was the syntax needed to show that i dont have a set amount of bytes, and they need to be read till the end of each transmission. I now know that i dont need anything else there. Thanks

Using uint8_t b1 = client.read(); seems to be the way to go when processing everything from within only the loop function.

So for now i have this and it works:

void runStat(){}         //Still need to write something
void powerFunc (){}

void loop() {

   WiFiClient client = server.available();
  
  if (client)                   
    {Serial.println("\n[Client connected]");
      while (client.connected()){
       if (client.available()) {

      {Serial.println("Incoming Command: "); 
      
    uint8_t b1 = client.read(); uint8_t b2 = client.read(); uint8_t b3 = client.read();
    uint8_t b4 = client.read(); uint8_t b5 = client.read(); uint8_t b6 = client.read();

{    if (b1 == 0x10){                          // STATUS
          if (b3 == b1) {
              Serial.print("Running Stats");
              runStat();}
                else {Serial.println ("Unknown command");}}
           
      if (b1 == 0x20){                          // POWER
          if (b3 == b1) {
              Serial.print("Power");  
              display.print("Power "); 
              powerFunc(); }
                else {Serial.println("Unknown command");}}

TonyWilk
Ive looked at the example for buffering input, and then sending it to a another function to prevent "blocking". It looks like pretty much exactly what i would need to implement

How would you go about applying that concept to this? Should i have client.read be buffered before the "if" arguments?
Or should i have the buffering occur at the call to other functions? ie runStat(client.read()), powerFunc(client.read())??

Your inconsistent placement of curly braces, your placing of code after a curly brace, your useless curly braces, and your poor indenting make for VERY hard to read and understand code.

Fix that, if you want me to continue trying to help.

Put EVERY { on a line BY ITSELF.
Put EVERY } on a line BY ITSELF.

Put ONE statement on any given line.

Use Tools + Auto Format.

       if (client.available()) {

      {Serial.println("Incoming Command: ");
     
    uint8_t b1 = client.read(); uint8_t b2 = client.read(); uint8_t b3 = client.read();
    uint8_t b4 = client.read(); uint8_t b5 = client.read(); uint8_t b6 = client.read();

If there is at least one byte to be read, it is NOT OK to read 6 bytes, unless you KNOW that there are at least six bytes to be read.