Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: libmDot-mbed5 ISL29011
LD100_example.cpp
00001 #include "dot_util.h" 00002 #include "RadioEvent.h" 00003 #include "LD100_util.h" 00004 00005 #if ACTIVE_EXAMPLE == LD100_EXAMPLE 00006 00007 ///////////////////////////////////////////////////////////////////////////// 00008 // -------------------- DOT LIBRARY REQUIRED ------------------------------// 00009 // * Because these example programs can be used for both mDot and xDot // 00010 // devices, the LoRa stack is not included. The libmDot library should // 00011 // be imported if building for mDot devices. The libxDot library // 00012 // should be imported if building for xDot devices. // 00013 // * https://developer.mbed.org/teams/MultiTech/code/libmDot-dev-mbed5/ // 00014 // * https://developer.mbed.org/teams/MultiTech/code/libmDot-mbed5/ // 00015 // * https://developer.mbed.org/teams/MultiTech/code/libxDot-dev-mbed5/ // 00016 // * https://developer.mbed.org/teams/MultiTech/code/libxDot-mbed5/ // 00017 ///////////////////////////////////////////////////////////////////////////// 00018 00019 ///////////////////////////////////////////////////////////// 00020 // * these options must match the settings on your gateway // 00021 // * edit their values to match your configuration // 00022 // * frequency sub band is only relevant for the 915 bands // 00023 // * either the network name and passphrase can be used or // 00024 // the network ID (8 bytes) and KEY (16 bytes) // 00025 ///////////////////////////////////////////////////////////// 00026 static std::string network_name = "MTCDT-18446018"; 00027 static std::string network_passphrase = "jointech_passphrase"; 00028 static uint8_t network_id[] = { 0x57, 0xD7, 0x64, 0xA4, 0x0C, 0xFE, 0xB1, 0xDF }; 00029 static uint8_t network_key[] = { 0x63, 0x81, 0x87, 0x8D, 0x11, 0x45, 0x88, 0x13, 0x30, 0xCF, 0xCF, 0xBC, 0x1D, 0x48, 0xA8, 0xEC }; 00030 static uint8_t frequency_sub_band = 2; 00031 static lora::NetworkType network_type = lora::PUBLIC_LORAWAN; 00032 static uint8_t join_delay = 5; 00033 static uint8_t ack = 0; 00034 static bool adr = true; 00035 00036 // deepsleep consumes slightly less current than sleep 00037 // in sleep mode, IO state is maintained, RAM is retained, and application will resume after waking up 00038 // in deepsleep mode, IOs float, RAM is lost, and application will start from beginning after waking up 00039 // if deep_sleep == true, device will enter deepsleep mode 00040 static bool deep_sleep = false; 00041 00042 mDot* dot = NULL; 00043 lora::ChannelPlan* plan = NULL; 00044 00045 Serial pc(USBTX, USBRX); 00046 00047 void ReadBatteryLevelAndSend() 00048 // get some dummy data and send it to the gateway 00049 { 00050 std::vector<uint8_t> tx_data; 00051 AnalogIn adc_batt(A2); 00052 float voltage; 00053 uint16_t u16_read; 00054 uint8_t u8_send; 00055 u16_read = adc_batt.read_u16(); // read ADC value 00056 voltage = u16_read / 65535.0 * 3.3 * 2; //convert to voltage level 00057 u8_send = voltage * 10; //use integer and 1 digit of decimal number 00058 logInfo("Battery Level: Voltage:%f [ADC:%u], Upload Value:%d(0x%x)", voltage, (int)u16_read, (int)u8_send, (int)u8_send); 00059 tx_data.push_back(u8_send); 00060 dot->setAppPort(10); //give a port number to distinglish data source 00061 send_data(tx_data); 00062 } 00063 00064 uint16_t modbus_crc16(const uint8_t *buf, int length) { 00065 uint16_t crc = 0xFFFF; 00066 int i,j; 00067 uint8_t LSB; 00068 for (i = 0; i < length; i++) { 00069 crc ^= buf[i]; 00070 for (j = 0; j < 8; j++) { 00071 LSB= crc & 1; 00072 crc = crc >> 1; 00073 if (LSB) { 00074 crc ^= 0xA001; 00075 } 00076 } 00077 } 00078 return crc; 00079 } 00080 00081 #define RS485_BAUDRATE 9600 00082 #define RS485_BITS 8 00083 #define RS485_PARITY mbed::SerialBase::None 00084 #define RS485_STOPBITS 1 00085 #define RS485_BTYETIME_MS 1 00086 #define RS485_BTYETIME_US 1042 00087 const int buffer_size = 256; 00088 uint8_t buffer[buffer_size]; 00089 00090 00091 void ReadRS485SensorAndSend() 00092 // get some dummy data and send it to the gateway 00093 { 00094 std::vector<uint8_t> tx_data; 00095 00096 00097 DigitalOut rs485RWctl(PA_11); 00098 Serial rs485(SERIAL_TX, SERIAL_RX); 00099 00100 rs485RWctl = 0; //set low to stay in receiver mode 00101 rs485.baud(RS485_BAUDRATE); 00102 rs485.format(RS485_BITS, RS485_PARITY , RS485_STOPBITS); 00103 //clear modbus buffer 00104 { 00105 Timer t; 00106 t.reset(); t.start(); 00107 int timeup_ms = RS485_BTYETIME_MS * 4; // let Modbus Frame Time Out 00108 while (t.read_ms() < timeup_ms) 00109 { 00110 if (rs485.readable()) 00111 { 00112 timeup_ms = RS485_BTYETIME_MS * 3; // modbus frame timeout 00113 rs485.getc(); 00114 t.reset(); 00115 } 00116 } 00117 t.stop(); 00118 } 00119 00120 //sent Modbus command 00121 { 00122 int trans_count = 0; 00123 uint16_t crc16; 00124 buffer[0]= 0x0A; //Addr 00125 buffer[1]= 0x04; //Func 00126 buffer[2]= 0x00; //Register (High Byte) 00127 buffer[3]= 0x01; //Register (Low Byte) 00128 buffer[4]= 0x00; //Quantity (High Byte) 00129 buffer[5]= 10; //Quantity (Low Byte) 00130 crc16 = modbus_crc16(buffer, 6); 00131 buffer[6]= (crc16) & 0x00FF; //CRC16 (Low Byte) 00132 buffer[7]= (crc16 >> 8) & 0x00FF; //CRC16 (High Byte) 00133 00134 rs485RWctl = 1; //set high to swtich to transmitor mode 00135 while ( trans_count < 8) 00136 { 00137 if (rs485.writable()) 00138 { 00139 rs485.putc(buffer[trans_count]); 00140 trans_count++; 00141 wait_ms(RS485_BTYETIME_MS); 00142 } 00143 } 00144 wait_ms(RS485_BTYETIME_MS * 2); // let last byte transmit completely 00145 rs485RWctl = 0; //set low to switch back receiver mode 00146 logDebug("Send a Modbus command to RS485"); 00147 } 00148 00149 //retrieve Modbus Data 00150 { 00151 Timer t; 00152 t.reset(); t.start(); 00153 int timeup_ms = 200; // modbus command timeout, depend on devices 00154 int hasReceivedBytes = 0; 00155 int receivedBytes = 0; 00156 00157 while (t.read_ms() < timeup_ms) 00158 { 00159 if (rs485.readable()) 00160 { 00161 timeup_ms = RS485_BTYETIME_MS * 3; // modbus frame timeout 00162 t.reset(); 00163 buffer[receivedBytes] = rs485.getc(); 00164 receivedBytes++; 00165 hasReceivedBytes ++; 00166 } 00167 } 00168 t.stop(); 00169 if ( hasReceivedBytes > 2) 00170 { 00171 uint16_t crc16; 00172 crc16 = modbus_crc16(buffer, hasReceivedBytes -2 ); 00173 if ( (buffer[hasReceivedBytes - 1] == ((crc16 >> 8) & 0x00FF)) && 00174 (buffer[hasReceivedBytes - 2] == ((crc16 ) & 0x00FF)) ) 00175 { 00176 logDebug("Received Modbus %d bytes correctly", hasReceivedBytes); 00177 logInfo("Received Modbus Data:%s", mts::Text::bin2hexString(buffer,hasReceivedBytes).c_str()); 00178 if (( buffer[0] == 0x0A) && ( buffer[1]== 0x04) && ( buffer[2]== 20)) 00179 { 00180 // send data to LoRaWAN gateway 00181 tx_data.push_back(buffer[3]); //temperature high byte 00182 tx_data.push_back(buffer[4]); //temperature low byte 00183 tx_data.push_back(buffer[9]); //Vibration X RMS high byte 00184 tx_data.push_back(buffer[10]); //Vibration X RAS low byte 00185 tx_data.push_back(buffer[11]); //Vibration Y RMS high byte 00186 tx_data.push_back(buffer[12]); //Vibration Y RAS low byte 00187 tx_data.push_back(buffer[13]); //Vibration Z RMS high byte 00188 tx_data.push_back(buffer[14]); //Vibration Z RMS low byte 00189 tx_data.push_back(buffer[21]); //Power Line Freq high byte 00190 tx_data.push_back(buffer[22]); //Power Line Freq low byte 00191 logInfo("Sent 10 bytes Data to LoraWAN Gateway"); 00192 dot->setAppPort(11); //give a port number to distinglish data source 00193 send_data(tx_data); 00194 logDebug("Sent Data to LoraWAN Gateway finished"); 00195 } 00196 else 00197 logDebug("Received Modbus Frame is not sensor data"); 00198 } 00199 else 00200 { 00201 logDebug("Received Modbus Frame CRC error"); 00202 logDebug("Received Modbus Data:%s", mts::Text::bin2hexString(buffer,hasReceivedBytes).c_str()); 00203 } 00204 } 00205 else 00206 { 00207 if (0 == hasReceivedBytes) 00208 logDebug("Modbus Command Timeout"); 00209 else 00210 logDebug("Received Modbus Frame Error"); 00211 } 00212 } 00213 } 00214 00215 int main() { 00216 // Custom event handler for automatically displaying RX data 00217 RadioEvent events; 00218 00219 pc.baud(115200); 00220 00221 #if defined(TARGET_XDOT_L151CC) 00222 i2c.frequency(400000); 00223 #endif 00224 00225 mts::MTSLog::setLogLevel(mts::MTSLog::TRACE_LEVEL); 00226 00227 #if CHANNEL_PLAN == CP_US915 00228 plan = new lora::ChannelPlan_US915(); 00229 #elif CHANNEL_PLAN == CP_AU915 00230 plan = new lora::ChannelPlan_AU915(); 00231 #elif CHANNEL_PLAN == CP_EU868 00232 plan = new lora::ChannelPlan_EU868(); 00233 #elif CHANNEL_PLAN == CP_KR920 00234 plan = new lora::ChannelPlan_KR920(); 00235 #elif CHANNEL_PLAN == CP_AS923 00236 plan = new lora::ChannelPlan_AS923(); 00237 #elif CHANNEL_PLAN == CP_AS923_JAPAN 00238 plan = new lora::ChannelPlan_AS923_Japan(); 00239 #elif CHANNEL_PLAN == CP_IN865 00240 plan = new lora::ChannelPlan_IN865(); 00241 #endif 00242 assert(plan); 00243 00244 dot = mDot::getInstance(plan); 00245 assert(dot); 00246 00247 // attach the custom events handler 00248 dot->setEvents(&events); 00249 00250 if (!dot->getStandbyFlag()) { 00251 logInfo("mbed-os library version: %d.%d.%d", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION); 00252 00253 // start from a well-known state 00254 logInfo("defaulting Dot configuration"); 00255 dot->resetConfig(); 00256 dot->resetNetworkSession(); 00257 00258 // make sure library logging is turned on 00259 dot->setLogLevel(mts::MTSLog::INFO_LEVEL); 00260 00261 // update configuration if necessary 00262 if (dot->getJoinMode() != mDot::OTA) { 00263 logInfo("changing network join mode to OTA"); 00264 if (dot->setJoinMode(mDot::OTA) != mDot::MDOT_OK) { 00265 logError("failed to set network join mode to OTA"); 00266 } 00267 } 00268 // in OTA and AUTO_OTA join modes, the credentials can be passed to the library as a name and passphrase or an ID and KEY 00269 // only one method or the other should be used! 00270 // network ID = crc64(network name) 00271 // network KEY = cmac(network passphrase) 00272 //update_ota_config_name_phrase(network_name, network_passphrase, frequency_sub_band, network_type, ack); 00273 update_ota_config_id_key(network_id, network_key, frequency_sub_band, network_type, ack); 00274 00275 // configure network link checks 00276 // network link checks are a good alternative to requiring the gateway to ACK every packet and should allow a single gateway to handle more Dots 00277 // check the link every count packets 00278 // declare the Dot disconnected after threshold failed link checks 00279 // for count = 3 and threshold = 5, the Dot will ask for a link check response every 5 packets and will consider the connection lost if it fails to receive 3 responses in a row 00280 update_network_link_check_config(3, 5); 00281 00282 // enable or disable Adaptive Data Rate 00283 dot->setAdr(adr); 00284 00285 // Configure the join delay 00286 dot->setJoinDelay(join_delay); 00287 00288 // save changes to configuration 00289 logInfo("saving configuration"); 00290 if (!dot->saveConfig()) { 00291 logError("failed to save configuration"); 00292 } 00293 00294 // display configuration 00295 display_config(); 00296 } else { 00297 // restore the saved session if the dot woke from deepsleep mode 00298 // useful to use with deepsleep because session info is otherwise lost when the dot enters deepsleep 00299 logInfo("restoring network session from NVM"); 00300 dot->restoreNetworkSession(); 00301 } 00302 00303 dot->setLogLevel(mts::MTSLog::DEBUG_LEVEL); 00304 TCA6424_init(); 00305 00306 while (true) { 00307 LED_D6(true); 00308 00309 00310 LED_D5(true); 00311 // join network if not joined 00312 if (!dot->getNetworkJoinStatus()) { 00313 join_network(); 00314 } 00315 LED_D5(false); 00316 00317 LED_D4(true); 00318 // Read Sensor Data and Upload it to gateway 00319 // mts::MTSLog::setLogLevel(mts::MTSLog::DEBUG_LEVEL); // enable debug log 00320 // ReadBatteryLevelAndSend(); 00321 ReadRS485SensorAndSend(); 00322 LED_D4(false); 00323 00324 // if going into deepsleep mode, save the session so we don't need to join again after waking up 00325 // not necessary if going into sleep mode since RAM is retained 00326 if (deep_sleep) { 00327 logInfo("saving network session to NVM"); 00328 dot->saveNetworkSession(); 00329 } 00330 00331 LED_D6(false); 00332 00333 // ONLY ONE of the three functions below should be uncommented depending on the desired wakeup method 00334 //sleep_wake_rtc_only(deep_sleep); 00335 //sleep_wake_interrupt_only(deep_sleep); 00336 sleep_wake_rtc_or_interrupt(deep_sleep); 00337 } 00338 00339 return 0; 00340 } 00341 00342 #endif
Generated on Wed Jul 13 2022 00:37:31 by
1.7.2