cmqttcan-buslegato

CAN frame over MQTT (need to convert hex string to byte array)


I am implementing a MQTT communication. I want to send CAN frames over MQTT through a graphical interfaces (realized in python). I am able to send messages from the GUI to one topic and I am able to see messages arrived on the same topic (using paho library) when I use the board. The function is below and the topic is diagnostic_request/topic:

 void onMessageArrived
(
    const char* topic,
    const uint8_t* payload,
    size_t payloadLen,
    void* context
)
{
    //LE_FATAL("The publisher received a message!");
    //GIMP
    char payloadStr[payloadLen + 1];
    memcpy(payloadStr, payload, payloadLen);
    payloadStr[payloadLen] = '\0';
    LE_INFO("Received message! topic: \"%s\", payload: \"%s\"", topic, payloadStr);
    //GIMP principio di conversione

    if (strcmp(subscribeTopic, topic)==0)
        LE_INFO("Sei sul topic di richiesta diagnostica!");
        can_send();        
  }

At this point I have a difficulty. My can_send function (that works!) is:

int can_send(void)
{
    const char* subscribeTopic = "diagnostic_request/topic";
    LE_FATAL_IF(
            mqtt_Subscribe(MQTTSession, subscribeTopic, MQTT_QOS0_TRANSMIT_ONCE) != LE_OK,
            "failed to subscribe to %s",
            subscribeTopic);
    LE_INFO("Subscribed to topic (%s)", subscribeTopic);


           
        
int nbytesWrite;

// USE SEND STANDARD FRAME
frameWrite.can_id = 0x750; //codice identificativo di una richiesta diagnostica per centralina simulata
frameWrite.can_id &= CAN_SFF_MASK;

frameWrite.can_dlc = 8;
 //strcpy((char *)frameWrite.data, "MGATE");
frameWrite.data[0] = 0x03;
frameWrite.data[1] = 0x22;
frameWrite.data[2] = 0xF1;
frameWrite.data[3] = 0x89;
frameWrite.data[4] = 0x00;
frameWrite.data[5] = 0x00;
frameWrite.data[6] = 0x00;
frameWrite.data[7] = 0x00;
if ((nbytesWrite = write(sdw, &frameWrite, sizeof(frameWrite))) != sizeof(frameWrite))
{
    canwrite = false;
    LE_INFO ("Writing error, nbytesWrite = %d", nbytesWrite);
    return SOCK_WRITING_ERROR;
}

canwrite = true;
return 0;
}

So I have to call can_send in the onMessageArrived function when is statement is ok. I am able to see when I send a publish on diagnostic_request/topic. The only problem is to send the payloadStr value to the can_send function and unpackage it in the frameWrite.data[]. Can someone help me to understand how to modify the can_send function in order that the values

frameWrite.data[0] = 0x03;
frameWrite.data[1] = 0x22;
frameWrite.data[2] = 0xF1;
frameWrite.data[3] = 0x89;
frameWrite.data[4] = 0x00;
frameWrite.data[5] = 0x00;
frameWrite.data[6] = 0x00;
frameWrite.data[7] = 0x00;

are values that I send through mqtt in the payloadStr? I send a string of 8 bytes but I can't unpackage it. Any help will be appreciated Regards


