Files
MqttCanGateway/mqttclient.cpp
Wolfgang Hottgenroth 910d8c7c02 changes
2016-10-31 13:37:10 +01:00

210 lines
5.3 KiB
C++

/*
* mqttclient.cpp
*
* Created on: 03.03.2016
* Author: wn
*/
#include <stdlib.h>
#include "mqttclient.h"
#include <avr/wdt.h>
#include <Streaming.h>
#include <Ethernet.h>
#include <Metro.h>
#include <PubSubClient.h>
#include <stdio.h>
#include "canclient.h"
static const char MESSAGE_TOPIC[] = "IoT/MqttCanGateway/Message";
static const char WATCHDOG_TOPIC[] = "IoT/Watchdog";
void callback(char* topic, byte* payload, unsigned int length);
static uint8_t MAC[] = { 0x90, 0xA2, 0xDA, 0x00, 0x51, 0x09 };
const static char BROKER[] = "mqttbroker";
EthernetClient client;
PubSubClient mqttClient = PubSubClient(BROKER, 1883, callback, client);
uint8_t disconnectState = 0;
uint32_t disconnectTime = 0;
Metro minute = Metro(60000);
Metro second = Metro(1000);
uint32_t uptime;
void callback(char* topic, byte* payload, unsigned int length) {
const uint8_t BUFSIZE = 128;
if ((length + 1) >= BUFSIZE) { // 1 for terminating NUL
// Serial << "Received message too long, ignore it" << endl;
} else {
char buffer[BUFSIZE];
memcpy(buffer, payload, length);
*(buffer + length) = 0;
Serial << "Received message: " << length << ", " << String(topic) << ", " << String(buffer) << endl;
// 00000001 08 01 02 03 04 05 06 07 08
// ^^^^^^^^ Address
// ^^Payload Length
// ^^^^^^^^^^^^^^^^^^^^^^^ Payload
if (!(strcmp(topic, MESSAGE_TOPIC))) {
char *paramPtr = buffer;
Serial << paramPtr << endl;
uint32_t canAddress;
uint8_t canLength;
const uint8_t MAX_CAN_MSG_SIZE = 8;
uint8_t canDataBuffer[MAX_CAN_MSG_SIZE];
uint8_t canDataBufferIdx = 0;
uint8_t state = 0;
int8_t done = 0;
while (done == 0) {
Serial << "State: " << (uint16_t) state << endl;
if ((paramPtr != 0) && (*paramPtr != 0)) {
char *dataPtr = strsep(&paramPtr, " ");
uint32_t data = strtol(dataPtr, NULL, 16);
switch (state) {
case 0:
Serial << "address found: " << data << endl;
canAddress = data;
state++;
break;
case 1:
Serial << "length found: " << data << endl;
if (data > MAX_CAN_MSG_SIZE) {
Serial << "length too large" << endl;
done = -1;
} else {
canLength = data;
state = 2;
}
break;
case 2:
Serial << "payload octet found: " << data << endl;
if (data > 255) {
Serial << "too large for an octet" << endl;
done = -1;
} else {
canDataBuffer[canDataBufferIdx] = data;
canDataBufferIdx++;
if (canDataBufferIdx == canLength) {
done = 1;
}
}
break;
}
} else {
Serial << "Error in received message, to little data" << endl;
done = -1;
}
}
if (done == 1) {
Serial << "complete message received" << endl;
Serial << "Address: " << canAddress << endl;
Serial << "Length: " << (uint16_t)canLength << endl;
Serial << "Data: ";
for (uint8_t i = 0; i < canLength; i++) {
Serial << (uint16_t)canDataBuffer[i] << " ";
}
Serial << endl;
CanClientNS::sendMessage(canAddress, canLength, canDataBuffer);
} else if (done == -1) {
Serial << "error while evaluating message" << endl;
}
} else if (!strcmp(topic, WATCHDOG_TOPIC)) {
wdt_reset();
} else {
// Serial << "Strange, unknown topic received" << endl;
}
}
}
void MqttClientNS::begin() {
Ethernet.begin(MAC);
Serial << "Got IP address: " << Ethernet.localIP() << endl;
disconnectState = 3;
disconnectTime = millis();
}
void MqttClientNS::exec() {
if ((disconnectState == 0) && (! mqttClient.loop())) {
disconnectState = 1;
}
switch (disconnectState) {
case 0:
// Serial.println("discState 0");
// everything fine
break;
case 1:
// Serial.println("discState 1");
mqttClient.disconnect();
disconnectTime = millis();
disconnectState = 2;
break;
case 2:
// Serial.println("discState 3");
if (disconnectTime + 2000 < millis()) {
disconnectState = 3;
}
break;
case 3:
// Serial.println("discState 3");
if (mqttClient.connect("Monitor")) {
mqttClient.subscribe(MESSAGE_TOPIC);
mqttClient.subscribe(WATCHDOG_TOPIC);
disconnectTime = millis();
mqttClient.publish("IoT/MqttCanGateway/Started", "MqttCanGateway started");
disconnectState = 0;
} else {
disconnectState = 1;
}
break;
default:
disconnectState = 0;
break;
}
if (second.check() == 1) {
uptime++;
// Serial.println("mqtt tick");
if (disconnectState == 0) {
String msg = String("{ \"metadata\": { \"device\": \"MqttCanGateway\" }, \"data\": { \"uptime\": ") + uptime + String("}}");
mqttClient.publish("IoT/MqttCanGateway/Heartbeat", (char*)msg.c_str());
}
}
}
void sendMessage(uint32_t address, uint8_t length, uint8_t *payload) {
const uint8_t BUFSIZE1 = 25;
char buffer1[BUFSIZE1];
char *bufPtr = buffer1;
for (uint8_t i = 0; i < length; i++) {
int res = sprintf(bufPtr, "%02x ", payload[i]);
bufPtr += res;
}
int l = strlen(buffer1);
buffer1[l-1] = 0;
const uint8_t BUFSIZE2 = 170;
char buffer2[BUFSIZE2];
int res = snprintf(buffer2, BUFSIZE2, "{ \"metadata\": { \"device\":\"MqttCanGateway\" }, \"data\": { \"uptime\": %ld, \"address\": \"%08lx\", \"length\": %d, \"payload\": \"%s\" }}", uptime, address, length, buffer1);
if (res >= BUFSIZE2) {
Serial << "too much payload" << endl;
} else {
Serial << "length: " << res << endl;
Serial << "about to send " << buffer2 << endl;
}
}