diff --git a/tutorials/IoT_Education_Kits/Industry_4.0_Kit/RAK12014_RAK12029_RAK13001_LoRaWAN Code/RAK12014_RAK12029_RAK13001_LoRaWAN Code.ino b/tutorials/IoT_Education_Kits/Industry_4.0_Kit/RAK12014_RAK12029_RAK13001_LoRaWAN Code/RAK12014_RAK12029_RAK13001_LoRaWAN Code.ino new file mode 100644 index 0000000..4f70e20 --- /dev/null +++ b/tutorials/IoT_Education_Kits/Industry_4.0_Kit/RAK12014_RAK12029_RAK13001_LoRaWAN Code/RAK12014_RAK12029_RAK13001_LoRaWAN Code.ino @@ -0,0 +1,320 @@ +#include +#include //http://librarymanager/All#SX126x +#include +#include + +// For RAK12014 module +#include // Click to install library: http://librarymanager/All#stm32duino_vl53l0x +VL53L0X sensor_vl53l0x(&Wire, WB_IO2); + +uint32_t distance; +int status; + +// For RAK13001 module +#define RELAY_PIN WB_IO4 +int object; + +// For RAK12029 module +#include "RAK12029_LDC1614.h" + +#define INDUCTANCE 13.000 +#define CAPATANCE 100.0 +#define GETCHANNEL LDC1614_CHANNEL_0 // LDC1614_CHANNEL_(0~3); selecting the coil channel from 0 - 3 +RAK12029_LDC1614_Inductive ldc; + +u16 value = 0; +u32 ChannelData = 0; + +#ifdef RAK4630 +#define BOARD "RAK4631 " +#define RAK4631_BOARD true +#else +#define RAK4631_BOARD false +#endif + +bool doOTAA = true; // OTAA is used by default. +#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */ +#define SCHED_QUEUE_SIZE 60 /**< Maximum number of events in the scheduler queue. */ +#define LORAWAN_DATERATE DR_0 /*LoRaMac datarates definition, from DR_0 to DR_5*/ +#define LORAWAN_TX_POWER TX_POWER_5 /*LoRaMac tx power definition, from TX_POWER_0 to TX_POWER_15*/ +#define JOINREQ_NBTRIALS 3 /**< Number of trials for the join request. */ +DeviceClass_t g_CurrentClass = CLASS_A; /* class definition*/ +LoRaMacRegion_t g_CurrentRegion = LORAMAC_REGION_US915; /* Region:EU868*/ +lmh_confirm g_CurrentConfirm = LMH_CONFIRMED_MSG; /* confirm/unconfirm packet definition*/ +uint8_t gAppPort = LORAWAN_APP_PORT; /* data port*/ + +/**@brief Structure containing LoRaWan parameters, needed for lmh_init() +*/ +static lmh_param_t g_lora_param_init = { LORAWAN_ADR_ON, LORAWAN_DATERATE, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_TX_POWER, LORAWAN_DUTYCYCLE_OFF }; + +// Forward declaration +static void lorawan_has_joined_handler(void); +static void lorawan_join_failed_handler(void); +static void lorawan_rx_handler(lmh_app_data_t *app_data); +static void lorawan_confirm_class_handler(DeviceClass_t Class); +static void send_lora_frame(void); + +/**@brief Structure containing LoRaWan callback functions, needed for lmh_init() +*/ +static lmh_callback_t g_lora_callbacks = { BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed, + lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler }; +//OTAA keys !!!! KEYS ARE MSB !!!! +uint8_t nodeDeviceEUI[8] = { 0xAC, 0x1F, 0x09, 0xFF, 0xFE, 0x06, 0xD3, 0xE9 }; +uint8_t nodeAppEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +uint8_t nodeAppKey[16] = { 0xC0, 0x81, 0xBB, 0x65, 0x54, 0xCF, 0xF7, 0x65, 0x87, 0x70, 0xFD, 0x31, 0x7F, 0x01, 0x87, 0x51 }; + +// ABP keys +uint32_t nodeDevAddr = 0x260116F8; +uint8_t nodeNwsKey[16] = { 0x7E, 0xAC, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23 }; +uint8_t nodeAppsKey[16] = { 0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C }; + +// Private definition +#define LORAWAN_APP_DATA_BUFF_SIZE 64 /**< buffer size of the data to be transmitted. */ +static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE]; //< Lora user application data buffer. +static lmh_app_data_t m_lora_app_data = { m_lora_app_data_buffer, 0, 0, 0, 0 }; //< Lora user application data structure. + +static uint32_t count = 0; +static uint32_t count_fail = 0; + +void setup() { + // Sensor Power Switch + pinMode(WB_IO2, OUTPUT); + digitalWrite(WB_IO2, HIGH); + + // Control Chip Switch + pinMode(WB_IO5, OUTPUT); + digitalWrite(WB_IO5, LOW); + + // Control Relay Module + pinMode(RELAY_PIN,OUTPUT); + digitalWrite(RELAY_PIN, LOW); // relay module initially LOW + + pinMode(LED_GREEN, OUTPUT); // Output LED + pinMode(LED_BLUE, OUTPUT); // Output LED + + // Initialize LoRa chip. + lora_rak4630_init(); + + // Initialize Serial for debug output + time_t timeout = millis(); + Serial.begin(115200); + while (!Serial) { + if ((millis() - timeout) < 5000) { + delay(100); + } else { + break; + } + } + Serial.println("====================================="); + Serial.println("Welcome to RAK4630 LoRaWan!!!"); + if (doOTAA) { + Serial.println("Type: OTAA"); + } else { + Serial.println("Type: ABP"); + } + + switch (g_CurrentRegion) { + case LORAMAC_REGION_AS923: + Serial.println("Region: AS923"); + break; + case LORAMAC_REGION_AU915: + Serial.println("Region: AU915"); + break; + case LORAMAC_REGION_CN470: + Serial.println("Region: CN470"); + break; + case LORAMAC_REGION_EU433: + Serial.println("Region: EU433"); + break; + case LORAMAC_REGION_IN865: + Serial.println("Region: IN865"); + break; + case LORAMAC_REGION_EU868: + Serial.println("Region: EU868"); + break; + case LORAMAC_REGION_KR920: + Serial.println("Region: KR920"); + break; + case LORAMAC_REGION_US915: + Serial.println("Region: US915"); + break; + } + Serial.println("====================================="); + + // Setup the EUIs and Keys + if (doOTAA) { + lmh_setDevEui(nodeDeviceEUI); + lmh_setAppEui(nodeAppEUI); + lmh_setAppKey(nodeAppKey); + } else { + lmh_setNwkSKey(nodeNwsKey); + lmh_setAppSKey(nodeAppsKey); + lmh_setDevAddr(nodeDevAddr); + } + + uint32_t err_code; + // Initialize LoRaWan + err_code = lmh_init(&g_lora_callbacks, g_lora_param_init, doOTAA, g_CurrentClass, g_CurrentRegion); + if (err_code != 0) { + Serial.printf("lmh_init failed - %d\n", err_code); + return; + } + + // Start Join procedure + lmh_join(); + + Serial.println("==========================================="); + Serial.println("RAK12014 + RAK12029 + RAK13001 LoRaWAN Code"); + Serial.println("==========================================="); + + Wire.begin(); + + // Configure VL53L0X component. + sensor_vl53l0x.begin(); + + // Switch off VL53L0X component. + sensor_vl53l0x.VL53L0X_Off(); + + // Initialize VL53L0X component. + status = sensor_vl53l0x.InitSensor(0x52); + if (status) { + Serial.println("Init sensor_vl53l0x failed..."); + } + + // From RAK12029 + ldc.LDC1614_init(); + /*single channel use case configuration.*/ + if (ldc.LDC1614_single_channel_config(GETCHANNEL, INDUCTANCE, CAPATANCE)) { + Serial.println("can't detect sensor!"); + while (1) delay(100); + } +} + +void loop() { + // Put your application tasks here, like reading of sensors, + // Controlling actuators and/or other functions. + + // Read data from RAK12014 + status = sensor_vl53l0x.GetDistance(&distance); + + // Read data from RAK12029 + ldc.IIC_read_16bit(LDC1614_READ_DEVICE_ID, &value); + if (value == 0x3055) { + //u32 ChannelData = 0; + /*Get channel 0 result and parse it.*/ + delay(100); + if (ldc.LDC1614_get_channel_result(GETCHANNEL, &ChannelData) == 0) { + /*sensor result value.you can make a lot of application according to its changes.*/ + if (0 != ChannelData) { + digitalWrite(LED_BLUE, HIGH); // Indicator Blue LED + digitalWrite(LED_GREEN, HIGH); // Indicator Green LED + } + delay(200); + digitalWrite(LED_BLUE, LOW); // Indicator Blue LED + digitalWrite(LED_GREEN, LOW); // Indicator Green LED + } + } + + if (ChannelData >= 49900000) // metallic material sensed nearby via inductive sensor; you can adjust this value to calibrate operation + { + digitalWrite(RELAY_PIN, HIGH); // Turns ON the relay module + object = 1; // "1" corresponds to metallic object + Serial.println("Metal Detected"); + } + + else if (ChannelData <= 49800000) // nothing metallic was sensed; default value sensed by the inductive sensor; you can adjust this value to calibrate operation + { + digitalWrite(RELAY_PIN, LOW); // Turns OFF the relay module + object = 0; // "0" corresponds to non-metallic object + Serial.println("No Metal Detected"); + } + + Serial.println("Sending frame now..."); + send_lora_frame(); + + Serial.print(distance); // From RAK12014 module + Serial.println("mm "); + Serial.println(object); // From RAK13001 module + Serial.println(ChannelData); // From RAK12029 module + + delay(5000); +} + +/**@brief LoRa function for handling HasJoined event. + */ +void lorawan_has_joined_handler(void) { + Serial.println("OTAA Mode, Network Joined!"); +} + +/**@brief LoRa function for handling OTAA join failed +*/ +static void lorawan_join_failed_handler(void) { + Serial.println("OTAA join failed!"); + Serial.println("Check your EUI's and Keys's!"); + Serial.println("Check if a Gateway is in range!"); +} +/**@brief Function for handling LoRaWan received data from Gateway + * + * @param[in] app_data Pointer to rx data + */ +void lorawan_rx_handler(lmh_app_data_t *app_data) { + Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n", + app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer); +} + +void lorawan_confirm_class_handler(DeviceClass_t Class) { + Serial.printf("switch to class %c done\n", "ABC"[Class]); + // Informs the server that switch has occurred ASAP + m_lora_app_data.buffsize = 0; + m_lora_app_data.port = gAppPort; + lmh_send(&m_lora_app_data, g_CurrentConfirm); +} + +String data = ""; + +void send_lora_frame(void) { + if (lmh_join_status_get() != LMH_SET) { + //Not joined, try again later + return; + } + + Serial.print("result: "); + uint32_t i = 0; + memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE); + m_lora_app_data.port = gAppPort; + + data = " Distance: " + String(distance) + " mm " + " Metallic: " + String(object) + " Inductive_Sense: " + String(ChannelData); + Serial.println(data); + + uint32_t distance_data = distance; // data from RAK12014 module + uint32_t channel_data = ChannelData; // data from RAK12029 module + int metallic_data = object; // data from RAK13001 module + + m_lora_app_data.buffer[i++] = 0x01; // byte[0] + + // Data from RAK12014 module + m_lora_app_data.buffer[i++] = (uint8_t)((distance_data & 0xFF000000) >> 24); // byte[1] + m_lora_app_data.buffer[i++] = (uint8_t)((distance_data & 0x00FF0000) >> 16); // byte[2] + m_lora_app_data.buffer[i++] = (uint8_t)((distance_data & 0x0000FF00) >> 8); // byte[3] + m_lora_app_data.buffer[i++] = (uint8_t)(distance_data & 0x000000FF); // byte[4] + + // Data from RAK12029 module (inductive sensor) + m_lora_app_data.buffer[i++] = (uint8_t)((channel_data & 0xFF000000) >> 24); // byte[5] + m_lora_app_data.buffer[i++] = (uint8_t)((channel_data & 0x00FF0000) >> 16); // byte[6] + m_lora_app_data.buffer[i++] = (uint8_t)((channel_data & 0x0000FF00) >> 8); // byte[7] + m_lora_app_data.buffer[i++] = (uint8_t)(channel_data & 0x000000FF); // byte[8] + + // Data from RAK13001 module (relay module status) + m_lora_app_data.buffer[i++] = metallic_data; // byte[9] + + m_lora_app_data.buffsize = i; + + lmh_error_status error = lmh_send(&m_lora_app_data, g_CurrentConfirm); + if (error == LMH_SUCCESS) { + count++; + Serial.printf("lmh_send ok count %d\n", count); + } else { + count_fail++; + Serial.printf("lmh_send fail count %d\n", count_fail); + } +} \ No newline at end of file diff --git a/tutorials/IoT_Education_Kits/Industry_4.0_Kit/RAK16002_LoRaWAN_Code/RAK16002_LoRaWAN_Code.ino b/tutorials/IoT_Education_Kits/Industry_4.0_Kit/RAK16002_LoRaWAN_Code/RAK16002_LoRaWAN_Code.ino new file mode 100644 index 0000000..45e69b5 --- /dev/null +++ b/tutorials/IoT_Education_Kits/Industry_4.0_Kit/RAK16002_LoRaWAN_Code/RAK16002_LoRaWAN_Code.ino @@ -0,0 +1,279 @@ +#include +#include //http://librarymanager/All#SX126x +#include +#include + +#include "LTC2941.h" // Click here to get the library: http://librarymanager/All#GROVE-Coulomb_Counter +#define BATTERY_CAPACITY 2200 // unit:mAh. +#define CURRENT_CAPACITY 42352 // Set the current battery level to 1800 mAh. +#define Enable WB_IO2 // Sensor Power Switch + +#ifdef RAK4630 + #define BOARD "RAK4631 " + #define RAK4631_BOARD true +#else + #define RAK4631_BOARD false +#endif + +long int coulomb, mAh, percent; + +bool doOTAA = true; // OTAA is used by default. +#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */ +#define SCHED_QUEUE_SIZE 60 /**< Maximum number of events in the scheduler queue. */ +#define LORAWAN_DATERATE DR_0 /*LoRaMac datarates definition, from DR_0 to DR_5*/ +#define LORAWAN_TX_POWER TX_POWER_5 /*LoRaMac tx power definition, from TX_POWER_0 to TX_POWER_15*/ +#define JOINREQ_NBTRIALS 3 /**< Number of trials for the join request. */ +DeviceClass_t g_CurrentClass = CLASS_A; /* class definition*/ +LoRaMacRegion_t g_CurrentRegion = LORAMAC_REGION_US915; /* Region:EU868*/ +lmh_confirm g_CurrentConfirm = LMH_CONFIRMED_MSG; /* confirm/unconfirm packet definition*/ +uint8_t gAppPort = LORAWAN_APP_PORT; /* data port*/ + +/**@brief Structure containing LoRaWan parameters, needed for lmh_init() +*/ +static lmh_param_t g_lora_param_init = {LORAWAN_ADR_ON, LORAWAN_DATERATE, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_TX_POWER, LORAWAN_DUTYCYCLE_OFF}; + +// Forward declaration +static void lorawan_has_joined_handler(void); +static void lorawan_join_failed_handler(void); +static void lorawan_rx_handler(lmh_app_data_t *app_data); +static void lorawan_confirm_class_handler(DeviceClass_t Class); +static void send_lora_frame(void); + +/**@brief Structure containing LoRaWan callback functions, needed for lmh_init() +*/ +static lmh_callback_t g_lora_callbacks = {BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed, + lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler + }; +//OTAA keys !!!! KEYS ARE MSB !!!! +uint8_t nodeDeviceEUI[8] = {0xAC, 0x1F, 0x09, 0xFF, 0xFE, 0x05, 0x3E, 0x3E}; +uint8_t nodeAppEUI[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +uint8_t nodeAppKey[16] = {0x64, 0xF6, 0xCB, 0x00, 0x35, 0x2D, 0x3B, 0x99, 0x6C, 0xFB, 0x36, 0xE4, 0xCE, 0x1A, 0x08, 0x91}; + +// ABP keys +uint32_t nodeDevAddr = 0x260116F8; +uint8_t nodeNwsKey[16] = {0x7E, 0xAC, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23}; +uint8_t nodeAppsKey[16] = {0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C}; + +// Private definition +#define LORAWAN_APP_DATA_BUFF_SIZE 64 /**< buffer size of the data to be transmitted. */ +static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE]; //< Lora user application data buffer. +static lmh_app_data_t m_lora_app_data = {m_lora_app_data_buffer, 0, 0, 0, 0}; //< Lora user application data structure. + +static uint32_t count = 0; +static uint32_t count_fail = 0; + +void setup() +{ + // Sensor Power Switch + pinMode(Enable, OUTPUT); + digitalWrite(Enable, HIGH); + + pinMode(LED_GREEN, OUTPUT); // Output LED + pinMode(LED_BLUE, OUTPUT); // Output LED + + // Initialize LoRa chip. + lora_rak4630_init(); + + // Initialize Serial for debug output + time_t timeout = millis(); + Serial.begin(115200); + while (!Serial) + { + if ((millis() - timeout) < 5000) + { + delay(100); + } + else + { + break; + } + } + Serial.println("====================================="); + Serial.println("Welcome to RAK4630 LoRaWan!!!"); + if (doOTAA) + { + Serial.println("Type: OTAA"); + } + else + { + Serial.println("Type: ABP"); + } + + switch (g_CurrentRegion) + { + case LORAMAC_REGION_AS923: + Serial.println("Region: AS923"); + break; + case LORAMAC_REGION_AU915: + Serial.println("Region: AU915"); + break; + case LORAMAC_REGION_CN470: + Serial.println("Region: CN470"); + break; + case LORAMAC_REGION_EU433: + Serial.println("Region: EU433"); + break; + case LORAMAC_REGION_IN865: + Serial.println("Region: IN865"); + break; + case LORAMAC_REGION_EU868: + Serial.println("Region: EU868"); + break; + case LORAMAC_REGION_KR920: + Serial.println("Region: KR920"); + break; + case LORAMAC_REGION_US915: + Serial.println("Region: US915"); + break; + } + Serial.println("====================================="); + + // Setup the EUIs and Keys + if (doOTAA) + { + lmh_setDevEui(nodeDeviceEUI); + lmh_setAppEui(nodeAppEUI); + lmh_setAppKey(nodeAppKey); + } + else + { + lmh_setNwkSKey(nodeNwsKey); + lmh_setAppSKey(nodeAppsKey); + lmh_setDevAddr(nodeDevAddr); + } + + uint32_t err_code; + // Initialize LoRaWan + err_code = lmh_init(&g_lora_callbacks, g_lora_param_init, doOTAA, g_CurrentClass, g_CurrentRegion); + if (err_code != 0) + { + Serial.printf("lmh_init failed - %d\n", err_code); + return; + } + + // Start Join procedure + lmh_join(); + + Serial.println("========================"); + Serial.println("RAK16002 LoRaWAN example"); + Serial.println("========================"); + + Wire.begin(); + + ltc2941.initialize(); + ltc2941.setBatteryFullMAh(BATTERY_CAPACITY , false); + ltc2941.setAccumulatedCharge(CURRENT_CAPACITY); // Set the current battery level to 1800 mAh. + +} + +void loop() +{ + // Put your application tasks here, like reading of sensors, + // Controlling actuators and/or other functions. + + digitalWrite(LED_BLUE,HIGH); + digitalWrite(LED_GREEN, HIGH); + + // Measures Coulomb, Charge and Percentage + coulomb = ltc2941.getCoulombs(); + mAh = ltc2941.getmAh(); + percent = ltc2941.getPercent(); + + Serial.println("Sending frame now..."); + send_lora_frame(); + + Serial.print(coulomb); + Serial.print("C "); + Serial.print(mAh); + Serial.print("mAh "); + Serial.print(percent); + Serial.println("%"); + delay(5000); + +} + +/**@brief LoRa function for handling HasJoined event. + */ +void lorawan_has_joined_handler(void) +{ + Serial.println("OTAA Mode, Network Joined!"); +} + +/**@brief LoRa function for handling OTAA join failed +*/ +static void lorawan_join_failed_handler(void) +{ + Serial.println("OTAA join failed!"); + Serial.println("Check your EUI's and Keys's!"); + Serial.println("Check if a Gateway is in range!"); +} +/**@brief Function for handling LoRaWan received data from Gateway + * + * @param[in] app_data Pointer to rx data + */ +void lorawan_rx_handler(lmh_app_data_t *app_data) +{ + Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n", + app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer); +} + +void lorawan_confirm_class_handler(DeviceClass_t Class) +{ + Serial.printf("switch to class %c done\n", "ABC"[Class]); + // Informs the server that switch has occurred ASAP + m_lora_app_data.buffsize = 0; + m_lora_app_data.port = gAppPort; + lmh_send(&m_lora_app_data, g_CurrentConfirm); +} + +String data = ""; + +void send_lora_frame(void) +{ + if (lmh_join_status_get() != LMH_SET) + { + //Not joined, try again later + return; + } + + Serial.print("result: "); + uint32_t i = 0; + memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE); + m_lora_app_data.port = gAppPort; + + data = " Coulomb: " + String(coulomb) + " C " + " Charge: " + String(mAh) + " mAh " + " Percentage: " + String(percent) + " % "; + Serial.println(data); + + uint32_t coulomb_data = coulomb; + uint32_t mAh_data = mAh; + uint16_t percent_data = percent; + + m_lora_app_data.buffer[i++] = 0x01; + + m_lora_app_data.buffer[i++] = (uint8_t)((coulomb_data & 0xFF000000) >> 24); + m_lora_app_data.buffer[i++] = (uint8_t)((coulomb_data & 0x00FF0000) >> 16); + m_lora_app_data.buffer[i++] = (uint8_t)((coulomb_data & 0x0000FF00) >> 8); + m_lora_app_data.buffer[i++] = (uint8_t)(coulomb_data & 0x000000FF); + + m_lora_app_data.buffer[i++] = (uint8_t)((mAh_data & 0xFF000000) >> 24); + m_lora_app_data.buffer[i++] = (uint8_t)((mAh_data & 0x00FF0000) >> 16); + m_lora_app_data.buffer[i++] = (uint8_t)((mAh_data & 0x0000FF00) >> 8); + m_lora_app_data.buffer[i++] = (uint8_t)(mAh_data & 0x000000FF); + + m_lora_app_data.buffer[i++] = (uint8_t)((percent_data) >> 8); + m_lora_app_data.buffer[i++] = (uint8_t)(percent_data); + + m_lora_app_data.buffsize = i; + + lmh_error_status error = lmh_send(&m_lora_app_data, g_CurrentConfirm); + if (error == LMH_SUCCESS) + { + count++; + Serial.printf("lmh_send ok count %d\n", count); + } + else + { + count_fail++; + Serial.printf("lmh_send fail count %d\n", count_fail); + } +} diff --git a/tutorials/IoT_Education_Kits/Light_and_Color_Kit/RAK12019_RAK12010_RAK14003_LoRaWAN_Code/RAK12019_RAK12010_RAK14003_LoRaWAN_Code.ino b/tutorials/IoT_Education_Kits/Light_and_Color_Kit/RAK12019_RAK12010_RAK14003_LoRaWAN_Code/RAK12019_RAK12010_RAK14003_LoRaWAN_Code.ino new file mode 100644 index 0000000..409fc38 --- /dev/null +++ b/tutorials/IoT_Education_Kits/Light_and_Color_Kit/RAK12019_RAK12010_RAK14003_LoRaWAN_Code/RAK12019_RAK12010_RAK14003_LoRaWAN_Code.ino @@ -0,0 +1,586 @@ +#include +#include //http://librarymanager/All#SX126x +#include +#include + +#include "UVlight_LTR390.h" // http://librarymanager/All#RAK12019_LTR390 +UVlight_LTR390 ltr = UVlight_LTR390(); + +#include "Light_VEML7700.h" // http://librarymanager/All#Light_veml7700 +Light_VEML7700 VMEL = Light_VEML7700(); + +uint16_t uvi; +uint32_t uvs; +uint32_t lux; +uint32_t white; +uint32_t raw_als; + +#include //http://librarymanager/All#Adafruit_MCP23017 +Adafruit_MCP23X17 mcp; + +// Added definitions for the functionality of RAK14003 +const uint8_t LED_0 = 0; // PA0 (17) of MCP23017 +const uint8_t LED_1 = 1; // PA1 (18) of MCP23017 +const uint8_t LED_2 = 2; // PA2 (19) of MCP23017 +const uint8_t LED_3 = 3; // PA3 (20) of MCP23017 +const uint8_t LED_4 = 4; // PA4 (21) of MCP23017 +const uint8_t LED_5 = 5; // PA5 (22) of MCP23017 +const uint8_t LED_6 = 6; // PA6 (23) of MCP23017 +const uint8_t LED_7 = 7; // PA7 (24) of MCP23017 +const uint8_t LED_8 = 8; // PB0 (25) of MCP23017 +const uint8_t LED_9 = 9; // PB1 (26) of MCP23017 + +#ifdef RAK4630 +#define BOARD "RAK4631 " +#define RAK4631_BOARD true +#else +#define RAK4631_BOARD false +#endif + +bool doOTAA = true; // OTAA is used by default. +#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */ +#define SCHED_QUEUE_SIZE 60 /**< Maximum number of events in the scheduler queue. */ +#define LORAWAN_DATERATE DR_0 /*LoRaMac datarates definition, from DR_0 to DR_5*/ +#define LORAWAN_TX_POWER TX_POWER_5 /*LoRaMac tx power definition, from TX_POWER_0 to TX_POWER_15*/ +#define JOINREQ_NBTRIALS 3 /**< Number of trials for the join request. */ +DeviceClass_t g_CurrentClass = CLASS_A; /* class definition*/ +LoRaMacRegion_t g_CurrentRegion = LORAMAC_REGION_US915; /* Region:EU868*/ +lmh_confirm g_CurrentConfirm = LMH_CONFIRMED_MSG; /* confirm/unconfirm packet definition*/ +uint8_t gAppPort = LORAWAN_APP_PORT; /* data port*/ + +/**@brief Structure containing LoRaWan parameters, needed for lmh_init() +*/ +static lmh_param_t g_lora_param_init = { LORAWAN_ADR_ON, LORAWAN_DATERATE, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_TX_POWER, LORAWAN_DUTYCYCLE_OFF }; + +// Forward declaration +static void lorawan_has_joined_handler(void); +static void lorawan_join_failed_handler(void); +static void lorawan_rx_handler(lmh_app_data_t *app_data); +static void lorawan_confirm_class_handler(DeviceClass_t Class); +static void send_lora_frame(void); + +/**@brief Structure containing LoRaWan callback functions, needed for lmh_init() +*/ +static lmh_callback_t g_lora_callbacks = { BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed, + lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler }; +//OTAA keys !!!! KEYS ARE MSB !!!! +uint8_t nodeDeviceEUI[8] = { 0xAC, 0x1F, 0x09, 0xFF, 0xFE, 0x06, 0xD3, 0xE9 }; +uint8_t nodeAppEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +uint8_t nodeAppKey[16] = { 0xE9, 0x0D, 0x28, 0x1D, 0x92, 0x3D, 0xE4, 0x9F, 0xD9, 0xF7, 0xE0, 0x5F, 0x39, 0x10, 0x55, 0x71 }; + +// ABP keys +uint32_t nodeDevAddr = 0x260116F8; +uint8_t nodeNwsKey[16] = { 0x7E, 0xAC, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23 }; +uint8_t nodeAppsKey[16] = { 0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C }; + +// Private definition +#define LORAWAN_APP_DATA_BUFF_SIZE 64 /**< buffer size of the data to be transmitted. */ +static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE]; //< Lora user application data buffer. +static lmh_app_data_t m_lora_app_data = { m_lora_app_data_buffer, 0, 0, 0, 0 }; //< Lora user application data structure. + +static uint32_t count = 0; +static uint32_t count_fail = 0; + +void setup() { + + // Initialize Serial for debug output + pinMode(LED_BLUE, OUTPUT); + digitalWrite(LED_BLUE, HIGH); + + // Sensor Power Switch + pinMode(WB_IO2, OUTPUT); + digitalWrite(WB_IO2, HIGH); + + // Reset RAK14003 module + pinMode(WB_IO4, OUTPUT); + digitalWrite(WB_IO4, HIGH); + delay(10); + digitalWrite(WB_IO4, LOW); + delay(10); + digitalWrite(WB_IO4, HIGH); + delay(10); + + // Initialize LoRa chip. + lora_rak4630_init(); + + // Initialize Serial for debug output + time_t timeout = millis(); + Serial.begin(115200); + while (!Serial) { + if ((millis() - timeout) < 5000) { + delay(100); + } else { + break; + } + } + Serial.println("====================================="); + Serial.println("Welcome to RAK4630 LoRaWan!!!"); + if (doOTAA) { + Serial.println("Type: OTAA"); + } else { + Serial.println("Type: ABP"); + } + + switch (g_CurrentRegion) { + case LORAMAC_REGION_AS923: + Serial.println("Region: AS923"); + break; + case LORAMAC_REGION_AU915: + Serial.println("Region: AU915"); + break; + case LORAMAC_REGION_CN470: + Serial.println("Region: CN470"); + break; + case LORAMAC_REGION_EU433: + Serial.println("Region: EU433"); + break; + case LORAMAC_REGION_IN865: + Serial.println("Region: IN865"); + break; + case LORAMAC_REGION_EU868: + Serial.println("Region: EU868"); + break; + case LORAMAC_REGION_KR920: + Serial.println("Region: KR920"); + break; + case LORAMAC_REGION_US915: + Serial.println("Region: US915"); + break; + } + Serial.println("====================================="); + + // Setup the EUIs and Keys + if (doOTAA) { + lmh_setDevEui(nodeDeviceEUI); + lmh_setAppEui(nodeAppEUI); + lmh_setAppKey(nodeAppKey); + } else { + lmh_setNwkSKey(nodeNwsKey); + lmh_setAppSKey(nodeAppsKey); + lmh_setDevAddr(nodeDevAddr); + } + + uint32_t err_code; + // Initialize LoRaWan + err_code = lmh_init(&g_lora_callbacks, g_lora_param_init, doOTAA, g_CurrentClass, g_CurrentRegion); + if (err_code != 0) { + Serial.printf("lmh_init failed - %d\n", err_code); + return; + } + + // Start Join procedure + lmh_join(); + + Serial.println("================================"); + Serial.println("RAK12019 + RAK12010 LoRaWAN Code"); + Serial.println("================================"); + + if (!VMEL.begin()) + { + Serial.println("Sensor not found"); + while (1); + } + + VMEL.setGain(VEML7700_GAIN_1); + VMEL.setIntegrationTime(VEML7700_IT_800MS); + + Serial.print(F("Gain: ")); + switch (VMEL.getGain()) + { + case VEML7700_GAIN_1: Serial.println("1"); break; + case VEML7700_GAIN_2: Serial.println("2"); break; + case VEML7700_GAIN_1_4: Serial.println("1/4"); break; + case VEML7700_GAIN_1_8: Serial.println("1/8"); break; + } + + Serial.print(F("Integration Time (ms): ")); + switch (VMEL.getIntegrationTime()) + { + case VEML7700_IT_25MS: Serial.println("25"); break; + case VEML7700_IT_50MS: Serial.println("50"); break; + case VEML7700_IT_100MS: Serial.println("100"); break; + case VEML7700_IT_200MS: Serial.println("200"); break; + case VEML7700_IT_400MS: Serial.println("400"); break; + case VEML7700_IT_800MS: Serial.println("800"); break; + } + + Serial.println("RAK12019 test"); + Wire.begin(); + if (!ltr.init()) + { + Serial.println("Couldn't find LTR sensor!"); + while (1) + delay(10); + } + Serial.println("Found LTR390 sensor!"); + + //set to LTR390_MODE_UVS,get ultraviolet light data. + ltr.setMode(LTR390_MODE_UVS); // UVS Mode + + Serial.println("In UVS mode"); + + ltr.setGain(LTR390_GAIN_3); + Serial.print("Gain : "); + switch (ltr.getGain()) + { + case LTR390_GAIN_1: + Serial.println(1); + break; + case LTR390_GAIN_3: + Serial.println(3); + break; + case LTR390_GAIN_6: + Serial.println(6); + break; + case LTR390_GAIN_9: + Serial.println(9); + break; + case LTR390_GAIN_18: + Serial.println(18); + break; + default: + Serial.println("Failed to set gain"); + break; + } + ltr.setResolution(LTR390_RESOLUTION_16BIT); + Serial.print("Integration Time (ms): "); + switch (ltr.getResolution()) + { + case LTR390_RESOLUTION_13BIT: + Serial.println(13); + break; + case LTR390_RESOLUTION_16BIT: + Serial.println(16); + break; + case LTR390_RESOLUTION_17BIT: + Serial.println(17); + break; + case LTR390_RESOLUTION_18BIT: + Serial.println(18); + break; + case LTR390_RESOLUTION_19BIT: + Serial.println(19); + break; + case LTR390_RESOLUTION_20BIT: + Serial.println(20); + break; + default: + Serial.println("Failed to set Integration Time"); + break; + } + + ltr.setThresholds(100, 1000); //Set the interrupt output threshold range for lower and upper. + + ltr.configInterrupt(true, LTR390_MODE_UVS); + + // For RAK14003 + mcp.begin_I2C(0x24); + + // Added for the functionality of RAK14003 + + Wire.begin(); // initialize I2C serial bus + + // Configuration of MCP23017 I/O ports + mcp.pinMode(LED_0, OUTPUT); // Red LED; Top most + mcp.pinMode(LED_1, OUTPUT); // Red LED + mcp.pinMode(LED_2, OUTPUT); // Orange LED + mcp.pinMode(LED_3, OUTPUT); // Orange LED + mcp.pinMode(LED_4, OUTPUT); // Orange LED + mcp.pinMode(LED_5, OUTPUT); // Green LED + mcp.pinMode(LED_6, OUTPUT); // Green LED + mcp.pinMode(LED_7, OUTPUT); // Green LED + mcp.pinMode(LED_8, OUTPUT); // Green LED + mcp.pinMode(LED_9, OUTPUT); // Green LED; Bottom + + // Initially Turn OFF all LEDs + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, HIGH); + mcp.digitalWrite(LED_2, HIGH); + mcp.digitalWrite(LED_3, HIGH); + mcp.digitalWrite(LED_4, HIGH); + mcp.digitalWrite(LED_5, HIGH); + mcp.digitalWrite(LED_6, HIGH); + mcp.digitalWrite(LED_7, HIGH); + mcp.digitalWrite(LED_8, HIGH); + mcp.digitalWrite(LED_9, HIGH); + +} + +void loop() { + // Put your application tasks here, like reading of sensors, + // Controlling actuators and/or other functions. + + // Trial # 1 + // Data from RAK12019 + if (ltr.newDataAvailable()) + { + uvi = ltr.getUVI(); + uvs = ltr.readUVS(); + } + + // Data from RAK12010 + lux = VMEL.readLux(); + white = VMEL.readWhite(); + raw_als = VMEL.readALS(); + + Serial.println("Sending frame now..."); + send_lora_frame(); + + // Showing only UV Index (uvi), UV Intensity (uvs) and Lux (lx) + + // From RAK12019 module + Serial.print("UVI: "); + Serial.println(uvi); // Uvi data from RAK12019 + Serial.print("UVS: "); + Serial.println(uvs); // Uvs data from RAK12019 + + // From RAK12010 + Serial.print("Lux: "); + Serial.print(lux); + Serial.println(" lx "); + Serial.print("White: "); + Serial.println(white); + Serial.print("Raw ALS: "); + Serial.println(raw_als); + + // Result of uvi to be displayed via RAK14003 module + if (uvi <= 0.4) + { + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, HIGH); + mcp.digitalWrite(LED_2, HIGH); + mcp.digitalWrite(LED_3, HIGH); + mcp.digitalWrite(LED_4, HIGH); + mcp.digitalWrite(LED_5, HIGH); + mcp.digitalWrite(LED_6, HIGH); + mcp.digitalWrite(LED_7, HIGH); + mcp.digitalWrite(LED_8, HIGH); + mcp.digitalWrite(LED_9, HIGH); + } + + else if (uvi > 0.5 && uvi <= 1) + { + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, HIGH); + mcp.digitalWrite(LED_2, HIGH); + mcp.digitalWrite(LED_3, HIGH); + mcp.digitalWrite(LED_4, HIGH); + mcp.digitalWrite(LED_5, HIGH); + mcp.digitalWrite(LED_6, HIGH); + mcp.digitalWrite(LED_7, HIGH); + mcp.digitalWrite(LED_8, HIGH); + mcp.digitalWrite(LED_9, LOW); + } + + else if (uvi > 1.5 && uvi <= 2) + { + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, HIGH); + mcp.digitalWrite(LED_2, HIGH); + mcp.digitalWrite(LED_3, HIGH); + mcp.digitalWrite(LED_4, HIGH); + mcp.digitalWrite(LED_5, HIGH); + mcp.digitalWrite(LED_6, HIGH); + mcp.digitalWrite(LED_7, HIGH); + mcp.digitalWrite(LED_8, LOW); + mcp.digitalWrite(LED_9, LOW); + } + + else if (uvi > 2.5 && uvi <= 3) + { + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, HIGH); + mcp.digitalWrite(LED_2, HIGH); + mcp.digitalWrite(LED_3, HIGH); + mcp.digitalWrite(LED_4, HIGH); + mcp.digitalWrite(LED_5, HIGH); + mcp.digitalWrite(LED_6, HIGH); + mcp.digitalWrite(LED_7, LOW); + mcp.digitalWrite(LED_8, LOW); + mcp.digitalWrite(LED_9, LOW); + } + + else if (uvi > 3.5 && uvi <= 4) + { + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, HIGH); + mcp.digitalWrite(LED_2, HIGH); + mcp.digitalWrite(LED_3, HIGH); + mcp.digitalWrite(LED_4, HIGH); + mcp.digitalWrite(LED_5, HIGH); + mcp.digitalWrite(LED_6, LOW); + mcp.digitalWrite(LED_7, LOW); + mcp.digitalWrite(LED_8, LOW); + mcp.digitalWrite(LED_9, LOW); + } + + else if (uvi > 4.5 && uvi <= 5) + { + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, HIGH); + mcp.digitalWrite(LED_2, HIGH); + mcp.digitalWrite(LED_3, HIGH); + mcp.digitalWrite(LED_4, HIGH); + mcp.digitalWrite(LED_5, LOW); + mcp.digitalWrite(LED_6, LOW); + mcp.digitalWrite(LED_7, LOW); + mcp.digitalWrite(LED_8, LOW); + mcp.digitalWrite(LED_9, LOW); + } + + else if (uvi > 5.5 && uvi <= 6) + { + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, HIGH); + mcp.digitalWrite(LED_2, HIGH); + mcp.digitalWrite(LED_3, HIGH); + mcp.digitalWrite(LED_4, LOW); + mcp.digitalWrite(LED_5, LOW); + mcp.digitalWrite(LED_6, LOW); + mcp.digitalWrite(LED_7, LOW); + mcp.digitalWrite(LED_8, LOW); + mcp.digitalWrite(LED_9, LOW); + } + + else if (uvi > 6.5 && uvi <= 7) + { + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, HIGH); + mcp.digitalWrite(LED_2, HIGH); + mcp.digitalWrite(LED_3, LOW); + mcp.digitalWrite(LED_4, LOW); + mcp.digitalWrite(LED_5, LOW); + mcp.digitalWrite(LED_6, LOW); + mcp.digitalWrite(LED_7, LOW); + mcp.digitalWrite(LED_8, LOW); + mcp.digitalWrite(LED_9, LOW); + } + + else if (uvi > 7.5 && uvi <= 8) + { + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, HIGH); + mcp.digitalWrite(LED_2, LOW); + mcp.digitalWrite(LED_3, LOW); + mcp.digitalWrite(LED_4, LOW); + mcp.digitalWrite(LED_5, LOW); + mcp.digitalWrite(LED_6, LOW); + mcp.digitalWrite(LED_7, LOW); + mcp.digitalWrite(LED_8, LOW); + mcp.digitalWrite(LED_9, LOW); + } + + else if (uvi > 8.5 && uvi <= 9.5) + { + mcp.digitalWrite(LED_0, HIGH); + mcp.digitalWrite(LED_1, LOW); + mcp.digitalWrite(LED_2, LOW); + mcp.digitalWrite(LED_3, LOW); + mcp.digitalWrite(LED_4, LOW); + mcp.digitalWrite(LED_5, LOW); + mcp.digitalWrite(LED_6, LOW); + mcp.digitalWrite(LED_7, LOW); + mcp.digitalWrite(LED_8, LOW); + mcp.digitalWrite(LED_9, LOW); + } + + else if (uvi >= 10) + { + mcp.digitalWrite(LED_0, LOW); + mcp.digitalWrite(LED_1, LOW); + mcp.digitalWrite(LED_2, LOW); + mcp.digitalWrite(LED_3, LOW); + mcp.digitalWrite(LED_4, LOW); + mcp.digitalWrite(LED_5, LOW); + mcp.digitalWrite(LED_6, LOW); + mcp.digitalWrite(LED_7, LOW); + mcp.digitalWrite(LED_8, LOW); + mcp.digitalWrite(LED_9, LOW); + } + + delay(10000); +} + +/**@brief LoRa function for handling HasJoined event. + */ +void lorawan_has_joined_handler(void) { + Serial.println("OTAA Mode, Network Joined!"); +} + +/**@brief LoRa function for handling OTAA join failed +*/ +static void lorawan_join_failed_handler(void) { + Serial.println("OTAA join failed!"); + Serial.println("Check your EUI's and Keys's!"); + Serial.println("Check if a Gateway is in range!"); +} +/**@brief Function for handling LoRaWan received data from Gateway + * + * @param[in] app_data Pointer to rx data + */ +void lorawan_rx_handler(lmh_app_data_t *app_data) { + Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n", + app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer); +} + +void lorawan_confirm_class_handler(DeviceClass_t Class) { + Serial.printf("switch to class %c done\n", "ABC"[Class]); + // Informs the server that switch has occurred ASAP + m_lora_app_data.buffsize = 0; + m_lora_app_data.port = gAppPort; + lmh_send(&m_lora_app_data, g_CurrentConfirm); +} + +String data = ""; + +void send_lora_frame(void) { + if (lmh_join_status_get() != LMH_SET) { + //Not joined, try again later + return; + } + + Serial.print("result: "); + uint32_t i = 0; + memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE); + m_lora_app_data.port = gAppPort; + + // Showing only UV Index (uvi), UV Intensity (uvs) and Lux (lx) + data = " Uvi Data: " + String(uvi) + " Uvs Data: " + String(uvs) + " Lux Data: " + String(lux) + " lx " ; + + Serial.println(data); + + // Showing only UV Index (uvi), UV Intensity (uvs) and Lux (lx) + uint16_t uvi_data = uvi; // Uvi data from RAK12019 + uint32_t uvs_data = uvs; // Uvs data from RAK12019 + uint32_t lux_data = lux; // Lux data from RAK12010 + + m_lora_app_data.buffer[i++] = 0x01; // byte[0] + + // Showing only UV Index (uvi), UV Intensity (uvs) and Lux (lx) + // Data from RAK12019 module + m_lora_app_data.buffer[i++] = (uint8_t)((uvi_data & 0x0000FF00) >> 8); // byte[1] + m_lora_app_data.buffer[i++] = (uint8_t)(uvi_data & 0x000000FF); // byte[2] + + // Data from RAK12019 module + m_lora_app_data.buffer[i++] = (uint8_t)((uvs_data & 0xFF000000) >> 24); // byte[3] + m_lora_app_data.buffer[i++] = (uint8_t)((uvs_data & 0x00FF0000) >> 16); // byte[4] + m_lora_app_data.buffer[i++] = (uint8_t)((uvs_data & 0x0000FF00) >> 8); // byte[5] + m_lora_app_data.buffer[i++] = (uint8_t)(uvs_data & 0x000000FF); // byte[6] + + // Data from RAK12010 module + m_lora_app_data.buffer[i++] = (uint8_t)((lux_data & 0xFF000000) >> 24); // byte[7] + m_lora_app_data.buffer[i++] = (uint8_t)((lux_data & 0x00FF0000) >> 16); // byte[8] + m_lora_app_data.buffer[i++] = (uint8_t)((lux_data & 0x0000FF00) >> 8); // byte[9] + m_lora_app_data.buffer[i++] = (uint8_t)(lux_data & 0x000000FF); // byte[10] + + m_lora_app_data.buffsize = i; + + lmh_error_status error = lmh_send(&m_lora_app_data, g_CurrentConfirm); + if (error == LMH_SUCCESS) { + count++; + Serial.printf("lmh_send ok count %d\n", count); + } else { + count_fail++; + Serial.printf("lmh_send fail count %d\n", count_fail); + } +} \ No newline at end of file diff --git a/tutorials/IoT_Education_Kits/Light_and_Color_Kit/RAK12021_RAK14001_LoRaWAN_Code/RAK12021_RAK14001_LoRaWAN_Code.ino b/tutorials/IoT_Education_Kits/Light_and_Color_Kit/RAK12021_RAK14001_LoRaWAN_Code/RAK12021_RAK14001_LoRaWAN_Code.ino new file mode 100644 index 0000000..f5a6a23 --- /dev/null +++ b/tutorials/IoT_Education_Kits/Light_and_Color_Kit/RAK12021_RAK14001_LoRaWAN_Code/RAK12021_RAK14001_LoRaWAN_Code.ino @@ -0,0 +1,327 @@ +#include +#include //http://librarymanager/All#SX126x +#include +#include //http://librarymanager/All#NCP5623 By:RAKWireless +#include "TCS3772.h" // Click here to get the library: http://librarymanager/All#TCS37725 +// It use WB_IO2 to power up and is conflicting with INT1, so better use in SlotA/SlotC/SlotD. + +NCP5623 rgb; +TCS3772 tcs3772; +TCS3772_DataScaled tcs3772_data = {0}; + +uint16_t scale_factor; + +uint16_t redColor; +uint16_t greenColor; +uint16_t blueColor; + +#ifdef RAK4630 +#define BOARD "RAK4631 " +#define RAK4631_BOARD true +#else +#define RAK4631_BOARD false +#endif + +bool doOTAA = true; // OTAA is used by default. +#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */ +#define SCHED_QUEUE_SIZE 60 /**< Maximum number of events in the scheduler queue. */ +#define LORAWAN_DATERATE DR_0 /*LoRaMac datarates definition, from DR_0 to DR_5*/ +#define LORAWAN_TX_POWER TX_POWER_5 /*LoRaMac tx power definition, from TX_POWER_0 to TX_POWER_15*/ +#define JOINREQ_NBTRIALS 3 /**< Number of trials for the join request. */ +DeviceClass_t g_CurrentClass = CLASS_A; /* class definition*/ +LoRaMacRegion_t g_CurrentRegion = LORAMAC_REGION_US915; /* Region:EU868*/ +lmh_confirm g_CurrentConfirm = LMH_CONFIRMED_MSG; /* confirm/unconfirm packet definition*/ +uint8_t gAppPort = LORAWAN_APP_PORT; /* data port*/ + +/**@brief Structure containing LoRaWan parameters, needed for lmh_init() +*/ +static lmh_param_t g_lora_param_init = { LORAWAN_ADR_ON, LORAWAN_DATERATE, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_TX_POWER, LORAWAN_DUTYCYCLE_OFF }; + +// Forward declaration +static void lorawan_has_joined_handler(void); +static void lorawan_join_failed_handler(void); +static void lorawan_rx_handler(lmh_app_data_t *app_data); +static void lorawan_confirm_class_handler(DeviceClass_t Class); +static void send_lora_frame(void); + +/**@brief Structure containing LoRaWan callback functions, needed for lmh_init() +*/ +static lmh_callback_t g_lora_callbacks = { BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed, + lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler }; +//OTAA keys !!!! KEYS ARE MSB !!!! +uint8_t nodeDeviceEUI[8] = { 0xAC, 0x1F, 0x09, 0xFF, 0xFE, 0x05, 0x3E, 0x3E }; +uint8_t nodeAppEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +uint8_t nodeAppKey[16] = { 0x96, 0xBD, 0xC5, 0x98, 0x17, 0x69, 0x8D, 0xFA, 0x1F, 0x64, 0xFE, 0x1C, 0xF9, 0x26, 0x7F, 0x8D }; + +// ABP keys +uint32_t nodeDevAddr = 0x260116F8; +uint8_t nodeNwsKey[16] = { 0x7E, 0xAC, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23 }; +uint8_t nodeAppsKey[16] = { 0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C }; + +// Private definition +#define LORAWAN_APP_DATA_BUFF_SIZE 64 /**< buffer size of the data to be transmitted. */ +static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE]; //< Lora user application data buffer. +static lmh_app_data_t m_lora_app_data = { m_lora_app_data_buffer, 0, 0, 0, 0 }; //< Lora user application data structure. + +static uint32_t count = 0; +static uint32_t count_fail = 0; + +void setup() { + + // Initialize Serial for debug output + pinMode(LED_BLUE, OUTPUT); + digitalWrite(LED_BLUE, HIGH); + + // Sensor Power Switch + pinMode(WB_IO2, OUTPUT); + digitalWrite(WB_IO2, HIGH); + + // enable RAK14001 + pinMode(WB_IO6, OUTPUT); + digitalWrite(WB_IO6, HIGH); + + // Initialize LoRa chip. + lora_rak4630_init(); + + // Initialize Serial for debug output + time_t timeout = millis(); + Serial.begin(115200); + while (!Serial) { + if ((millis() - timeout) < 5000) { + delay(100); + } else { + break; + } + } + Serial.println("====================================="); + Serial.println("Welcome to RAK4630 LoRaWan!!!"); + if (doOTAA) { + Serial.println("Type: OTAA"); + } else { + Serial.println("Type: ABP"); + } + + switch (g_CurrentRegion) { + case LORAMAC_REGION_AS923: + Serial.println("Region: AS923"); + break; + case LORAMAC_REGION_AU915: + Serial.println("Region: AU915"); + break; + case LORAMAC_REGION_CN470: + Serial.println("Region: CN470"); + break; + case LORAMAC_REGION_EU433: + Serial.println("Region: EU433"); + break; + case LORAMAC_REGION_IN865: + Serial.println("Region: IN865"); + break; + case LORAMAC_REGION_EU868: + Serial.println("Region: EU868"); + break; + case LORAMAC_REGION_KR920: + Serial.println("Region: KR920"); + break; + case LORAMAC_REGION_US915: + Serial.println("Region: US915"); + break; + } + Serial.println("====================================="); + + // Setup the EUIs and Keys + if (doOTAA) { + lmh_setDevEui(nodeDeviceEUI); + lmh_setAppEui(nodeAppEUI); + lmh_setAppKey(nodeAppKey); + } else { + lmh_setNwkSKey(nodeNwsKey); + lmh_setAppSKey(nodeAppsKey); + lmh_setDevAddr(nodeDevAddr); + } + + uint32_t err_code; + // Initialize LoRaWan + err_code = lmh_init(&g_lora_callbacks, g_lora_param_init, doOTAA, g_CurrentClass, g_CurrentRegion); + if (err_code != 0) { + Serial.printf("lmh_init failed - %d\n", err_code); + return; + } + + // Start Join procedure + lmh_join(); + + Serial.println("================================"); + Serial.println("RAK12021 + RAK14001 LoRaWAN Code"); + Serial.println("================================"); + + // If using Native I2C + Wire.begin(); + Wire.setClock(100000); + + // Serial.println("RAK14001 + RAK12021"); + + if (!rgb.begin()) + { + Serial.println("RAK14001 not found on the I2C line"); + while (1); + } + else + { + Serial.println("RAK14001 Found. Begining execution"); + } + + // set the current output level max, the range is 1 to 31 + rgb.setCurrent(25); + + if(tcs3772.begin() == true) + { + Serial.println("Found sensor."); + } + else + { + Serial.println("TCS37725 not found ... check your connections."); + while(1) + { + delay(10); + } + } + delay(1000); +} + +void loop() { + // Put your application tasks here, like reading of sensors, + // Controlling actuators and/or other functions. + + tcs3772_data = tcs3772.getMeasurement(); + + scale_factor = tcs3772.autoGain(tcs3772_data.clear); + + redColor = tcs3772_data.red; + greenColor = tcs3772_data.green; + blueColor = tcs3772_data.blue; + + rgb.setColor(0,0,0); // Initially OFF + + Serial.println("Sending frame now..."); + send_lora_frame(); + + Serial.print(" R: "); + Serial.println(redColor); + Serial.print(" G: "); + Serial.println(greenColor); + Serial.print(" B: "); + Serial.println(blueColor); + + // The values of redColor, greenColor and blueColor can be varied during the sensing calibration of RAK12021 module + + if (((redColor >= 9000) && (redColor <= 65535)) && ((greenColor >= 10000) && (greenColor <= 65535)) && ((blueColor >= 12000) && (blueColor <= 65535))) + { + rgb.setColor(255,255,255); // WHITE + } + + else if (((redColor >= 4000) && (redColor <= 18000)) && ((greenColor >= 1300) && (greenColor <= 5000)) && ((blueColor >= 950) && (blueColor <= 2000))) + { + rgb.setColor(255,255,0); // YELLOW + } + + else if (((redColor >= 600) && (redColor <= 2000)) && ((greenColor >= 1700) && (greenColor <= 10000)) && ((blueColor >= 6800) && (blueColor <= 27000))) + { + rgb.setColor(0,0,255); // BLUE + } + + else if (((redColor >= 1400) && (redColor <= 4000)) && ((greenColor >= 1300) && (greenColor <= 10000)) && ((blueColor >= 950) && (blueColor <= 2700))) + { + rgb.setColor(0,255,0); // GREEN + } + + else if (((redColor >= 3000) && (redColor <= 20000)) && ((greenColor >= 700) && (greenColor <= 2400)) && ((blueColor >= 950) && (blueColor <= 3000))) + { + rgb.setColor(255,0,0); // RED + } + + else if ((redColor < 1500) && (greenColor < 1400) && (blueColor < 900)) + { + rgb.setColor(0,0,0); // OFF + } + + delay(5000); +} + +/**@brief LoRa function for handling HasJoined event. + */ +void lorawan_has_joined_handler(void) { + Serial.println("OTAA Mode, Network Joined!"); +} + +/**@brief LoRa function for handling OTAA join failed +*/ +static void lorawan_join_failed_handler(void) { + Serial.println("OTAA join failed!"); + Serial.println("Check your EUI's and Keys's!"); + Serial.println("Check if a Gateway is in range!"); +} +/**@brief Function for handling LoRaWan received data from Gateway + * + * @param[in] app_data Pointer to rx data + */ +void lorawan_rx_handler(lmh_app_data_t *app_data) { + Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n", + app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer); +} + +void lorawan_confirm_class_handler(DeviceClass_t Class) { + Serial.printf("switch to class %c done\n", "ABC"[Class]); + // Informs the server that switch has occurred ASAP + m_lora_app_data.buffsize = 0; + m_lora_app_data.port = gAppPort; + lmh_send(&m_lora_app_data, g_CurrentConfirm); +} + +String data = ""; + +void send_lora_frame(void) { + if (lmh_join_status_get() != LMH_SET) { + //Not joined, try again later + return; + } + + Serial.print("result: "); + uint32_t i = 0; + memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE); + m_lora_app_data.port = gAppPort; + + // Showing the values of red, green and blue colors from RAK12021 + data = " Red: " + String(redColor) + " Green: " + String(greenColor) + " Blue: " + String(blueColor); + + Serial.println(data); + + uint16_t red_data = redColor; + uint16_t green_data = greenColor; + uint16_t blue_data = blueColor; + + m_lora_app_data.buffer[i++] = 0x01; // byte[0] + + // Red data + m_lora_app_data.buffer[i++] = (uint8_t)((red_data & 0x0000FF00) >> 8); // byte[1] + m_lora_app_data.buffer[i++] = (uint8_t)(red_data & 0x000000FF); // byte[2] + + // Green data + m_lora_app_data.buffer[i++] = (uint8_t)((green_data & 0x0000FF00) >> 8); // byte[3] + m_lora_app_data.buffer[i++] = (uint8_t)(green_data & 0x000000FF); // byte[4] + + // Blue data + m_lora_app_data.buffer[i++] = (uint8_t)((blue_data & 0x0000FF00) >> 8); // byte[5] + m_lora_app_data.buffer[i++] = (uint8_t)(blue_data & 0x000000FF); // byte[6] + + m_lora_app_data.buffsize = i; + + lmh_error_status error = lmh_send(&m_lora_app_data, g_CurrentConfirm); + if (error == LMH_SUCCESS) { + count++; + Serial.printf("lmh_send ok count %d\n", count); + } else { + count_fail++; + Serial.printf("lmh_send fail count %d\n", count_fail); + } +} \ No newline at end of file diff --git a/tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12006_LoRaWAN_Code.ino b/tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12006_LoRaWAN_Code/RAK12006_LoRaWAN_Code.ino similarity index 100% rename from tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12006_LoRaWAN_Code.ino rename to tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12006_LoRaWAN_Code/RAK12006_LoRaWAN_Code.ino diff --git a/tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12007_LoRaWAN_Code.ino b/tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12007_LoRaWAN_Code/RAK12007_LoRaWAN_Code.ino similarity index 100% rename from tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12007_LoRaWAN_Code.ino rename to tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12007_LoRaWAN_Code/RAK12007_LoRaWAN_Code.ino diff --git a/tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12013_LoRaWAN_Code.ino b/tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12013_LoRaWAN_Code/RAK12013_LoRaWAN_Code.ino similarity index 100% rename from tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12013_LoRaWAN_Code.ino rename to tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12013_LoRaWAN_Code/RAK12013_LoRaWAN_Code.ino diff --git a/tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12017_LoRaWAN_Code.ino b/tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12017_LoRaWAN_Code/RAK12017_LoRaWAN_Code.ino similarity index 100% rename from tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12017_LoRaWAN_Code.ino rename to tutorials/IoT_Education_Kits/Movement_Detection_Kit/RAK12017_LoRaWAN_Code/RAK12017_LoRaWAN_Code.ino diff --git a/tutorials/IoT_Education_Kits/Outdoor_Location_Kit/GPS_Tracker_Movement_Trigger_RAK12500/GPS_Tracker_Movement_Trigger_RAK12500.ino b/tutorials/IoT_Education_Kits/Outdoor_Location_Kit/GPS_Tracker_Movement_Trigger_RAK12500/GPS_Tracker_Movement_Trigger_RAK12500.ino new file mode 100644 index 0000000..2c9c773 --- /dev/null +++ b/tutorials/IoT_Education_Kits/Outdoor_Location_Kit/GPS_Tracker_Movement_Trigger_RAK12500/GPS_Tracker_Movement_Trigger_RAK12500.ino @@ -0,0 +1,547 @@ +/** + @file GPS_Tracker.ino + @author rakwireless.com + @brief This sketch demonstrate a GPS tracker that collect location from a uBlox M7 GNSS sensor + and send the data to lora gateway. + It uses a 3-axis acceleration sensor to detect movement of the tracker + @version 0.2 + @date 2021-04-30 + + @copyright Copyright (c) 2020 + + @note RAK4631 GPIO mapping to nRF52840 GPIO ports + RAK4631 <-> nRF52840 + WB_IO1 <-> P0.17 (GPIO 17) + WB_IO2 <-> P1.02 (GPIO 34) + WB_IO3 <-> P0.21 (GPIO 21) + WB_IO4 <-> P0.04 (GPIO 4) + WB_IO5 <-> P0.09 (GPIO 9) + WB_IO6 <-> P0.10 (GPIO 10) + WB_SW1 <-> P0.01 (GPIO 1) + WB_A0 <-> P0.04/AIN2 (AnalogIn A2) + WB_A1 <-> P0.31/AIN7 (AnalogIn A7) +*/ + +#include +#include //http://librarymanager/All#SX126x +#include +#include "SparkFunLIS3DH.h" //http://librarymanager/All#SparkFun-LIS3DH +#include //http://librarymanager/All#SparkFun_u-blox_GNSS +#include "Wire.h" + +#define INT1_PIN WB_IO5 // Set on Slot D to support all wisblock base. + +LIS3DH acc_sensor(I2C_MODE, 0x18); + +SFE_UBLOX_GNSS g_myGNSS; + +String tmp_data = ""; +int direction_S_N = 0; //0--S, 1--N +int direction_E_W = 0; //0--E, 1--W + +// RAK4630 supply two LED +#ifndef LED_BUILTIN +#define LED_BUILTIN 35 +#endif + +#ifndef LED_BUILTIN2 +#define LED_BUILTIN2 36 +#endif + +bool doOTAA = true; // OTAA is used by default. +#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */ +#define SCHED_QUEUE_SIZE 60 /**< Maximum number of events in the scheduler queue. */ +#define LORAWAN_DATERATE DR_0 /*LoRaMac datarates definition, from DR_0 to DR_5*/ +#define LORAWAN_TX_POWER TX_POWER_5 /*LoRaMac tx power definition, from TX_POWER_0 to TX_POWER_15*/ +#define JOINREQ_NBTRIALS 3 /**< Number of trials for the join request. */ +DeviceClass_t gCurrentClass = CLASS_A; /* class definition*/ +LoRaMacRegion_t gCurrentRegion = LORAMAC_REGION_US915; /* Region:EU868*/ +lmh_confirm gCurrentConfirm = LMH_UNCONFIRMED_MSG; /* confirm/unconfirm packet definition*/ +uint8_t gAppPort = LORAWAN_APP_PORT; /* data port*/ + +/**@brief Structure containing LoRaWan parameters, needed for lmh_init() +*/ +static lmh_param_t lora_param_init = {LORAWAN_ADR_ON, LORAWAN_DATERATE, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_TX_POWER, LORAWAN_DUTYCYCLE_OFF}; + +// Foward declaration +static void lorawan_has_joined_handler(void); +static void lorawan_join_failed_handler(void); +static void lorawan_rx_handler(lmh_app_data_t *app_data); +static void lorawan_confirm_class_handler(DeviceClass_t Class); +static void send_lora_frame(void); + +/**@brief Structure containing LoRaWan callback functions, needed for lmh_init() +*/ +static lmh_callback_t lora_callbacks = {BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed, + lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler + }; + +//OTAA keys !!!! KEYS ARE MSB !!!! +uint8_t nodeDeviceEUI[8] = {0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x06, 0x03, 0xFB}; +uint8_t nodeAppEUI[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +uint8_t nodeAppKey[16] = {0xFC, 0x07, 0x2B, 0x4B, 0x6A, 0xA7, 0xE5, 0x75, 0x89, 0x2A, 0x95, 0x80, 0x3F, 0xCB, 0xD3, 0xE3}; + +// ABP keys +uint32_t nodeDevAddr = 0x260116F8; +uint8_t nodeNwsKey[16] = {0x7E, 0xAC, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23}; +uint8_t nodeAppsKey[16] = {0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C}; + +// Private defination +#define LORAWAN_APP_DATA_BUFF_SIZE 64 /**< buffer size of the data to be transmitted. */ +#define LORAWAN_APP_INTERVAL 10000 /**< Defines for user timer, the application data transmission interval. 10s, value in [ms]. */ +static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE]; //< Lora user application data buffer. +static lmh_app_data_t m_lora_app_data = {m_lora_app_data_buffer, 0, 0, 0, 0}; //< Lora user application data structure. + +TimerEvent_t appTimer; +static uint32_t timers_init(void); +static uint32_t count = 0; +static uint32_t count_fail = 0; +volatile uint8_t tracker_trig = 0; +String data = ""; +bool send_always; + +void acc_int_callback(void) +{ + if (tracker_trig == 0) + { + Serial.println("Tracker Moved!"); + tracker_trig = 1; + send_lora_frame(); + } +} + +/** + @brief Clear ACC interrupt register to enable next wakeup + +*/ +void clear_acc_int(void) +{ + uint8_t data_read; + tracker_trig = 0; + acc_sensor.readRegister(&data_read, LIS3DH_INT1_SRC); +} + +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + + // Initialize Serial for debug output + time_t timeout = millis(); + Serial.begin(115200); + while (!Serial) + { + if ((millis() - timeout) < 5000) + { + delay(100); + } + else + { + break; + } + } + + // Initialize LoRa chip. + lora_rak4630_init(); + + Serial.println("====================================="); + Serial.println("Welcome to RAK4630 LoRaWan!!!"); + if (doOTAA) + { + Serial.println("Type: OTAA"); + } + else + { + Serial.println("Type: ABP"); + } + + switch (gCurrentRegion) + { + case LORAMAC_REGION_AS923: + Serial.println("Region: AS923"); + break; + case LORAMAC_REGION_AU915: + Serial.println("Region: AU915"); + break; + case LORAMAC_REGION_CN470: + Serial.println("Region: CN470"); + break; + case LORAMAC_REGION_CN779: + Serial.println("Region: CN779"); + break; + case LORAMAC_REGION_EU433: + Serial.println("Region: EU433"); + break; + case LORAMAC_REGION_IN865: + Serial.println("Region: IN865"); + break; + case LORAMAC_REGION_EU868: + Serial.println("Region: EU868"); + break; + case LORAMAC_REGION_KR920: + Serial.println("Region: KR920"); + break; + case LORAMAC_REGION_US915: + Serial.println("Region: US915"); + break; + case LORAMAC_REGION_RU864: + Serial.println("Region: RU864"); + break; + case LORAMAC_REGION_AS923_2: + Serial.println("Region: AS923-2"); + break; + case LORAMAC_REGION_AS923_3: + Serial.println("Region: AS923-3"); + break; + case LORAMAC_REGION_AS923_4: + Serial.println("Region: AS923-4"); + break; + } + Serial.println("====================================="); + + pinMode(INT1_PIN, INPUT); + + Wire.begin(); + + acc_sensor.settings.accelSampleRate = 10; //Hz. Can be: 0,1,10,25,50,100,200,400,1600,5000 Hz + acc_sensor.settings.accelRange = 2; //Max G force readable. Can be: 2, 4, 8, 16 + + acc_sensor.settings.adcEnabled = 0; + acc_sensor.settings.tempEnabled = 0; + acc_sensor.settings.xAccelEnabled = 1; + acc_sensor.settings.yAccelEnabled = 1; + acc_sensor.settings.zAccelEnabled = 1; + + //lis3dh init + if (acc_sensor.begin() != 0) + { + Serial.println("Problem starting the sensor at 0x18."); + } + else + { + uint8_t data_to_write = 0; + // Enable interrupts + data_to_write |= 0x20; //Z high + data_to_write |= 0x08; //Y high + data_to_write |= 0x02; //X high + acc_sensor.writeRegister(LIS3DH_INT1_CFG, data_to_write); // Enable interrupts on high tresholds for x, y and z + + // Set interrupt trigger range + data_to_write = 0; + + data_to_write |= 0x10; // 1/8 range + + acc_sensor.writeRegister(LIS3DH_INT1_THS, data_to_write); // 1/8th range + + // Set interrupt signal length + data_to_write = 0; + data_to_write |= 0x01; // 1 * 1/50 s = 20ms + acc_sensor.writeRegister(LIS3DH_INT1_DURATION, data_to_write); + + acc_sensor.readRegister(&data_to_write, LIS3DH_CTRL_REG5); + data_to_write &= 0xF3; //Clear bits of interest + data_to_write |= 0x08; //Latch interrupt (Cleared by reading int1_src) + acc_sensor.writeRegister(LIS3DH_CTRL_REG5, data_to_write); // Set interrupt to latching + + // Select interrupt pin 1 + data_to_write = 0; + data_to_write |= 0x40; //AOI1 event (Generator 1 interrupt on pin 1) + data_to_write |= 0x20; //AOI2 event () + acc_sensor.writeRegister(LIS3DH_CTRL_REG3, data_to_write); + + // No interrupt on pin 2 + acc_sensor.writeRegister(LIS3DH_CTRL_REG6, 0x00); + + // Enable high pass filter + acc_sensor.writeRegister(LIS3DH_CTRL_REG2, 0x01); + + // Set low power mode + data_to_write = 0; + acc_sensor.readRegister(&data_to_write, LIS3DH_CTRL_REG1); + data_to_write |= 0x08; + acc_sensor.writeRegister(LIS3DH_CTRL_REG1, data_to_write); + delay(100); + data_to_write = 0; + acc_sensor.readRegister(&data_to_write, 0x1E); + data_to_write |= 0x90; + acc_sensor.writeRegister(0x1E, data_to_write); + delay(100); + + clear_acc_int(); + + // Set the interrupt callback function + attachInterrupt(INT1_PIN, acc_int_callback, RISING); + } + //gps init + + pinMode(WB_IO2, OUTPUT); + digitalWrite(WB_IO2, 0); + delay(1000); + digitalWrite(WB_IO2, 1); + delay(1000); + + int baud[7] = {9600, 14400, 19200, 38400, 56000, 57600, 115200}; + + for (int i = 0 ; i < sizeof(baud) / sizeof(int) ; i++) + { + Serial1.begin(baud[i]); + while (!Serial1); // Wait for user to open terminal + if (g_myGNSS.begin(Serial1) == true) + { + Serial.printf("GNSS baund rate: %d \n", baud[i]); //GNSS baund rate + break; + } + Serial1.end(); + delay(200); + } + Serial.println("GNSS serial connected"); + + g_myGNSS.setUART1Output(COM_TYPE_UBX); //Set the UART port to output UBX only + g_myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + g_myGNSS.saveConfiguration(); //Save the current settings to flash and BBR + + //creat a user timer to send data to server period + uint32_t err_code; + + err_code = timers_init(); + if (err_code != 0) + { + Serial.printf("timers_init failed - %d\n", err_code); + return; + } + + // Setup the EUIs and Keys + if (doOTAA) + { + lmh_setDevEui(nodeDeviceEUI); + lmh_setAppEui(nodeAppEUI); + lmh_setAppKey(nodeAppKey); + } + else + { + lmh_setNwkSKey(nodeNwsKey); + lmh_setAppSKey(nodeAppsKey); + lmh_setDevAddr(nodeDevAddr); + } + + // Initialize LoRaWan + err_code = lmh_init(&lora_callbacks, lora_param_init, doOTAA, gCurrentClass, gCurrentRegion); + if (err_code != 0) + { + Serial.printf("lmh_init failed - %d\n", err_code); + return; + } + + // Start Join procedure + lmh_join(); +} + +void loop() +{ + send_always = 1; // Make this value 1 if you want continuous transmission and 0 if only when triggered. + float x = 0; + float y = 0; + float z = 0; + + Serial.println("\ncheck acc!"); + x = acc_sensor.readFloatAccelX() * 1000; + y = acc_sensor.readFloatAccelY() * 1000; + z = acc_sensor.readFloatAccelZ() * 1000; + data = "X = " + String(x) + "mg" + " Y = " + String(y) + "mg" + " Z =" + String(z) + "mg"; + Serial.println(data); + data = ""; + + // long latitude; + // long longitude; + uint32_t latitude = 10000000; + uint32_t longitude = 10000000; + + // For one second we parse GPS data and report some key values + for (unsigned long start = millis(); millis() - start < 1000;) + { + latitude = g_myGNSS.getLatitude(); + Serial.print(F(" Lat: ")); + Serial.print(latitude); + + longitude = g_myGNSS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + } + + // float flat, flon; + // int32_t ilat, ilon; + + // unsigned long age; + // gps.f_get_position(&flat, &flon, &age); + // flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat; + // ilat = flat * 100000; + // flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon; + // ilon = flon * 100000; + memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE); + m_lora_app_data.port = gAppPort; + m_lora_app_data.buffer[0] = 0x09; + //lat data + m_lora_app_data.buffer[1] = (latitude & 0xFF000000) >> 24; + m_lora_app_data.buffer[2] = (latitude & 0x00FF0000) >> 16; + m_lora_app_data.buffer[3] = (latitude & 0x0000FF00) >> 8; + m_lora_app_data.buffer[4] = latitude & 0x000000FF; + if (direction_S_N == 0) + { + m_lora_app_data.buffer[5] = 'S'; + } + else + { + m_lora_app_data.buffer[5] = 'N'; + } + //lon data + m_lora_app_data.buffer[6] = (longitude & 0xFF000000) >> 24; + m_lora_app_data.buffer[7] = (longitude & 0x00FF0000) >> 16; + m_lora_app_data.buffer[8] = (longitude & 0x0000FF00) >> 8; + m_lora_app_data.buffer[9] = longitude & 0x000000FF; + if (direction_E_W == 0) + { + m_lora_app_data.buffer[10] = 'E'; + } + else + { + m_lora_app_data.buffer[10] = 'W'; + } + m_lora_app_data.buffsize = 11; + + // Put your application tasks here, like reading of sensors, + // Controlling actuators and/or other functions. +} + +/**@brief LoRa function for handling HasJoined event. +*/ +void lorawan_has_joined_handler(void) +{ + if (doOTAA == true) + { + Serial.println("OTAA Mode, Network Joined!"); + } + else + { + Serial.println("ABP Mode"); + } + + lmh_error_status ret = lmh_class_request(gCurrentClass); + if (ret == LMH_SUCCESS) + { + delay(1000); + TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL); + TimerStart(&appTimer); + } +} +/**@brief LoRa function for handling OTAA join failed +*/ +static void lorawan_join_failed_handler(void) +{ + Serial.println("OTAA join failed!"); + Serial.println("Check your EUI's and Keys's!"); + Serial.println("Check if a Gateway is in range!"); +} +/**@brief Function for handling LoRaWan received data from Gateway + + @param[in] app_data Pointer to rx data +*/ +void lorawan_rx_handler(lmh_app_data_t *app_data) +{ + Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n", + app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer); +} + +void lorawan_confirm_class_handler(DeviceClass_t Class) +{ + Serial.printf("switch to class %c done\n", "ABC"[Class]); + // Informs the server that switch has occurred ASAP + m_lora_app_data.buffsize = 0; + m_lora_app_data.port = gAppPort; + lmh_send(&m_lora_app_data, gCurrentConfirm); +} + +void send_lora_frame(void) +{ + if (lmh_join_status_get() != LMH_SET) + { + //Not joined, try again later + return; + } + + if (tracker_trig == 1 || send_always == 1) + { + lmh_error_status error = lmh_send(&m_lora_app_data, gCurrentConfirm); + if (error == LMH_SUCCESS) + { + count++; + Serial.printf("lmh_send ok count %d\n", count); + } + else + { + count_fail++; + Serial.printf("lmh_send fail count %d\n", count_fail); + } + TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL); + TimerStart(&appTimer); + } + else + { + Serial.printf("Not sending!", count_fail); + TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL); + TimerStart(&appTimer); + } +} + +/**@brief Function for analytical direction. +*/ +void direction_parse(String tmp) +{ + if (tmp.indexOf(",E,") != -1) + { + direction_E_W = 0; + } + else + { + direction_E_W = 1; + } + + if (tmp.indexOf(",S,") != -1) + { + direction_S_N = 0; + } + else + { + direction_S_N = 1; + } +} + +/**@brief Function for handling a LoRa tx timer timeout event. +*/ + +void tx_lora_periodic_handler(void) +{ + if (send_always == 1) + { + send_lora_frame(); + } + else + { + Serial.println("No Location Found"); + TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL); + TimerStart(&appTimer); + } + tracker_trig = 0; + send_always = 0; + clear_acc_int(); +} + +/**@brief Function for the Timer initialization. + + @details Initializes the timer module. This creates and starts application timers. +*/ +uint32_t timers_init(void) +{ + TimerInit(&appTimer, tx_lora_periodic_handler); + return 0; +} diff --git a/tutorials/IoT_Education_Kits/Outdoor_Location_Kit/GPS_Tracker_Movement_Trigger_RAK1910/GPS_Tracker_Movement_Trigger_RAK1910.ino b/tutorials/IoT_Education_Kits/Outdoor_Location_Kit/GPS_Tracker_Movement_Trigger_RAK1910/GPS_Tracker_Movement_Trigger_RAK1910.ino new file mode 100644 index 0000000..3a31ebc --- /dev/null +++ b/tutorials/IoT_Education_Kits/Outdoor_Location_Kit/GPS_Tracker_Movement_Trigger_RAK1910/GPS_Tracker_Movement_Trigger_RAK1910.ino @@ -0,0 +1,529 @@ +/** + @file GPS_Tracker.ino + @author rakwireless.com + @brief This sketch demonstrate a GPS tracker that collect location from a uBlox M7 GNSS sensor + and send the data to lora gateway. + It uses a 3-axis acceleration sensor to detect movement of the tracker + @version 0.2 + @date 2021-04-30 + + @copyright Copyright (c) 2020 + + @note RAK4631 GPIO mapping to nRF52840 GPIO ports + RAK4631 <-> nRF52840 + WB_IO1 <-> P0.17 (GPIO 17) + WB_IO2 <-> P1.02 (GPIO 34) + WB_IO3 <-> P0.21 (GPIO 21) + WB_IO4 <-> P0.04 (GPIO 4) + WB_IO5 <-> P0.09 (GPIO 9) + WB_IO6 <-> P0.10 (GPIO 10) + WB_SW1 <-> P0.01 (GPIO 1) + WB_A0 <-> P0.04/AIN2 (AnalogIn A2) + WB_A1 <-> P0.31/AIN7 (AnalogIn A7) +*/ + +#include +#include //http://librarymanager/All#SX126x +#include +#include "SparkFunLIS3DH.h" //http://librarymanager/All#SparkFun-LIS3DH +#include "Wire.h" +#include //http://librarymanager/All#TinyGPS + +#define INT1_PIN WB_IO5 // Set on Slot D to support all wisblock base. + +LIS3DH acc_sensor(I2C_MODE, 0x18); + +TinyGPS gps; + +String tmp_data = ""; +int direction_S_N = 0; //0--S, 1--N +int direction_E_W = 0; //0--E, 1--W + +// RAK4630 supply two LED +#ifndef LED_BUILTIN +#define LED_BUILTIN 35 +#endif + +#ifndef LED_BUILTIN2 +#define LED_BUILTIN2 36 +#endif + +bool doOTAA = true; // OTAA is used by default. +#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */ +#define SCHED_QUEUE_SIZE 60 /**< Maximum number of events in the scheduler queue. */ +#define LORAWAN_DATERATE DR_0 /*LoRaMac datarates definition, from DR_0 to DR_5*/ +#define LORAWAN_TX_POWER TX_POWER_5 /*LoRaMac tx power definition, from TX_POWER_0 to TX_POWER_15*/ +#define JOINREQ_NBTRIALS 3 /**< Number of trials for the join request. */ +DeviceClass_t gCurrentClass = CLASS_A; /* class definition*/ +LoRaMacRegion_t gCurrentRegion = LORAMAC_REGION_EU868; /* Region:EU868*/ +lmh_confirm gCurrentConfirm = LMH_UNCONFIRMED_MSG; /* confirm/unconfirm packet definition*/ +uint8_t gAppPort = LORAWAN_APP_PORT; /* data port*/ + +/**@brief Structure containing LoRaWan parameters, needed for lmh_init() +*/ +static lmh_param_t lora_param_init = {LORAWAN_ADR_ON, LORAWAN_DATERATE, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_TX_POWER, LORAWAN_DUTYCYCLE_OFF}; + +// Foward declaration +static void lorawan_has_joined_handler(void); +static void lorawan_join_failed_handler(void); +static void lorawan_rx_handler(lmh_app_data_t *app_data); +static void lorawan_confirm_class_handler(DeviceClass_t Class); +static void send_lora_frame(void); + +/**@brief Structure containing LoRaWan callback functions, needed for lmh_init() +*/ +static lmh_callback_t lora_callbacks = {BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed, + lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler + }; + +//OTAA keys !!!! KEYS ARE MSB !!!! +uint8_t nodeDeviceEUI[8] = {0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x06, 0x03, 0xFB}; +uint8_t nodeAppEUI[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +uint8_t nodeAppKey[16] = {0xFC, 0x07, 0x2B, 0x4B, 0x6A, 0xA7, 0xE5, 0x75, 0x89, 0x2A, 0x95, 0x80, 0x3F, 0xCB, 0xD3, 0xE3}; + +// ABP keys +uint32_t nodeDevAddr = 0x260116F8; +uint8_t nodeNwsKey[16] = {0x7E, 0xAC, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23}; +uint8_t nodeAppsKey[16] = {0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C}; + +// Private defination +#define LORAWAN_APP_DATA_BUFF_SIZE 64 /**< buffer size of the data to be transmitted. */ +#define LORAWAN_APP_INTERVAL 10000 /**< Defines for user timer, the application data transmission interval. 10s, value in [ms]. */ +static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE]; //< Lora user application data buffer. +static lmh_app_data_t m_lora_app_data = {m_lora_app_data_buffer, 0, 0, 0, 0}; //< Lora user application data structure. + +TimerEvent_t appTimer; +static uint32_t timers_init(void); +static uint32_t count = 0; +static uint32_t count_fail = 0; +volatile uint8_t tracker_trig = 0; +String data = ""; +bool send_always; + +void acc_int_callback(void) +{ + if (tracker_trig == 0) + { + Serial.println("Tracker Moved!"); + tracker_trig = 1; + send_lora_frame(); + } +} + +/** + @brief Clear ACC interrupt register to enable next wakeup + +*/ +void clear_acc_int(void) +{ + uint8_t data_read; + tracker_trig = 0; + acc_sensor.readRegister(&data_read, LIS3DH_INT1_SRC); +} + +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + + // Initialize Serial for debug output + time_t timeout = millis(); + Serial.begin(115200); + while (!Serial) + { + if ((millis() - timeout) < 5000) + { + delay(100); + } + else + { + break; + } + } + + // Initialize LoRa chip. + lora_rak4630_init(); + + Serial.println("====================================="); + Serial.println("Welcome to RAK4630 LoRaWan!!!"); + if (doOTAA) + { + Serial.println("Type: OTAA"); + } + else + { + Serial.println("Type: ABP"); + } + + switch (gCurrentRegion) + { + case LORAMAC_REGION_AS923: + Serial.println("Region: AS923"); + break; + case LORAMAC_REGION_AU915: + Serial.println("Region: AU915"); + break; + case LORAMAC_REGION_CN470: + Serial.println("Region: CN470"); + break; + case LORAMAC_REGION_CN779: + Serial.println("Region: CN779"); + break; + case LORAMAC_REGION_EU433: + Serial.println("Region: EU433"); + break; + case LORAMAC_REGION_IN865: + Serial.println("Region: IN865"); + break; + case LORAMAC_REGION_EU868: + Serial.println("Region: EU868"); + break; + case LORAMAC_REGION_KR920: + Serial.println("Region: KR920"); + break; + case LORAMAC_REGION_US915: + Serial.println("Region: US915"); + break; + case LORAMAC_REGION_RU864: + Serial.println("Region: RU864"); + break; + case LORAMAC_REGION_AS923_2: + Serial.println("Region: AS923-2"); + break; + case LORAMAC_REGION_AS923_3: + Serial.println("Region: AS923-3"); + break; + case LORAMAC_REGION_AS923_4: + Serial.println("Region: AS923-4"); + break; + } + Serial.println("====================================="); + + pinMode(INT1_PIN, INPUT); + + Wire.begin(); + + acc_sensor.settings.accelSampleRate = 10; //Hz. Can be: 0,1,10,25,50,100,200,400,1600,5000 Hz + acc_sensor.settings.accelRange = 2; //Max G force readable. Can be: 2, 4, 8, 16 + + acc_sensor.settings.adcEnabled = 0; + acc_sensor.settings.tempEnabled = 0; + acc_sensor.settings.xAccelEnabled = 1; + acc_sensor.settings.yAccelEnabled = 1; + acc_sensor.settings.zAccelEnabled = 1; + + //lis3dh init + if (acc_sensor.begin() != 0) + { + Serial.println("Problem starting the sensor at 0x18."); + } + else + { + uint8_t data_to_write = 0; + // Enable interrupts + data_to_write |= 0x20; //Z high + data_to_write |= 0x08; //Y high + data_to_write |= 0x02; //X high + acc_sensor.writeRegister(LIS3DH_INT1_CFG, data_to_write); // Enable interrupts on high tresholds for x, y and z + + // Set interrupt trigger range + data_to_write = 0; + + data_to_write |= 0x10; // 1/8 range + + acc_sensor.writeRegister(LIS3DH_INT1_THS, data_to_write); // 1/8th range + + // Set interrupt signal length + data_to_write = 0; + data_to_write |= 0x01; // 1 * 1/50 s = 20ms + acc_sensor.writeRegister(LIS3DH_INT1_DURATION, data_to_write); + + acc_sensor.readRegister(&data_to_write, LIS3DH_CTRL_REG5); + data_to_write &= 0xF3; //Clear bits of interest + data_to_write |= 0x08; //Latch interrupt (Cleared by reading int1_src) + acc_sensor.writeRegister(LIS3DH_CTRL_REG5, data_to_write); // Set interrupt to latching + + // Select interrupt pin 1 + data_to_write = 0; + data_to_write |= 0x40; //AOI1 event (Generator 1 interrupt on pin 1) + data_to_write |= 0x20; //AOI2 event () + acc_sensor.writeRegister(LIS3DH_CTRL_REG3, data_to_write); + + // No interrupt on pin 2 + acc_sensor.writeRegister(LIS3DH_CTRL_REG6, 0x00); + + // Enable high pass filter + acc_sensor.writeRegister(LIS3DH_CTRL_REG2, 0x01); + + // Set low power mode + data_to_write = 0; + acc_sensor.readRegister(&data_to_write, LIS3DH_CTRL_REG1); + data_to_write |= 0x08; + acc_sensor.writeRegister(LIS3DH_CTRL_REG1, data_to_write); + delay(100); + data_to_write = 0; + acc_sensor.readRegister(&data_to_write, 0x1E); + data_to_write |= 0x90; + acc_sensor.writeRegister(0x1E, data_to_write); + delay(100); + + clear_acc_int(); + + // Set the interrupt callback function + attachInterrupt(INT1_PIN, acc_int_callback, RISING); + } + //gps init + + pinMode(WB_IO2, OUTPUT); + digitalWrite(WB_IO2, 0); + delay(1000); + digitalWrite(WB_IO2, 1); + delay(1000); + + Serial1.begin(9600); + while (!Serial1); + Serial.println("gps uart init ok!"); + + //creat a user timer to send data to server period + uint32_t err_code; + + err_code = timers_init(); + if (err_code != 0) + { + Serial.printf("timers_init failed - %d\n", err_code); + return; + } + + // Setup the EUIs and Keys + if (doOTAA) + { + lmh_setDevEui(nodeDeviceEUI); + lmh_setAppEui(nodeAppEUI); + lmh_setAppKey(nodeAppKey); + } + else + { + lmh_setNwkSKey(nodeNwsKey); + lmh_setAppSKey(nodeAppsKey); + lmh_setDevAddr(nodeDevAddr); + } + + // Initialize LoRaWan + err_code = lmh_init(&lora_callbacks, lora_param_init, doOTAA, gCurrentClass, gCurrentRegion); + if (err_code != 0) + { + Serial.printf("lmh_init failed - %d\n", err_code); + return; + } + + // Start Join procedure + lmh_join(); +} + +void loop() +{ + send_always = 1; // Make this value 1 if you want continuous transmission and 0 if only when triggered. + float x = 0; + float y = 0; + float z = 0; + + bool newData = false; + + Serial.println("/ncheck acc!"); + x = acc_sensor.readFloatAccelX() * 1000; + y = acc_sensor.readFloatAccelY() * 1000; + z = acc_sensor.readFloatAccelZ() * 1000; + data = "X = " + String(x) + "mg" + " Y = " + String(y) + "mg" + " Z =" + String(z) + "mg"; + Serial.println(data); + data = ""; + // For one second we parse GPS data and report some key values + for (unsigned long start = millis(); millis() - start < 1000;) + { + while (Serial1.available()) + { + char c = Serial1.read(); + Serial.write(c); // uncomment this line if you want to see the GPS data flowing + tmp_data += c; + if (gps.encode(c))// Did a new valid sentence come in? + newData = true; + } + } + direction_parse(tmp_data); + tmp_data = ""; + float flat, flon; + int32_t ilat, ilon; + if (newData) + { + unsigned long age; + gps.f_get_position(&flat, &flon, &age); + flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat; + ilat = flat * 100000; + flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon; + ilon = flon * 100000; + memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE); + m_lora_app_data.port = gAppPort; + m_lora_app_data.buffer[0] = 0x09; + //lat data + m_lora_app_data.buffer[1] = (ilat & 0xFF000000) >> 24; + m_lora_app_data.buffer[2] = (ilat & 0x00FF0000) >> 16; + m_lora_app_data.buffer[3] = (ilat & 0x0000FF00) >> 8; + m_lora_app_data.buffer[4] = ilat & 0x000000FF; + if (direction_S_N == 0) + { + m_lora_app_data.buffer[5] = 'S'; + } + else + { + m_lora_app_data.buffer[5] = 'N'; + } + //lon data + m_lora_app_data.buffer[6] = (ilon & 0xFF000000) >> 24; + m_lora_app_data.buffer[7] = (ilon & 0x00FF0000) >> 16; + m_lora_app_data.buffer[8] = (ilon & 0x0000FF00) >> 8; + m_lora_app_data.buffer[9] = ilon & 0x000000FF; + if (direction_E_W == 0) + { + m_lora_app_data.buffer[10] = 'E'; + } + else + { + m_lora_app_data.buffer[10] = 'W'; + } + m_lora_app_data.buffsize = 11; + } + // Put your application tasks here, like reading of sensors, + // Controlling actuators and/or other functions. +} + +/**@brief LoRa function for handling HasJoined event. +*/ +void lorawan_has_joined_handler(void) +{ + if (doOTAA == true) + { + Serial.println("OTAA Mode, Network Joined!"); + } + else + { + Serial.println("ABP Mode"); + } + + lmh_error_status ret = lmh_class_request(gCurrentClass); + if (ret == LMH_SUCCESS) + { + delay(1000); + TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL); + TimerStart(&appTimer); + } +} +/**@brief LoRa function for handling OTAA join failed +*/ +static void lorawan_join_failed_handler(void) +{ + Serial.println("OTAA join failed!"); + Serial.println("Check your EUI's and Keys's!"); + Serial.println("Check if a Gateway is in range!"); +} +/**@brief Function for handling LoRaWan received data from Gateway + + @param[in] app_data Pointer to rx data +*/ +void lorawan_rx_handler(lmh_app_data_t *app_data) +{ + Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n", + app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer); +} + +void lorawan_confirm_class_handler(DeviceClass_t Class) +{ + Serial.printf("switch to class %c done\n", "ABC"[Class]); + // Informs the server that switch has occurred ASAP + m_lora_app_data.buffsize = 0; + m_lora_app_data.port = gAppPort; + lmh_send(&m_lora_app_data, gCurrentConfirm); +} + +void send_lora_frame(void) +{ + if (lmh_join_status_get() != LMH_SET) + { + //Not joined, try again later + return; + } + + if (tracker_trig == 1 || send_always == 1) + { + lmh_error_status error = lmh_send(&m_lora_app_data, gCurrentConfirm); + if (error == LMH_SUCCESS) + { + count++; + Serial.printf("lmh_send ok count %d\n", count); + } + else + { + count_fail++; + Serial.printf("lmh_send fail count %d\n", count_fail); + } + TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL); + TimerStart(&appTimer); + } + else + { + Serial.printf("Not sending!", count_fail); + TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL); + TimerStart(&appTimer); + } +} + +/**@brief Function for analytical direction. +*/ +void direction_parse(String tmp) +{ + if (tmp.indexOf(",E,") != -1) + { + direction_E_W = 0; + } + else + { + direction_E_W = 1; + } + + if (tmp.indexOf(",S,") != -1) + { + direction_S_N = 0; + } + else + { + direction_S_N = 1; + } +} + +/**@brief Function for handling a LoRa tx timer timeout event. +*/ + +void tx_lora_periodic_handler(void) +{ + if (send_always == 1) + { + send_lora_frame(); + } + else + { + Serial.println("No Location Found"); + TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL); + TimerStart(&appTimer); + } + tracker_trig = 0; + send_always = 0; + clear_acc_int(); +} + +/**@brief Function for the Timer initialization. + + @details Initializes the timer module. This creates and starts application timers. +*/ +uint32_t timers_init(void) +{ + TimerInit(&appTimer, tx_lora_periodic_handler); + return 0; +}