Thread: Putting char in unsigned char

  1. #1
    Registered User
    Join Date
    Sep 2020
    Posts
    20

    Putting char in unsigned char

    Hi all,

    I'm about to finalize my project, at last!
    Still I'm facing one issue.

    I have a UDP multicolor lamp, which works on a unique address (ID) so you can have 100 lamps working separately.

    With an custom Windows application you can set this address(or mode).

    Currently is my issue that my 'packetBuffer' is a char variable, while my 'tableID' is a unsigned char.

    This is the essential piece of code:
    Code:
      tableID = Udp.read(packetBuffer, 255);
      Serial.println(tableID);
      EEPROM.put(address, tableID);
        if (EEPROM.commit()) {
          Serial.println("EEPROM successfully committed -- TABLE ID is updated");
          Udp.beginPacket(Udp.remoteIP(), destinationPort);
          String text = "New table ID is: ";
          String toSend = text + tableID;
          Udp.print(toSend);
          Udp.endPacket();
          //resetFunc(); ///RESET CODE(!)
        } else {
          Serial.println("ERROR! EEPROM commit failed");
        }
    When running this, my tableID remains 0.
    What I'm sending through UDP ASCII is "101"

    In that case tableID should be updated to 101

    Code:
    char packetBuffer[256];
    unsigned char tableID;
    I can not change the type since it is used for more.

    I'm willing to share the full code but it's 900 lines long

  2. #2
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    Is this for Arduino? In that case, Udp.read() returns the number of bytes read, not the data itself. You will have to parse the packet data in the packetBuffer variable after you read it from UDP.

  3. #3
    Registered User
    Join Date
    Sep 2020
    Posts
    20
    Quote Originally Posted by christop View Post
    Is this for Arduino? In that case, Udp.read() returns the number of bytes read, not the data itself. You will have to parse the packet data in the packetBuffer variable after you read it from UDP.
    Hi christop, yes, correct, in the end it is for Arduino/NodeMCU.
    I've tried many things like also;

    tableID = packetBuffer; (which gives an compile error since packetBuffer is char and tableID is unsigned char)

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by unknown_072
    tableID = packetBuffer; (which gives an compile error since packetBuffer is char and tableID is unsigned char)
    Are you sure you are getting a compile error? It is legal to implicitly convert a char to an unsigned char, and even if char is signed that conversion is well defined so I would not expect even a warning. However, it can be good to make the conversion explicit by a cast, and perhaps an overzealous compiler might emit a warning if you don't do that, but even then it'll only be an error if you're compiling with the option of treating warnings as errors.

    Anyway, a cast is not necessarily the correct solution. You need to know the format of the value that is stored in the buffer, e.g., if it is text you may need to parse the text as a numeric string that is converted to an unsigned char.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Sep 2020
    Posts
    20
    Quote Originally Posted by laserlight View Post
    Are you sure you are getting a compile error? It is legal to implicitly convert a char to an unsigned char, and even if char is signed that conversion is well defined so I would not expect even a warning. However, it can be good to make the conversion explicit by a cast, and perhaps an overzealous compiler might emit a warning if you don't do that, but even then it'll only be an error if you're compiling with the option of treating warnings as errors.

    Anyway, a cast is not necessarily the correct solution. You need to know the format of the value that is stored in the buffer, e.g., if it is text you may need to parse the text as a numeric string that is converted to an unsigned char.
    Hi laserlight, this specific UDP packet is always a 3-digit number.
    I'm still experiencing with the max range of that number, but for testing that number is always a value between 100 and 200.

    My UDP packet is always is in ASCII format sending for example "101" to the controller.

    At first I also tried to read it like this:
    Code:
      /*if ( !strcmp(packetBuffer, "%03d"))
        {
        int newID = (int)packetBuffer; 
        tableID = (unsigned char)newID;
        Serial.println(tableID);
    But also, no succes.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    That makes it easy. I'd suggest something like this:
    Code:
    numBytes = Udp.read(packetBuffer, 255);
    if (numBytes != 3) {
        // handle unexpected input error
        // ...
    }
    
    unsigned int result = 100 * (packetBuffer[0] - '0') + 10 * (packetBuffer[1] - '0') + (packetBuffer - '0');
    if (result > UCHAR_MAX) {
        // handle input value out of range error
        // ...
    }
    
    tableID = (unsigned char)result;
    where the type of numBytes is the return type of Udp.read. You can also do additional error checking to confirm that the content of packetBuffer are digits before you do the computation. Alternatively, you could call strtol instead of doing your own computation, and then check the range.
    Last edited by laserlight; 09-30-2020 at 02:21 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Sep 2020
    Posts
    20
    Quote Originally Posted by laserlight View Post
    That makes it easy. I'd suggest something like this:
    Code:
    numBytes = Udp.read(packetBuffer, 255);
    if (numBytes != 3) {
        // handle unexpected input error
        // ...
    }
    
    unsigned int result = 100 * (packetBuffer[0] - '0') + 10 * (packetBuffer[1] - '0') + (packetBuffer - '0');
    if (result > UCHAR_MAX) {
        // handle input value out of range error
        // ...
    }
    
    tableID = (unsigned char)result;
    where the type of numBytes is the return type of Udp.read. You can also do additional error checking to confirm that the content of packetBuffer are digits before you do the computation. Alternatively, you could call strtol instead of doing your own computation, and then check the range.
    Thanks for the suggestion! first I used 'char' as type for numBytes, since, the packetBuffer is also char. This gave an error.

    So then I tried 'int' since, that is wat I originally use as you can see here in code
    Code:
      int len = Udp.read(packetBuffer, 255);
        if (len > 0) {
          packetBuffer[len] = 0;
          checkPackets();
        }
    This also resulted in error: invalid conversion from 'char*' to 'unsigned int' [-fpermissive]

    Where this is the code, used from your suggestion:

    Code:
    int numBytes = Udp.read(packetBuffer, 255);
    if (numBytes != 3) {
        // handle unexpected input error
        // ...
    }
    
    
    unsigned int result = 100 * (packetBuffer[0] - '0') + 10 * (packetBuffer[1] - '0') + (packetBuffer - '0');
    if (result > UCHAR_MAX) {
        // handle input value out of range error
        // ...
    }
    
    
    tableID = (unsigned char)result;
      
    }
    the compile error is on this line:
    Code:
    unsigned int result = 100 * (packetBuffer[0] - '0') + 10 * (packetBuffer[1] - '0') + (packetBuffer - '0');

  8. #8
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Code:
    ...(packetBuffer - '0');
    Should be
    Code:
    ...(packetBuffer[2] - '0');

  9. #9
    Registered User
    Join Date
    Sep 2020
    Posts
    20
    Quote Originally Posted by Click_here View Post
    Code:
    ...(packetBuffer - '0');
    Should be
    Code:
    ...(packetBuffer[2] - '0');
    Ah yes, well that worked! Thanks.
    But still, there is a difference in the numbers, and I would say that has to do with the unsigned char vs. char?

    For instance, I've set my table ID to 135 (by sending UDP packet "135"), however my controller puts it to ID: 131
    If I send 195 then the controller says it 191, so it seems to me like there always is a difference of 4

    What's the nicest way to make this correct?

  10. #10
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    Quote Originally Posted by unknown_072 View Post
    Ah yes, well that worked! Thanks.
    But still, there is a difference in the numbers, and I would say that has to do with the unsigned char vs. char?

    For instance, I've set my table ID to 135 (by sending UDP packet "135"), however my controller puts it to ID: 131
    If I send 195 then the controller says it 191, so it seems to me like there always is a difference of 4

    What's the nicest way to make this correct?
    It most likely isn't to do with the signed/unsigned issue. Are you able to post more of your code for us to check?

    Also, are you able to display each digit and check what you are being sent? If you are getting the characters "1", "9" and "5", then that calculation will give you 195, regardless of it using signed or unsigned chars.

  11. #11
    Registered User
    Join Date
    Sep 2020
    Posts
    20
    Okay I'll try to explain, it's a bit hard.
    The device(lamp) has a unique ID(the 3 digits we are talking about).
    This ID can be set through a custom WinForm which I've built for it.
    The device will always talk back to the WinForm with clear information.

    It works like this:

    1. WinForm application open
    2. Choose mode "Set new ID"
    3. Application: "Set destination IP" --- to make sure we bind with the correct device
    4. The device now answers: Current table ID + "is listening"
    5. Now you can enter an ID, when pressing enter, the device answers: "Waiting for ID to be committed"
    6. Press enter to commit (string will be send with the ID)
    6. Now is the interesting part:
    The device checks all incoming packets, if a packet is not recognized but it received it specifically it will respond with it's ID and a text "Command not recognized".

    It is correct that it responds like this, since I did not build a line that will recognize an ID -- it is a debug feature.
    The interesting thing is that the device will always respond: (current)ID + " : This command is not recognized"

    The ID is always 225, no matter which value I set as ID.
    Putting char in unsigned char-2020-09-30-12_33_49-de-terrastool-copyrightthebulb-png

    I can ask, after this process, for the actual ID of the device. Which is different again, it is the more precise ID with an offset of 4Putting char in unsigned char-2020-09-30-12_38_33-de-terrastool-copyrightthebulb-png


    I've attached my code here: Pastebin.com - Forbidden (#403) . The lines can be found in void addressLamp()
    (starting on line 731) the addressLamp process is started through a boolean started on line 421

  12. #12

  13. #13
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    I think this isn't working as you expect:


    Code:
      else if ( !strcmp(packetBuffer, "%u"))
        {
        int newID = (int)packetBuffer; 
        tableID = (unsigned char)newID;
        Serial.println(tableID);
        Serial.println(newID);

    What do you expect it will do?

  14. #14
    Registered User
    Join Date
    Sep 2020
    Posts
    20
    Quote Originally Posted by hamster_nz View Post
    I think this isn't working as you expect:


    Code:
      else if ( !strcmp(packetBuffer, "%u"))
        {
        int newID = (int)packetBuffer; 
        tableID = (unsigned char)newID;
        Serial.println(tableID);
        Serial.println(newID);

    What do you expect it will do?
    Correct, It won't do anything. It was an attempt to capture the digits in the string, before this I've tried with "%03d"

  15. #15
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    What you are wanting is something like

    Code:
    if(isdigit(packetBuffer[0]) && isdigit(packetBuffer[1]) isdigit(packetBuffer[2]))
       ....
    Or something similar that is aligned with what you are doing in the packet (i.e enforces the correct number of digits).

    PS. You need to have included "ctype.h" header for the isdigit() function.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Compare unsigned char array with const char*
    By Lazar in forum C++ Programming
    Replies: 3
    Last Post: 09-10-2015, 08:36 AM
  2. Replies: 4
    Last Post: 07-24-2012, 10:41 AM
  3. Replies: 2
    Last Post: 10-06-2009, 09:37 AM
  4. cast unsigned char* to (the default) signed char*
    By Mario F. in forum C++ Programming
    Replies: 24
    Last Post: 07-27-2007, 10:41 AM
  5. unsigned char vs signed char and range of values
    By Silvercord in forum C++ Programming
    Replies: 5
    Last Post: 01-22-2003, 01:30 PM

Tags for this Thread