Solution

  • Taking the approach of "write the test first".....

    int convertNybble (char const hex) 
    {
        if (hex >= '0' && hex <= '9')
        {
            return hex - '0';
        }
        else if (hex >= 'a' && hex <= 'f')
        {
            return 10 + (hex - 'a');
        }
        else if (hex >= 'A' && hex <= 'F')
        {
            return 10 + (hex - 'A');
        }
        
        return -1; // invalid hex character
    }
    
    
    #define ERR_NOT_EVEN_NUMBER_OF_DIGITS   -1
    #define ERR_STRING_TOO_LONG             -2
    #define ERR_INVALID_CHAR                -3
    
    
    int preparePayload(char const* hexString, unsigned char* canBuffer, size_t const bufLen)
    {
        size_t hexLen = strlen(hexString);
    
        if (0 != (hexLen % 2))
        {
            // Expect an even number of digits.
            return ERR_NOT_EVEN_NUMBER_OF_DIGITS;
        }
    
        size_t payloadLen = hexLen / 2;
    
        // buffer will contain payload-length, followed by payload data.
        //  so payloadLen+1 must be able to fit into bufLen - fail if payloadLen+1 > bufLen, which is the same as payloadLen >= bufLen
        if (payloadLen >= bufLen)
        {
            // will not be able to fit the decoded string into the payload buffer
            return ERR_STRING_TOO_LONG;
        }
    
        unsigned char* bufEnd = canBuffer;
        bufEnd += bufLen;
    
        *canBuffer++ = (unsigned char)payloadLen;
    
        while (payloadLen > 0)
        {
            payloadLen--;
    
            int hexDigit[2];
            hexDigit[0] = convertNybble(*hexString++);
            hexDigit[1] = convertNybble(*hexString++);
    
            if ((hexDigit[0] < 0) || (hexDigit[1] < 0))
            {
                return ERR_INVALID_CHAR;
            }
    
            *canBuffer++ = (hexDigit[0] << 4) | hexDigit[1];
        }
    
        // fill any leftovers with zero
        while (canBuffer < bufEnd)
        {
            *canBuffer++ = 0;
        }
    
        return (0);
    }
    
    
    
    int performTests()
    {
        char const* testStr[5] =
        {
            "12345",
            "0123456789ABCDEF",
            "@ABC",
            "0AF9",
            "0123456789ABCD"
        };
    
    #define MARKER 0xFF
    #define PAYLOAD_LEN 8
        unsigned char payload[PAYLOAD_LEN+1];
        payload[PAYLOAD_LEN] = MARKER;
    
        int decodeResult = preparePayload(testStr[0], payload, PAYLOAD_LEN);
    
        if (ERR_NOT_EVEN_NUMBER_OF_DIGITS != decodeResult) { return -1; }       //not expected result
    
        decodeResult = preparePayload(testStr[1], payload, PAYLOAD_LEN);
    
        if (ERR_STRING_TOO_LONG != decodeResult) { return -1; }
    
        decodeResult = preparePayload(testStr[2], payload, PAYLOAD_LEN);
    
        if (ERR_INVALID_CHAR != decodeResult) { return -1; }
    
        // here we are checking the character decoding
        decodeResult = preparePayload(testStr[3], payload, PAYLOAD_LEN);
    
        if (0 != decodeResult) { return -1; }
    
        if (payload[0] != 2)    { return -1; }
        if (payload[1] != 0x0A) { return -1; }
        if (payload[2] != 0xF9) { return -1; }
        if (payload[3] != 0)    { return -1; }
        if (payload[7] != 0)    { return -1; }
        // payload contains - 02 0a f9 00 00 00 00 00 00
    
        // here we are checking the limit of the payload capacity
        decodeResult = preparePayload(testStr[4], payload, PAYLOAD_LEN);
    
        if (0 != decodeResult) { return -1; }
        // payload contains - 07 01 23 45 67 89 ab cd
    
    
        // check we haven't overrun the buffer
        if (payload[8] != MARKER) { return -1; }
    
    
        // all tests pass
        return 0;
    }
    
    
    int main()
    {
        int testResult = performTests();
        return testResult;
    }
    

    You can then embody the decoder as follows:

    convertNybble, preparePayload etc as above....
    
    
    int canbusSend(unsigned char const* canbusPayload)
    {
        //etc
    
        // - copy payloadBytes to frameWrite.data....
    
        //etc
    }
    
    
    void onMessageArrived
    (
        const char* topic,
        const uint8_t* mqttPayload,
        size_t payloadLen,
        void* context
    )
    {
    #define CANBUS_PAYLOAD_BUFFER_LEN   8
        unsigned char canbusPayload[CANBUS_PAYLOAD_BUFFER_LEN];
        int decodeResult = preparePayload((char const*)mqttPayload, canbusPayload, CANBUS_PAYLOAD_BUFFER_LEN);
    
        if (0 == decodeResult)
        {
            int canbusSendResult = canbusSend(canbusPayload);
            // TODO : report error if failed
        }
        else
        {
            //TODO : report error
        }
    }