Convert SML Hex String to signed Integer



  • Hi,

    hopefully this is a real easy one for the Pros - I'm not a c/ c++ programmer & struggeling hard.

    I use the following code on one of my ESP's to read the current (in Watt) & that worked fine:

    double getSubstrFromSMLasDouble(byte smlMessage[], int indexStart, int indexStop){
       return std::strtoul(getSubstrFromSML(smlMessage, indexStart, indexStop).c_str(), 0, 16);
    

    worked fine.. Until I started to generate electricity & now get negative values.

    Something like fffffb60 should convert into -1184.
    ffffd4b1 should convert into -110087

    This guy (https://www.scadacore.com/tools/programming-calculators/online-hex-converter/) says it makes sense to him under the "INT32 - Big Endian (ABCD)" column.

    I did quite a bit of research (not knowing what exactly I was looking for), saw fancy bit shifting in C and tried a couple of code snipets, including those two:

      return std::strtol(getSubstrFromSML(smlMessage, indexStart, indexStop).c_str(), 0, 16);
      return  (double) std::strtol(getSubstrFromSML(smlMessage, indexStart, indexStop).c_str(), 0, 16);
    

    So far that was not very successful - any guidance what I'm up to is appreciated!

    ItsMee



  • Wie sehen denn die Daten in smlMessage aus wenn du diese als Text ausgibst?
    Steht da wirklich fffffb60 als Text drinnen? Oder stehen da binär die 4 Bytes 0xff, 0xff, 0xfb, 0x60 drinnen?



  • Hi @hustbaer,

    danke Dir für's quer lesen & nachdenken!

    Ich habe mir eine angepasste Methode geschrieben um deine Frage zu beantworten:

    String getSubstrFromSMLAsDoubleDirect(byte smlMessage[], int indexStart, int indexStop){
      int arrSize = (2 * (indexStop-indexStart)) + 1;
      char returnValue[arrSize];
      char *myPtr = &returnValue[0];
      for (int i = indexStart; i <= indexStop; i++) {
        snprintf(myPtr, 3, "%02x", smlMessage[i]); //convert a byte to character string, and save 2 characters (+null) to charArr;
        mqttSendJson(OBJECT, getESPid(), opto_powermeter_topic+"/debug/doubleBytes" , "POWERSML", "CURRENTPOWER", String(smlMessage[i]), "Debug");
        myPtr += 2; //increment the pointer by two characters in charArr so that next time the null from the previous go is overwritten.
      }
      return "-1";
    }
    

    Dort bekomme ich dann einzelne Bytes welche von meiner ursprünglichen zu einem String ffffbbc0 concatiniert werden - aber schon die 'sauber' in einen String zu convertieren mache ich ggf. falsch. Da ich an das Gerät nur remote komme habe ich keine Möglichkeit print() zu verwenden sondern "muss" text über MQTT versenden.

    VALUE":"255
    VALUE":"255
    VALUE":"187
    VALUE":"192
    

    Wahrscheinlich hast Du einen Punkt und ich muss an der Stelle schon anfangen, ggf. noch endiness berücksichtigen?

    ItsMee



  • @itsmee sagte in Convert SML Hex String to signed Integer:

    Wahrscheinlich hast Du einen Punkt und ich muss an der Stelle schon anfangen, ggf. noch endiness berücksichtigen?

    for (int i = indexStart; i <= indexStop; i++) {
       snprintf(myPtr, 3, "%02x", smlMessage[i]);
    ...
    

    Ich denke ja, so wie du die einzelnen Bytes konvertierst - bei der niedrigsten Speicheradresse angefangen - muss der Wert in smlMessage im Big-Endian-Format abgelegt sein, damit du mit einem anschließenden std::strtol den korrekten Wert bekommst. Unabhängig von der Endianess des Systems, auf dem das Programm laufen soll.

    Wenn das bei diesem Protokoll nicht der Fall sein sollte, müsstest du die Bytes in umgekehrter Reihenfolge in den String schreiben oder das Ergebnis von std::strtol anpassen.


Anmelden zum Antworten