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
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
}
}