From 25c75c41f4cdbb09500ebe0a43c3ae91329852b6 Mon Sep 17 00:00:00 2001 From: Jeremy Hahn Date: Wed, 4 May 2016 00:07:40 -0400 Subject: [PATCH] Refactor canbus_iotbridge to passthru_iotbridge. Replace awsiot_client with passthru_shadow. Add file logger. --- Makefile.am | 8 +- src/awsiot_client.c | 4 + src/canbus_filelogger.c | 70 +++++++ src/canbus_filelogger.h | 27 +++ src/canbus_log.c | 48 +++++ src/canbus_log.h | 32 ++++ src/canbus_logger.c | 27 +++ src/canbus_logger.h | 27 +++ src/canbus_logger_interface.h | 33 ++++ src/ecutuned.c | 2 +- src/j2534.c | 27 ++- src/j2534.h | 1 - src/j2534_shadow.c | 17 -- src/j2534_shadow.h | 61 ------ ...anbus_iotbridge.c => passthru_iotbridge.c} | 174 +++++++----------- ...anbus_iotbridge.h => passthru_iotbridge.h} | 8 +- src/passthru_shadow.c | 137 ++++++++++++++ src/passthru_shadow.h | 67 +++++++ tests/check_j2534.c | 4 +- 19 files changed, 573 insertions(+), 201 deletions(-) create mode 100644 src/canbus_filelogger.c create mode 100644 src/canbus_filelogger.h create mode 100644 src/canbus_log.c create mode 100644 src/canbus_log.h create mode 100644 src/canbus_logger.c create mode 100644 src/canbus_logger.h create mode 100644 src/canbus_logger_interface.h delete mode 100644 src/j2534_shadow.c delete mode 100644 src/j2534_shadow.h rename src/{canbus_iotbridge.c => passthru_iotbridge.c} (52%) rename src/{canbus_iotbridge.h => passthru_iotbridge.h} (93%) create mode 100644 src/passthru_shadow.c create mode 100644 src/passthru_shadow.h diff --git a/Makefile.am b/Makefile.am index f0eaf2a..85c14cd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,12 +3,12 @@ ACLOCAL_AMFLAGS = -I m4 APP_DIR = src APP_INCLUDE_DIRS = -I$(top_srcdir)/include -I$(APP_DIR) -ECUTOOLS_SRC_FILES = src/canbus.c src/awsiot_client.c src/canbus_iotbridge.c src/apigateway.c +ECUTOOLS_SRC_FILES = src/canbus.c src/canbus_logger.c src/canbus_filelogger.c src/canbus_log.c src/apigateway.c src/passthru_shadow.c src/passthru_iotbridge.c ECUTOOLS_TEST_FILES = tests/check_j2534.c # AWS IoT client directory IOT_CLIENT_DIR = src/aws_iot_src -IOT_INCLUDE_DIRS = +IOT_INCLUDE_DIRS = -I $(IOT_CLIENT_DIR)/shadow IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux @@ -18,7 +18,9 @@ IOT_INCLUDE_DIRS += -I $(IOT_CLIENT_DIR)/utils PLATFORM_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/openssl PLATFORM_COMMON_DIR = $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/platform_linux/common -IOT_SRC_FILES = + +IOT_SRC_FILES = $(IOT_CLIENT_DIR)/utils/jsmn.c $(IOT_CLIENT_DIR)/utils/aws_iot_json_utils.c +IOT_SRC_FILES += $(IOT_CLIENT_DIR)/shadow/aws_iot_shadow.c $(IOT_CLIENT_DIR)/shadow/aws_iot_shadow_actions.c $(IOT_CLIENT_DIR)/shadow/aws_iot_shadow_json.c $(IOT_CLIENT_DIR)/shadow/aws_iot_shadow_records.c IOT_SRC_FILES += $(IOT_CLIENT_DIR)/protocol/mqtt/aws_iot_embedded_client_wrapper/aws_iot_mqtt_embedded_client_wrapper.c IOT_SRC_FILES += $(PLATFORM_DIR)/network_openssl_wrapper.c $(PLATFORM_DIR)/openssl_hostname_validation.c $(PLATFORM_DIR)/hostname_compare.c $(PLATFORM_DIR)/rawstr.c IOT_SRC_FILES += $(PLATFORM_COMMON_DIR)/timer.c diff --git a/src/awsiot_client.c b/src/awsiot_client.c index 72d2bac..dd70f30 100755 --- a/src/awsiot_client.c +++ b/src/awsiot_client.c @@ -60,12 +60,14 @@ void awsiot_client_connect(awsiot_client *awsiot) { if(awsiot->rc != NONE_ERROR) { sprintf(errmsg, "Error(%d) connecting to %s:%d", awsiot->rc, connectParams.pHostURL, connectParams.port); awsiot->onerror(awsiot, errmsg); + return NULL; } awsiot->rc = aws_iot_mqtt_autoreconnect_set_status(true); if(NONE_ERROR != awsiot->rc) { sprintf(errmsg, "Unable to set Auto Reconnect to true. IoT_Error_t=%d", awsiot->rc); awsiot->onerror(awsiot, errmsg); + return NULL; } awsiot->onopen(awsiot); @@ -90,6 +92,7 @@ void awsiot_client_subscribe(awsiot_client *awsiot, const char *topic) { char errmsg[255]; sprintf(errmsg, "awsiot_client_subscribe: error subscribing to topic %s. IoT_Error_t: %d", subParams.pTopic, awsiot->rc); awsiot->onerror(awsiot, errmsg); + return NULL; } } } @@ -114,6 +117,7 @@ void awsiot_client_publish(awsiot_client *awsiot, const char *topic, const char char errmsg[255]; sprintf(errmsg, "awsiot_client_publish: error publishing to topic %s. IoT_Error_t: %d", Params.pTopic, awsiot->rc); awsiot->onerror(awsiot, errmsg); + return NULL; } } diff --git a/src/canbus_filelogger.c b/src/canbus_filelogger.c new file mode 100644 index 0000000..c72476a --- /dev/null +++ b/src/canbus_filelogger.c @@ -0,0 +1,70 @@ +/** + * ecutools: IoT Automotive Tuning, Diagnostics & Analytics + * Copyright (C) 2014 Jeremy Hahn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "canbus_filelogger.h" + +void *canbus_filelogger_thread(void *ptr) { + + syslog(LOG_DEBUG, "canbus_filelogger_thread: running"); + + canbus_log_open(); + + logger *pLogger = (logger *)ptr; + + int can_frame_len = sizeof(struct can_frame); + struct can_frame frame; + memset(&frame, 0, can_frame_len); + + int data_len = can_frame_len + 25; + char data[data_len]; + memset(data, 0, data_len); + + while((pLogger->canbus->state & CANBUS_STATE_CONNECTED) && + canbus_read(pLogger->canbus, &frame) > 0) { + + memset(data, 0, data_len); + canbus_framecpy(&frame, data); + + if(frame.can_id & CAN_ERR_FLAG) { + syslog(LOG_ERR, "canbus_filelogger_thread: CAN ERROR: %s", data); + continue; + } + + canbus_log_write(data); + } + + canbus_log_close(); + syslog(LOG_DEBUG, "canbus_filelogger_thread: stopping"); + return NULL; +} + +unsigned int canbus_filelogger_run(logger *logger) { + canbus_connect(logger->canbus); + if(!canbus_isconnected(logger->canbus)) { + syslog(LOG_CRIT, "canbus_filelogger_run: unable to connect to CAN"); + return 1; + } + pthread_create(&logger->canbus_thread, NULL, canbus_filelogger_thread, (void *)logger); + pthread_join(logger->canbus_thread, NULL); + syslog(LOG_DEBUG, "canbus_filelogger_run: logger closed"); + return 0; +} + +unsigned int canbus_filelogger_cancel(logger *logger) { + return pthread_cancel(logger->canbus_thread); +} \ No newline at end of file diff --git a/src/canbus_filelogger.h b/src/canbus_filelogger.h new file mode 100644 index 0000000..54de124 --- /dev/null +++ b/src/canbus_filelogger.h @@ -0,0 +1,27 @@ +/** + * ecutools: IoT Automotive Tuning, Diagnostics & Analytics + * Copyright (C) 2014 Jeremy Hahn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CANBUSFILELOGGER_H +#define CANBUSFILELOGGER_H + +#include "canbus_logger_interface.h" + +unsigned int canbus_filelogger_run(logger *logger); +unsigned int canbus_filelogger_cancel(logger *logger); + + #endif \ No newline at end of file diff --git a/src/canbus_log.c b/src/canbus_log.c new file mode 100644 index 0000000..6200ca0 --- /dev/null +++ b/src/canbus_log.c @@ -0,0 +1,48 @@ +/** + * ecutools: IoT Automotive Tuning, Diagnostics & Analytics + * Copyright (C) 2014 Jeremy Hahn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "canbus_log.h" + +//FILE *canbus_log; + +char* canbus_log_datestamp() { + char buf[1000]; + time_t now = time(0); + struct tm tm = *gmtime(&now); + strftime(buf, sizeof buf, "%a, %d %b %Y %H:%M:%S %Z", &tm); + return buf; +} + +void canbus_log_open() { + char filename[1050]; + snprintf(filename, 1000, canbus_log_datestamp()); + strcat(filename, ".log"); + canbus_log = fopen(filename, "w"); + if(canbus_log == NULL) { + syslog(LOG_ERR, "canbus_log_open: Unable to open log file: %s", filename); + return; + } +} + +int canbus_log_write(char *data) { + return fprintf(canbus_log, data); +} + +void canbus_log_close() { + fclose(canbus_log); +} diff --git a/src/canbus_log.h b/src/canbus_log.h new file mode 100644 index 0000000..c8f8106 --- /dev/null +++ b/src/canbus_log.h @@ -0,0 +1,32 @@ +/** + * ecutools: IoT Automotive Tuning, Diagnostics & Analytics + * Copyright (C) 2014 Jeremy Hahn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CANBUSLOG_H +#define CANBUSLOG_H + +#include +#include +#include + +FILE *canbus_log; + +void canbus_log_open(); +int canbus_log_write(char *data); +void canbus_log_close(); + + #endif \ No newline at end of file diff --git a/src/canbus_logger.c b/src/canbus_logger.c new file mode 100644 index 0000000..6f4b8a6 --- /dev/null +++ b/src/canbus_logger.c @@ -0,0 +1,27 @@ +/** + * ecutools: IoT Automotive Tuning, Diagnostics & Analytics + * Copyright (C) 2014 Jeremy Hahn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + #include "canbus_logger.h" + +unsigned int canbus_logger_run(logger *logger) { + canbus_filelogger_run(logger); +} + +unsigned int canbus_logger_cancel(logger *logger) { + canbus_filelogger_run(logger); +} \ No newline at end of file diff --git a/src/canbus_logger.h b/src/canbus_logger.h new file mode 100644 index 0000000..9bb7b17 --- /dev/null +++ b/src/canbus_logger.h @@ -0,0 +1,27 @@ +/** + * ecutools: IoT Automotive Tuning, Diagnostics & Analytics + * Copyright (C) 2014 Jeremy Hahn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CANBUSLOGGER_H +#define CANBUSLOGGER_H + +#include "canbus_logger_interface.h" + +unsigned int canbus_logger_run(logger *logger); +unsigned int canbus_logger_cancel(logger *logger); + +#endif \ No newline at end of file diff --git a/src/canbus_logger_interface.h b/src/canbus_logger_interface.h new file mode 100644 index 0000000..3bede1e --- /dev/null +++ b/src/canbus_logger_interface.h @@ -0,0 +1,33 @@ +/** + * ecutools: IoT Automotive Tuning, Diagnostics & Analytics + * Copyright (C) 2014 Jeremy Hahn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CANBUSLOGGERINTERFACE_H +#define CANBUSLOGGERINTERFACE_H + +#include +#include +#include "canbus.h" + +typedef struct _logger { + uint8_t canbus_flags; + pthread_t canbus_thread; + struct canbus_filter *filters[10]; + canbus_client *canbus; +} logger; + +#endif diff --git a/src/ecutuned.c b/src/ecutuned.c index 689123c..1a4db72 100755 --- a/src/ecutuned.c +++ b/src/ecutuned.c @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -#include "canbus_iotbridge.h" #include #include #include #include #include +#include "passthru_iotbridge.h" int main_exit(int exit_status) { syslog(LOG_DEBUG, "exiting ecutune"); diff --git a/src/j2534.c b/src/j2534.c index 2625dc7..32f8b87 100755 --- a/src/j2534.c +++ b/src/j2534.c @@ -24,6 +24,7 @@ static int j2534_current_api_call = 0; long j2534_device_count = 0; SDEVICE j2534_device_list[25] = {0}; +SDEVICE *j2534_device_selected; //DeviceMap device_map[]; @@ -127,11 +128,18 @@ long PassThruScanForDevices(unsigned long *pDeviceCount) { } strcpy(j2534_device_list[i].DeviceName, sThingName); + j2534_device_list[i].DeviceAvailable = DEVICE_AVAILABLE; j2534_device_list[i].DeviceDLLFWStatus = DEVICE_DLL_FW_COMPATIBLE; j2534_device_list[i].DeviceConnectMedia = DEVICE_CONN_WIRELESS; j2534_device_list[i].DeviceConnectSpeed = 100000; j2534_device_list[i].DeviceSignalQuality = 100; j2534_device_list[i].DeviceSignalStrength = 100; + + // TODO: J2534-1 doesnt seem to define how the user application gets a handle to the + // first SDEVICE in the static list generated by PassThruScanForDevices. + if(i == 0) { + j2534_device_selected = &j2534_device_list[i]; + } } *pDeviceCount = j2534_device_count; @@ -265,14 +273,27 @@ long PassThruGetNextDevice(SDEVICE *psDevice) { */ long PassThruOpen(const char *pName, unsigned long *pDeviceID) { + // TODO: J2534-1 doesnt seem to define how PassThruOpen knows which SDEVICE is "selected". Using the + // global variable workaround commented on in PassThruScanForDevices for now. + + int api_call = 733; + openlog("ecutools-j2534", LOG_CONS | LOG_PERROR, LOG_USER); - syslog(LOG_DEBUG, "PassThruOpen: j2534_device_count=%d, pName=%s, pDeviceId=%d", j2534_device_count, pName, pDeviceID); + syslog(LOG_DEBUG, "PassThruOpen: j2534_device_count=%d, j2534_device_selected=%s, pName=%s, pDeviceId=%d", + j2534_device_count, j2534_device_selected->DeviceName, pName, pDeviceID); + + if(pName == NULL || pDeviceID == NULL) { + return unless_concurrent_call(ERR_NULL_PARAMETER, api_call); + } + + // Return all physical & logical communication channel pins to default state + int i; for(i=0; iDeviceName) == 0) { syslog(LOG_DEBUG, "PassThruOpen: Found device %s", pName); return STATUS_NOERROR; diff --git a/src/j2534.h b/src/j2534.h index 8b96ed1..64e81c7 100755 --- a/src/j2534.h +++ b/src/j2534.h @@ -66,7 +66,6 @@ //Reserved for SAE J2534-1 0x00000027 - 0x00007FFF //Reserved for SAE 0x00008000 - 0xFFFFFFFF - // Values for #define DEVICE_STATE_UNKNOWN 0x00 #define DEVICE_AVAILABLE 0x01 diff --git a/src/j2534_shadow.c b/src/j2534_shadow.c deleted file mode 100644 index 80f79d3..0000000 --- a/src/j2534_shadow.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "j2534_shadow.h" - -awsiot_client awsiot; - -void j2534_shadow_init() { - //awsiot -} - - - -int j2534_shadow_start_listening() { - awsiot_client_connect(bridge->awsiot); - if(bridge->awsiot->rc != NONE_ERROR) { - syslog(LOG_CRIT, "iotbridge_run: unable to connect to AWS IoT service"); - return -1; - } -} \ No newline at end of file diff --git a/src/j2534_shadow.h b/src/j2534_shadow.h deleted file mode 100644 index d60ad37..0000000 --- a/src/j2534_shadow.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * ecutools: IoT Automotive Tuning, Diagnostics & Analytics - * Copyright (C) 2014 Jeremy Hahn - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef J2534SHADOW_H_ -#define J2534SHADOW_H_ - -#include -#include -#include -#include "aws_iot_src/utils/aws_iot_error.h" -#include "aws_iot_src/utils/aws_iot_log.h" -#include "aws_iot_src/utils/aws_iot_version.h" -#include "aws_iot_src/protocol/mqtt/aws_iot_mqtt_interface.h" -#include "aws_iot_config.h" - -typedef struct _j2534_shadow { - MQTTSubscribeParams *subscribeParams; - MQTTPublishParams *publishParams; - IoT_Error_t rc; - pthread_t update_accepted_thread; - pthread_t update - pthread_t canbus_subscribe_thread; - pthread_mutex_t publish_lock; - pthread_mutex_t subscribe_lock; - void (*onopen)(struct _awsiot_client *); - void (*onmessage)(MQTTCallbackParams params); - void (*ondisconnect)(void); - void (*onclose)(struct _awsiot_client *, const char *message); - void (*onerror)(struct _awsiot_client *, const char *message); -} j2534_shadow; - - -void j2534_shadow_init(); - -void j2534_shadow_update(j2534_shadow *shadow); -void j2534_shadow_update_accepted(j2534_shadow *shadow); -void j2534_shadow_update_rejected(j2534_shadow *shadow); -void j2534_shadow_update_delta(j2534_shadow *shadow); - -void j2534_shadow_get(j2534_shadow *shadow); -void j2534_shadow_get_accepted(j2534_shadow *shadow); -void j2534_shadow_get_rejected(j2534_shadow *shadow); - -void j2534_shadow_delete(j2534_shadow *shadow); - -#endif \ No newline at end of file diff --git a/src/canbus_iotbridge.c b/src/passthru_iotbridge.c similarity index 52% rename from src/canbus_iotbridge.c rename to src/passthru_iotbridge.c index 51717a0..89a9d68 100755 --- a/src/canbus_iotbridge.c +++ b/src/passthru_iotbridge.c @@ -16,14 +16,8 @@ * along with this program. If not, see . */ -#include "canbus_iotbridge.h" - -const char *IOTBRIDGE_CANBUS_TOPIC = "ecutools/canbus"; - -void iotbridge_awsiot_onopen(awsiot_client *awsiot) { - syslog(LOG_DEBUG, "iotbridge_awsiot_onopen"); -} - +#include "passthru_iotbridge.h" +/* int iotbridge_awsiot_onmessage(MQTTCallbackParams params) { uint32_t payload_len = params.MessageParams.PayloadLen; @@ -81,7 +75,7 @@ int iotbridge_awsiot_onmessage(MQTTCallbackParams params) { if(strstr(payload, "#") == NULL) { syslog(LOG_ERR, "iotbridge_awsiot_onmessage: dropping invalid CAN payload: %s", payload); - return 0; + return 0; } char *can_id = strsep(&payload, "#"); @@ -98,13 +92,12 @@ int iotbridge_awsiot_onmessage(MQTTCallbackParams params) { can_message += 2 * sizeof(char); } - /* - int i; - for(i=0; ifilters); i++) { - if(bridge->filters[i] != NULL) { - iotbridge_process_filter(bridge, frame); - } - }*/ + //int i; + //for(i=0; ifilters); i++) { + //if(bridge->filters[i] != NULL) { + //iotbridge_process_filter(bridge, frame); + //} + //} if(canbus_write(bridge->canbus, frame) == -1) { syslog(LOG_ERR, "iotbridge_awsiot_onmessage: unable to write frame to CAN bus. error: %s", strerror(errno)); @@ -113,122 +106,83 @@ int iotbridge_awsiot_onmessage(MQTTCallbackParams params) { free(frame); return 0; } +}*/ +void iotbridge_shadow_onopen(passthru_shadow *shadow) { + syslog(LOG_DEBUG, "iotbridge_shadow_onopen"); } -void iotbridge_awsiot_onclose(awsiot_client *awsiot) { - syslog(LOG_DEBUG, "iotbridge_awsiot_onclose: connection closed"); +void iotbridge_shadow_onerror(passthru_shadow *shadow, const char *message) { + syslog(LOG_DEBUG, "iotbridge_shadow_onerror: message=%s", message); } -void iotbridge_awsiot_ondisconnect(void) { - syslog(LOG_DEBUG, "iotbridge_awsiot_ondisconnect: MQTT Disconnect"); - if(aws_iot_is_autoreconnect_enabled()){ - syslog(LOG_DEBUG, "Auto Reconnect is enabled, Reconnecting attempt will start now"); - } - else { - syslog(LOG_DEBUG, "Auto Reconnect not enabled. Starting manual reconnect..."); - IoT_Error_t rc = aws_iot_mqtt_attempt_reconnect(); - if(RECONNECT_SUCCESSFUL == rc){ - syslog(LOG_DEBUG, "Manual reconnect successful"); - } - else { - syslog(LOG_ERR, "Manual reconnect failed. IoT_Error_t: %d", rc); - } - } +void iotbridge_shadow_onget(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t) { + syslog(LOG_DEBUG, "iotbridge_shadow_onget: message=%s", pJsonValueBuffer); } -void iotbridge_awsiot_onerror(IoT_Error_t *awsiot, const char *message) { - syslog(LOG_DEBUG, "iotbridge_awsiot_onerror: message=%s", message); +void iotbridge_shadow_ondelta(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t) { + syslog(LOG_DEBUG, "iotbridge_shadow_ondelta pJsonValueBuffer=%.*s", valueLength, pJsonValueBuffer); + if(passthru_shadow_build_report_json(DELTA_REPORT, SHADOW_MAX_SIZE_OF_RX_BUFFER, pJsonValueBuffer, valueLength)) { + messageArrivedOnDelta = true; + } } -void *iotbridge_awsiot_canbus_subscribe_thread(void *ptr) { - - syslog(LOG_DEBUG, "iotbridge_awsiot_subscribe_thread: started"); - iotbridge *bridge = (iotbridge *)ptr; - awsiot_client_subscribe(bridge->awsiot, IOTBRIDGE_CANBUS_TOPIC); +void iotbridge_shadow_onupdate(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status, + const char *pReceivedJsonDocument, void *pContextData) { - while(1) { - bridge->awsiot->rc = aws_iot_mqtt_yield(100); - if(NETWORK_ATTEMPTING_RECONNECT == bridge->awsiot->rc) { - syslog(LOG_DEBUG, "Attempting to reconnect to AWS IoT service"); - sleep(1); - continue; - } - sleep(1); + if (status == SHADOW_ACK_TIMEOUT) { + syslog(LOG_DEBUG, "Update Timeout--"); + } + else if(status == SHADOW_ACK_REJECTED) { + syslog(LOG_DEBUG, "Update Rejected"); + } + else if(status == SHADOW_ACK_ACCEPTED) { + syslog(LOG_DEBUG, "Update Accepted !!"); } - - syslog(LOG_DEBUG, "iotbridge_awsiot_canbus_subscribe_thread: stopping"); - return NULL; -} - -void *iotbridge_awsiot_canbus_publish_thread(void *ptr) { - syslog(LOG_DEBUG, "iotbridge_awsiot_publish_thread: started"); - iotbridge_publish_thread_args *args = (iotbridge_publish_thread_args *)ptr; - awsiot_client_publish(args->awsiot, IOTBRIDGE_CANBUS_TOPIC, args->payload); - syslog(LOG_DEBUG, "iotbridge_awsiot_canbus_publish_thread: stopping"); - free(ptr); - return NULL; } -void *iotbridge_canbus_logger_thread(void *ptr) { - - syslog(LOG_DEBUG, "iotbridge_canbus_logger_thread: running"); +void *iotbridge_shadow_yield_thread(void *ptr) { + syslog(LOG_DEBUG, "iotbridge_shadow_yield_thread: started"); iotbridge *bridge = (iotbridge *)ptr; - int can_frame_len = sizeof(struct can_frame); - struct can_frame frame; - memset(&frame, 0, can_frame_len); - - int data_len = can_frame_len + 25; - char data[data_len]; - memset(data, 0, data_len); - - while(!awsiot_client_isconnected()) { - syslog(LOG_DEBUG, "iotbridge_canbus_logger_thread: waiting for connection to AWS IoT service"); - sleep(1); - } - - while(awsiot_client_isconnected() && - (bridge->canbus->state & CANBUS_STATE_CONNECTED) && - canbus_read(bridge->canbus, &frame) > 0) { - - memset(data, 0, data_len); - canbus_framecpy(&frame, data); - - if(frame.can_id & CAN_ERR_FLAG) { - syslog(LOG_ERR, "iotbridge_canbus_logger_thread: CAN ERROR: %s", data); + while(1) { + bridge->shadow->rc = aws_iot_shadow_yield(bridge->shadow->mqttClient, 1000); + if(NETWORK_ATTEMPTING_RECONNECT == bridge->shadow->rc) { + syslog(LOG_DEBUG, "Attempting to reconnect to AWS IoT shadow service"); + sleep(1); continue; } - iotbridge_publish_thread_args *args = malloc(sizeof(iotbridge_publish_thread_args)); - memset(args, 0, sizeof(iotbridge_publish_thread_args)); - args->awsiot = bridge->awsiot; - args->payload = data; - - if(pthread_create(&bridge->awsiot->publish_thread, NULL, iotbridge_awsiot_canbus_publish_thread, (void *)args) == -1) { - syslog(LOG_ERR, "cwebsocket_read_data: %s", strerror(errno)); - return -1; + if(messageArrivedOnDelta) { + syslog(LOG_DEBUG, "Sending delta message back. message=%s\n", DELTA_REPORT); + bridge->shadow->rc = aws_iot_shadow_update(bridge->shadow->mqttClient, AWS_IOT_MY_THING_NAME, DELTA_REPORT, bridge->shadow->onupdate, NULL, 2, true); + messageArrivedOnDelta = false; } + syslog(LOG_DEBUG, "iotbridge_shadow_yield_thread: waiting for delta"); + sleep(1); } - syslog(LOG_DEBUG, "iotbridge_canbus_logger_thread: stopping"); + syslog(LOG_DEBUG, "iotbridge_shadow_yield_thread: stopping"); return NULL; + } iotbridge *iotbridge_new() { iotbridge *bridge = malloc(sizeof(iotbridge)); memset(bridge, 0, sizeof(iotbridge)); + bridge->canbus = malloc(sizeof(canbus_client)); memset(bridge->canbus, 0, sizeof(canbus_client)); - bridge->awsiot = malloc(sizeof(awsiot_client)); - memset(bridge->awsiot, 0, sizeof(awsiot_client)); - bridge->awsiot->onopen = &iotbridge_awsiot_onopen; - bridge->awsiot->onmessage = &iotbridge_awsiot_onmessage; - bridge->awsiot->ondisconnect = &iotbridge_awsiot_ondisconnect; - bridge->awsiot->onclose = &iotbridge_awsiot_onclose; - bridge->awsiot->onerror = &iotbridge_awsiot_onerror; + + bridge->shadow = malloc(sizeof(passthru_shadow)); + memset(bridge->shadow, 0, sizeof(passthru_shadow)); + bridge->shadow->onerror = &iotbridge_shadow_onerror; + bridge->shadow->onopen = &iotbridge_shadow_onopen; + bridge->shadow->ondelta = &iotbridge_shadow_ondelta; + bridge->shadow->onupdate = &iotbridge_shadow_onupdate; + return bridge; } @@ -236,15 +190,15 @@ int iotbridge_run(iotbridge *bridge) { canbus_connect(bridge->canbus); if(!canbus_isconnected(bridge->canbus)) { syslog(LOG_CRIT, "iotbridge_run: unable to connect to CAN"); - return -1; + return 1; } - awsiot_client_connect(bridge->awsiot); - if(bridge->awsiot->rc != NONE_ERROR) { - syslog(LOG_CRIT, "iotbridge_run: unable to connect to AWS IoT service"); - return -1; + passthru_shadow_connect(bridge->shadow); + if(bridge->shadow->rc != NONE_ERROR) { + syslog(LOG_CRIT, "iotbridge_run: unable to connect to AWS IoT shadow service"); + return 3; } - pthread_create(&bridge->awsiot->subscribe_thread, NULL, iotbridge_awsiot_canbus_subscribe_thread, (void *)bridge); - pthread_join(bridge->awsiot->subscribe_thread, NULL); + pthread_create(&bridge->shadow->yield_thread, NULL, iotbridge_shadow_yield_thread, (void *)bridge); + pthread_join(bridge->shadow->yield_thread, NULL); syslog(LOG_DEBUG, "iotbridge_run: bridge closed"); return 0; } @@ -257,12 +211,12 @@ void iotbridge_process_filter(iotbridge *bridge, struct can_frame *frame) { void iotbridge_close(iotbridge *bridge, const char *message) { syslog(LOG_DEBUG, "iotbridge_close: closing bridge"); canbus_close(bridge->canbus); - awsiot_client_close(bridge->awsiot, IOTBRIDGE_CANBUS_TOPIC, message); + passthru_shadow_disconnect(bridge->shadow); iotbridge_destroy(bridge); syslog(LOG_DEBUG, "iotbridge_close: bridge closed"); } void iotbridge_destroy(iotbridge *bridge) { - free(bridge->awsiot); + free(bridge->shadow); free(bridge->canbus); } diff --git a/src/canbus_iotbridge.h b/src/passthru_iotbridge.h similarity index 93% rename from src/canbus_iotbridge.h rename to src/passthru_iotbridge.h index e6e4b6f..bcf729f 100755 --- a/src/canbus_iotbridge.h +++ b/src/passthru_iotbridge.h @@ -23,24 +23,24 @@ #include #include #include "canbus.h" -#include "awsiot_client.h" +#include "passthru_shadow.h" typedef struct _iotbridge { struct iotbridge_filter *filters[10]; pthread_t canbus_thread; pthread_t publish_thread; - awsiot_client *awsiot; canbus_client *canbus; + passthru_shadow *shadow; uint8_t canbus_flags; } iotbridge; typedef struct { - awsiot_client *awsiot; + passthru_shadow *shadow; char *payload; } iotbridge_publish_thread_args; iotbridge *bridge; -iotbridge *wcbridge_new(); +iotbridge *iotbridge_new(); int iotbridge_run(iotbridge *iotbridge); void iotbridge_close(iotbridge *iotbridge, const char *message); void iotridge_destroy(iotbridge *iotbridge); diff --git a/src/passthru_shadow.c b/src/passthru_shadow.c new file mode 100644 index 0000000..91a04bf --- /dev/null +++ b/src/passthru_shadow.c @@ -0,0 +1,137 @@ +#include "passthru_shadow.h" + +bool messageArrivedOnDelta = false; + +void passthru_shadow_connect(passthru_shadow *shadow) { + + char errmsg[255]; + char rootCA[255]; + char clientCRT[255]; + char clientKey[255]; + char CurrentWD[255]; + char certDirectory[10] = "certs"; + char cafileName[] = AWS_IOT_ROOT_CA_FILENAME; + char clientCRTName[] = AWS_IOT_CERTIFICATE_FILENAME; + char clientKeyName[] = AWS_IOT_PRIVATE_KEY_FILENAME; + shadow->rc = NONE_ERROR; + + getcwd(CurrentWD, sizeof(CurrentWD)); + sprintf(rootCA, "%s/%s/%s", CurrentWD, certDirectory, cafileName); + sprintf(clientCRT, "%s/%s/%s", CurrentWD, certDirectory, clientCRTName); + sprintf(clientKey, "%s/%s/%s", CurrentWD, certDirectory, clientKeyName); + + syslog(LOG_DEBUG, "rootCA %s", rootCA); + syslog(LOG_DEBUG, "clientCRT %s", clientCRT); + syslog(LOG_DEBUG, "clientKey %s", clientKey); + + MQTTClient_t mqttClient; + aws_iot_mqtt_init(&mqttClient); + shadow->mqttClient = &mqttClient; + + ShadowParameters_t sp = ShadowParametersDefault; + sp.pMyThingName = AWS_IOT_MY_THING_NAME; + sp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID; + sp.pHost = AWS_IOT_MQTT_HOST; + sp.port = AWS_IOT_MQTT_PORT; + sp.pClientCRT = clientCRT; + sp.pClientKey = clientKey; + sp.pRootCA = rootCA; + + shadow->rc = aws_iot_shadow_init(shadow->mqttClient); + if(shadow->rc != NONE_ERROR) { + sprintf(errmsg, "aws_iot_shadow_init error rc=%d", shadow->rc); + shadow->onerror(shadow, errmsg); + return; + } + + shadow->rc = aws_iot_shadow_connect(shadow->mqttClient, &sp); + if(shadow->rc != NONE_ERROR) { + sprintf(errmsg, "aws_iot_shadow_connect error rc=%d", shadow->rc); + shadow->onerror(shadow, errmsg); + return; + } +/* + shadow->rc = shadow->mqttClient->setAutoReconnectStatus(true); + if(shadow->rc != NONE_ERROR){ + sprintf(errmsg, "setAutoReconnectStatus error rc=%d", shadow->rc); + shadow->onerror(shadow, errmsg); + return; + } +*/ + jsonStruct_t deltaObject; + deltaObject.pData = DELTA_REPORT; + deltaObject.pKey = "state"; + deltaObject.type = SHADOW_JSON_OBJECT; + deltaObject.cb = shadow->ondelta; + + shadow->rc = aws_iot_shadow_register_delta(shadow->mqttClient, &deltaObject); + if(shadow->rc != NONE_ERROR) { + sprintf(errmsg, "aws_iot_shadow_register_delta error rc=%d", shadow->rc); + shadow->onerror(shadow, errmsg); + return; + } + + shadow->onopen(shadow); +} + +void passthru_shadow_report_delta(passthru_shadow *shadow) { + syslog(LOG_DEBUG, "Sending delta report: %s", DELTA_REPORT); + shadow->rc = aws_iot_shadow_update(shadow->mqttClient, AWS_IOT_MY_THING_NAME, DELTA_REPORT, shadow->onupdate, NULL, 2, true); + if(shadow->rc != NONE_ERROR) { + char errmsg[255]; + sprintf(errmsg, "aws_iot_shadow_update error rc=%d", shadow->rc); + shadow->onerror(shadow, errmsg); + } +} + +void passthru_shadow_get(passthru_shadow *shadow) { + syslog(LOG_DEBUG, "passthru_shadow_get: %s", DELTA_REPORT); + shadow->rc = aws_iot_shadow_get(shadow->mqttClient, AWS_IOT_MY_THING_NAME, shadow->onget, NULL, 2, true); + if(shadow->rc != NONE_ERROR) { + char errmsg[255]; + sprintf(errmsg, "aws_iot_shadow_get error rc=%d", shadow->rc); + shadow->onerror(shadow, errmsg); + } +} + +void passthru_shadow_update(passthru_shadow *shadow, char *message) { + syslog(LOG_DEBUG, "passthru_shadow_update: %s", DELTA_REPORT); + shadow->rc = aws_iot_shadow_update(shadow->mqttClient, AWS_IOT_MY_THING_NAME, message, shadow->onupdate, NULL, 2, true); + if(shadow->rc != NONE_ERROR) { + char errmsg[255]; + sprintf(errmsg, "aws_iot_shadow_update error rc=%d", shadow->rc); + shadow->onerror(shadow, errmsg); + } +} + +void passthru_shadow_disconnect(passthru_shadow *shadow) { + shadow->rc = aws_iot_shadow_disconnect(shadow->mqttClient); + if(shadow->rc != NONE_ERROR) { + char errmsg[255]; + sprintf(errmsg, "aws_iot_shadow_disconnect error rc=%d", shadow->rc); + shadow->onerror(shadow, errmsg); + } +} + +bool passthru_shadow_build_report_json(char *pJsonDocument, size_t maxSizeOfJsonDocument, const char *pReceivedDeltaData, uint32_t lengthDelta) { + + int32_t ret; + + if (pJsonDocument == NULL) { + return false; + } + + char tempClientTokenBuffer[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE]; + + if(aws_iot_fill_with_client_token(tempClientTokenBuffer, MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE) != NONE_ERROR){ + return false; + } + + ret = snprintf(pJsonDocument, maxSizeOfJsonDocument, "{\"state\":{\"reported\":%.*s}, \"clientToken\":\"%s\"}", lengthDelta, pReceivedDeltaData, tempClientTokenBuffer); + + if (ret >= maxSizeOfJsonDocument || ret < 0) { + return false; + } + + return true; +} diff --git a/src/passthru_shadow.h b/src/passthru_shadow.h new file mode 100644 index 0000000..4b75050 --- /dev/null +++ b/src/passthru_shadow.h @@ -0,0 +1,67 @@ +/** + * ecutools: IoT Automotive Tuning, Diagnostics & Analytics + * Copyright (C) 2014 Jeremy Hahn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PASSTHRUSHADOW_H_ +#define PASSTHRUSHADOW_H_ + +#include +#include +#include +#include "aws_iot_src/utils/aws_iot_log.h" +#include "aws_iot_src/utils/aws_iot_version.h" +#include "aws_iot_src/protocol/mqtt/aws_iot_mqtt_interface.h" +#include "aws_iot_src/shadow/aws_iot_shadow_interface.h" +#include "aws_iot_config.h" + +char DELTA_REPORT[SHADOW_MAX_SIZE_OF_RX_BUFFER]; +bool messageArrivedOnDelta; + +typedef struct _passthru_shadow { + char *clientId; + IoT_Error_t rc; + MQTTClient_t *mqttClient; + pthread_t yield_thread; + void (*onopen)(struct _passthru_shadow *); + void (*ondelta)(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t); + void (*onupdate)(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status, const char *pReceivedJsonDocument, void *pContextData); + void (*onget)(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t); + void (*ondisconnect)(void); + void (*onclose)(struct _passthru_shadow *, const char *message); + void (*onerror)(struct _passthru_shadow *, const char *message); +} passthru_shadow; + +void passthru_shadow_connect(passthru_shadow *shadow); +bool passthru_shadow_build_report_json(char *pJsonDocument, size_t maxSizeOfJsonDocument, const char *pReceivedDeltaData, uint32_t lengthDelta); +void passthru_shadow_report_delta(passthru_shadow *shadow); +void passthru_shadow_get(passthru_shadow *shadow); +void passthru_shadow_update(passthru_shadow *shadow, char *message); +void passthru_shadow_disconnect(passthru_shadow *shadow); + +/* +void passthru_shadow_update_accepted(passthru_shadow *shadow); +void passthru_shadow_update_rejected(passthru_shadow *shadow); +void passthru_shadow_update_delta(passthru_shadow *shadow); + +void passthru_shadow_get(passthru_shadow *shadow); +void passthru_shadow_get_accepted(passthru_shadow *shadow); +void passthru_shadow_get_rejected(passthru_shadow *shadow); + +void passthru_shadow_delete(passthru_shadow *shadow); +*/ + +#endif \ No newline at end of file diff --git a/tests/check_j2534.c b/tests/check_j2534.c index 75beabf..8f3e810 100644 --- a/tests/check_j2534.c +++ b/tests/check_j2534.c @@ -4,6 +4,7 @@ #include "j2534.h" extern SDEVICE j2534_device_list[25]; +extern SDEVICE *j2534_device_selected; START_TEST(test_j2534_PassThruScanForDevices) { @@ -16,6 +17,8 @@ START_TEST(test_j2534_PassThruScanForDevices) printf("PassThruGetLastError: %s", errmsg); } +syslog(LOG_DEBUG, "j2534_device_selected: %s", j2534_device_selected); + ck_assert_int_eq(pDeviceCount, 1); } END_TEST @@ -41,7 +44,6 @@ START_TEST(test_j2534_PassThruOpen) } ck_assert_int_eq(pDeviceId, 1); - syslog(LOG_DEBUG, "device name: %s", j2534_device_list[0].DeviceName); } END_TEST