diff --git a/Makefile b/Makefile index 9d9dc98..a67ca7f 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ command: gcc -o ${BIN}/command network.c command.c readref: - gcc -o ${BIN}/readref network.c mqtt.c -lmosquitto readref.c + gcc -o ${BIN}/readref network.c mqtt.c -lmosquitto readref.c -lm .PHONY: clean dirs clean: diff --git a/mqtt.c b/mqtt.c index 0964fef..b9547aa 100644 --- a/mqtt.c +++ b/mqtt.c @@ -6,7 +6,7 @@ // https://mosquitto.org/api/files/mosquitto-h.html #include -struct mosquitto *connectMqtt(char *user, char *pass) +struct mosquitto *connectMqtt(char *user, char *pass, void (*messageCallback)(struct mosquitto *, void *, const struct mosquitto_message *)) { int err; struct mosquitto *mqtt; @@ -47,6 +47,8 @@ struct mosquitto *connectMqtt(char *user, char *pass) return NULL; } + mosquitto_message_callback_set(mqtt, messageCallback); + return mqtt; } @@ -57,7 +59,22 @@ int sendMqtt(struct mosquitto *mqtt, char *topic, char *payload, int payloadLeng err = mosquitto_publish(mqtt, NULL, topic, payloadLength, payload, 0, false); if (err) { - fprintf(stderr, "Error publishing message (%d): %s\n", err, mosquitto_strerror(err)); + fprintf(stderr, "Error publishing message to %s (%d): %s\n", topic, err, mosquitto_strerror(err)); + return -1; + } + else + { + return 0; + } +} + +int recvMqtt(struct mosquitto *mqtt, char *topic) +{ + int err; + + err = mosquitto_subscribe(mqtt, NULL, topic, 0); + if (err) { + fprintf(stderr, "Error subscribing to %s (%d): %s", topic, err, mosquitto_strerror(err)); return -1; } else @@ -71,4 +88,5 @@ void disconnectMqtt(struct mosquitto *mqtt) // ignore errors mosquitto_disconnect(mqtt); mosquitto_destroy(mqtt); + mosquitto_lib_cleanup(); } \ No newline at end of file diff --git a/mqtt.h b/mqtt.h index 212260a..4205426 100644 --- a/mqtt.h +++ b/mqtt.h @@ -1,3 +1,4 @@ -struct mosquitto * connectMqtt(char *user, char *pass); +struct mosquitto * connectMqtt(char *user, char *pass, void (*messageCallback)(struct mosquitto *, void *, const struct mosquitto_message *)); int sendMqtt(struct mosquitto *mqtt, char *topic, char *payload, int payloadLength); +int recvMqtt(struct mosquitto *mqtt, char *topic); void disconnectMqtt(struct mosquitto *mqtt); \ No newline at end of file diff --git a/network.c b/network.c index 3971cfe..325d88f 100644 --- a/network.c +++ b/network.c @@ -48,7 +48,7 @@ int sendToXPlane(int sock, char *destAddr, int destPort, char *msg, void *payloa } else { - fprintf(stderr, "Failed to send message (%d): %s", errno, strerror(errno)); + fprintf(stderr, "Failed to send message (%d): %s\n", errno, strerror(errno)); return -1; } } @@ -57,7 +57,10 @@ int recvFromXPlane(int sock, char msg[DGRAM_MSG_LENGTH], void *payload, int maxL { char buf[maxLength + DGRAM_MSG_LENGTH]; memset(buf, 0, sizeof(buf)); - int recvBytes = recv(sock, buf, maxLength + DGRAM_MSG_LENGTH, 0); + + strcpy(msg, ""); + + int recvBytes = recv(sock, buf, maxLength + DGRAM_MSG_LENGTH, MSG_DONTWAIT); if (recvBytes >= 0) { if (recvBytes >= DGRAM_MSG_LENGTH) @@ -68,14 +71,21 @@ int recvFromXPlane(int sock, char msg[DGRAM_MSG_LENGTH], void *payload, int maxL } else { - fprintf(stderr, "Received data without message header?!"); + fprintf(stderr, "Received data without message header?!\n"); return -11; } } else { - fprintf(stderr, "Error receiving data (%d): %s", errno, strerror(errno)); - return -1; + if (errno != EAGAIN) + { + fprintf(stderr, "Error receiving data (%d): %s\n", errno, strerror(errno)); + return -1; + } + else + { + return 0; + } } } diff --git a/readref.c b/readref.c index 201cd2c..bb5919c 100644 --- a/readref.c +++ b/readref.c @@ -2,17 +2,34 @@ #include #include #include +#include +#include #include "network.h" #include "mqtt.h" #include "config.h" +#define MQTT_RREF_REQUEST_LENGTH_ID 3 +#define MQTT_RREF_REQUEST_LENGTH_FREQ 3 +#define MQTT_RREF_REQUEST_LENGTH_SEPARATOR 1 +#define MQTT_RREF_REQUEST_SEPARATOR ' ' + +const int MQTT_RREF_REQUEST_START_ID = 0; +const int MQTT_RREF_REQUEST_START_FREQ = MQTT_RREF_REQUEST_START_ID + MQTT_RREF_REQUEST_LENGTH_ID + MQTT_RREF_REQUEST_LENGTH_SEPARATOR; +const int MQTT_RREF_REQUEST_START_RREF = MQTT_RREF_REQUEST_START_FREQ + MQTT_RREF_REQUEST_LENGTH_FREQ + MQTT_RREF_REQUEST_LENGTH_SEPARATOR; + +const int MQTT_RREF_REQUEST_MIN_LENGTH = MQTT_RREF_REQUEST_LENGTH_ID + MQTT_RREF_REQUEST_LENGTH_FREQ + (2 * MQTT_RREF_REQUEST_LENGTH_SEPARATOR) + 1; // at least one char for rref + +int xPlaneSocket; +struct mosquitto *mqtt; + +#define XPLANE_RREF_MAX_LENGTH 400 struct dref_struct_in { int32_t dref_freq; int32_t dref_sender_index; // the index the customer is using to define this dataref - char dref_string[400]; + char dref_string[XPLANE_RREF_MAX_LENGTH]; }; struct dref_struct_out @@ -21,19 +38,70 @@ struct dref_struct_out float dref_flt_value; }; -int main(int argc, char *argv[]) +int *strtoint(char *in, size_t start, size_t n) { - int xPlaneSocket; - struct mosquitto *mqtt; - char *wtf; + int *ret = malloc(sizeof(int)); + *ret = 0; + int offset = start + n - 1; - // check argument - if (argc != 1 && (argc - 1) % 3 != 0) + if (offset < 0) { - fprintf(stderr, "Usage: %s [ [ ... ]]\n", argv[0]); - exit(EXIT_FAILURE); + return NULL; } + for (int i = 0; i < n; i++) { + int position = offset - i; + if (in[position] >= '0' && in[position] <= '9') + { + *ret += (in[position] - '0') * pow(10, i); + } + else + { + return NULL; + } + } + + return ret; +} + +void onMessage(struct mosquitto *mqtt, void *obj, const struct mosquitto_message *message) +{ + int *id, *frequency; + char rref[XPLANE_RREF_MAX_LENGTH]; + + printf("Received message %.*s on topic %s\n", message->payloadlen, (char *)message->payload, message->topic); + + if (strcmp(message->topic, "/xplane/meta/rref") == 0) + { + printf("found rref request\n"); + if (message->payloadlen >= MQTT_RREF_REQUEST_MIN_LENGTH) + { + id = strtoint(message->payload, MQTT_RREF_REQUEST_START_ID, MQTT_RREF_REQUEST_LENGTH_ID); + frequency = strtoint(message->payload, MQTT_RREF_REQUEST_START_FREQ, MQTT_RREF_REQUEST_LENGTH_FREQ); + + if (id == NULL || frequency == NULL) { + return; + } + + // prepare struct to send, make sure padding is with NULL bytes + struct dref_struct_in drefToRead = { + .dref_freq = *frequency, + .dref_sender_index = *id + }; + memset(drefToRead.dref_string, 0, sizeof(drefToRead.dref_string)); + strncpy(drefToRead.dref_string, &((char *)message->payload)[MQTT_RREF_REQUEST_START_RREF], message->payloadlen - MQTT_RREF_REQUEST_START_RREF); + + sendToXPlane(xPlaneSocket, DEST_SERVER, DEST_PORT, "RREF", (char *)&drefToRead, sizeof(drefToRead)); + } + } + else + { + fprintf(stderr, "Unkown topic %s\n", message->topic); + } +} + +int main() +{ // network xPlaneSocket = createSocket(SRC_PORT); if (xPlaneSocket < 0) @@ -42,25 +110,15 @@ int main(int argc, char *argv[]) } // mqtt - mqtt = connectMqtt(MQTT_USER, MQTT_PASS); - - // request every dref from arguments - for (int i = 1; i < argc; i = i + 3) + mqtt = connectMqtt(MQTT_USER, MQTT_PASS, onMessage); + if (mqtt == NULL) { - // prepare struct to send, make sure padding is with NULL bytes - struct dref_struct_in drefToRead = { - .dref_freq = strtoimax(argv[i + 1], &wtf, 10), - .dref_sender_index = strtoimax(argv[i + 2], &wtf, 10)}; - memset(drefToRead.dref_string, 0, sizeof(drefToRead.dref_string)); - strcpy(drefToRead.dref_string, argv[i]); - - // send payload - if (sendToXPlane(xPlaneSocket, DEST_SERVER, DEST_PORT, "RREF", (char *)&drefToRead, sizeof(drefToRead)) < 0) - { - exit(EXIT_FAILURE); - } + exit(EXIT_FAILURE); } + // subscribe meta channel + recvMqtt(mqtt, "/xplane/meta/#"); + // read from network char msg[DGRAM_MSG_LENGTH + 1]; char payload[RECV_BUFFER]; @@ -69,17 +127,18 @@ int main(int argc, char *argv[]) while (1) { int payloadBytes = recvFromXPlane(xPlaneSocket, msg, payload, RECV_BUFFER); - if (payloadBytes > 0) + if (payloadBytes >= 0) { - printf("Received message type %s\n", msg); - printf("Received message data (%d) ", payloadBytes); - for (int i = 0; i < payloadBytes; i++) - { - printf("%02x", payload[i]); - } - printf("\n"); if (strcmp(msg, "RREF") == 0) { + printf("Received message type %s\n", msg); + printf("Received message data (%d) ", payloadBytes); + for (int i = 0; i < payloadBytes; i++) + { + printf("%02x", payload[i]); + } + printf("\n"); + // XXX: loop throught multiple drefs if ((payloadBytes - 1) % 8 == 0) { @@ -110,6 +169,8 @@ int main(int argc, char *argv[]) { exit(EXIT_FAILURE); } + + mosquitto_loop(mqtt, 100, 1); } // bye bye (and no, I don't care about error anymore; I'll exit anyway?!) diff --git a/test/.gitignore b/test/.gitignore index 7fe8cc4..8afd293 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,4 +1,5 @@ airspeed heading mqtt -mqtt.h \ No newline at end of file +mqtt.h +strtoint \ No newline at end of file diff --git a/test/strtoint.c b/test/strtoint.c new file mode 100644 index 0000000..f2158fc --- /dev/null +++ b/test/strtoint.c @@ -0,0 +1,44 @@ +#include +#include +#include + +int *strtoint(char *in, size_t start, size_t n) +{ + int *ret = malloc(sizeof(int)); + *ret = 0; + int offset = start + n - 1; + + if (offset < 0) + { + return NULL; + } + + for (int i = 0; i < n; i++) { + int position = offset - i; + printf("foo: %c\n", in[position]); + if (in[position] >= '0' && in[position] <= '9') + { + *ret += (in[position] - '0') * pow(10, i); + } + else + { + return NULL; + } + } + + return ret; +} + +int main() +{ + char *in = "abcd123"; + int *ret = strtoint(in, 4, 3); + if (ret != NULL) + { + printf("%s | %d\n", in, *ret); + } + else + { + printf("ret is NULL\n"); + } +}