MTDOT-EVB link check code for site survey
Dependencies: DOGS102 GpsParser MTS-Serial NCP5623B libmDot mbed-rtos mbed
main.cpp
- Committer:
- mfiore
- Date:
- 2015-10-27
- Revision:
- 2:b197488a50dc
- Parent:
- 1:4e3ee9c860e3
File content as of revision 2:b197488a50dc:
/** * @file main.cpp * @brief Main application for mDot-EVB Automated Link Check demo * @author Tim Barr MultiTech Systems Inc. * @version 1.02 * @see * * Copyright (c) 2015 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * 1.00 TAB 10/22/15 Copied from MDOT-EVB-LinkCheck version 1.02. * Added mutex around certain mDot radio commands. * Moved ping check code to callable function. Added sweep * mode, re-wrote join code, and modified button operation * Fixed error in Downlink QOS SNR display. */ #include "mbed.h" #include "NCP5623B.h" #include "DOGS102.h" #include "font_6x8.h" #include "MultiTech_Logo.h" #include "mDot.h" #include "rtos.h" #include "GPSPARSER.h" #include "MTSSerial.h" #include <string> #include <vector> #include <ctime> enum LED1_COLOR { RED = 0, GREEN = 1 }; /* * union for converting from 32-bit to 4 8-bit values */ union convert32 { int32_t f_s; // convert from signed 32 bit int uint32_t f_u; // convert from unsigned 32 bit int uint8_t t_u[4]; // convert to 8 bit unsigned array }; /* * union for converting from 16- bit to 2 8-bit values */ union convert16 { int16_t f_s; // convert from signed 16 bit int uint16_t f_u; // convert from unsigned 16 bit int uint8_t t_u[2]; // convert to 8 bit unsigned array }; //DigitalIn mDot02(PA_2); // GPIO/UART_TX //DigitalOut mDot03(PA_3); // GPIO/UART_RX //DigitalIn mDot04(PA_6); // GPIO/SPI_MISO //DigitalIn mDot06(PA_8); // GPIO/I2C_SCL //DigitalIn mDot07(PC_9); // GPIO/I2C_SDA InterruptIn mDot08(PA_12); // GPIO/USB PB S1 on EVB InterruptIn mDot09(PA_11); // GPIO/USB PB S2 on EVB //DigitalIn mDot11(PA_7); // GPIO/SPI_MOSI InterruptIn mDot12(PA_0); // GPIO/UART_CTS PRESSURE_INT2 on EVB DigitalOut mDot13(PC_13,1); // GPIO LCD_C/D InterruptIn mDot15(PC_1); // GPIO LIGHT_PROX_INT on EVB InterruptIn mDot16(PA_1); // GPIO/UART_RTS ACCEL_INT2 on EVB DigitalOut mDot17(PA_4,1); // GPIO/SPI_NCS LCD_CS on EVB //DigitalIn mDot18(PA_5); // GPIO/SPI_SCK //DigitalInOut mDot19(PB_0,PIN_INPUT,PullNone,0); // GPIO PushPull LED Low=Red High=Green set MODE=INPUT to turn off AnalogIn mDot20(PB_1); // GPIO Current Sense Analog in on EVB Serial debugUART(PA_9, PA_10); // mDot debug UART MTSSerial mDotUART(PA_2,PA_3); // mDot external UART mDot02 and mDot03 I2C mDoti2c(PC_9,PA_8); // mDot External I2C mDot6 and mDot7 SPI mDotspi(PA_7,PA_6,PA_5); // mDot external SPI mDot11, mDot4, and mDot18 /* **** replace these values with the proper public or private network settings **** * config_network_nameand config_network_pass are for private networks. */ static std::string config_network_name = "TAB-CubeNet"; static std::string config_network_pass = "1nt3gral"; //static std::string config_network_name = "Arclight"; //static std::string config_network_pass = "default1"; static uint8_t config_frequency_sub_band = 5; //static std::string config_network_name = "GregCDT8"; //static std::string config_network_pass = "myAEP8chars"; //static uint8_t config_frequency_sub_band = 1; /* config_app_id and config_app_key are for public networks. static uint8_t app_id[8] = {0x00,0x01,0x02,0x03,0x0A,0x0B,0x0C,0x0D}; std::vector<uint8_t> config_app_id; static uint8_t app_key[16] = {0x00,0x01,0x02,0x03,0x0A,0x0B,0x0C,0x0D}; std::vector<uint8_t> config_app_key; */ uint8_t result; uint8_t data; uint8_t sf_val = mDot::SF_7; uint8_t pwr_val = 11; // dBm uint8_t swp_pwr; uint8_t swp_sf; const uint8_t sweep_table [2][4] = { { 11, 14, 18, 20}, {mDot::SF_7, mDot::SF_8, mDot::SF_9, mDot::SF_10} }; // max size of text string for 6x8 font. Set to 12 if using 8x8 font char txtstr[17]; int32_t mdot_ret; int32_t join_delay; osThreadId mainThreadID; // flags for push button debounce code bool pb1_low = false; bool pb2_low = false; bool toggle_text = false; bool main_single = false; bool main_sweep = false; NCP5623B* evbBackLight; DOGS102* evbLCD; mDot* mdot_radio; Mutex mdot_mutex; GPSPARSER* mdot_gps; convert32 convertL; convert16 convertS; void pb1ISR(void); void pb2ISR(void); void pb1_debounce(void const *args); void pb2_debounce(void const *args); void log_error(mDot* dot, const char* msg, int32_t retval); uint8_t ping_check(uint8_t set_pwr, uint8_t set_sf, uint8_t pings_per_check = 1); int main() { std::vector<uint8_t> mdot_EUI; uint16_t i = 0; // Number of ping attempts per Radio setting set here uint8_t number_of_pings = 5; debugUART.baud(115200); printf ("Start program \r\n"); Thread thread_1(pb1_debounce); Thread thread_2(pb2_debounce); printf("Thread init done\r\n"); mainThreadID = osThreadGetId(); printf("Device init start\r\n"); evbBackLight = new NCP5623B(mDoti2c); // setup backlight and LED 2 driver chip evbLCD = new DOGS102(mDotspi, mDot17, mDot13); // setup LCD printf ("Devices init done\r\n"); /* * Setup SW1 as Data rate and power out select */ mDot08.disable_irq(); mDot08.fall(&pb1ISR); /* * need to call this function after rise or fall because rise/fall sets * mode to PullNone */ mDot08.mode(PullUp); mDot08.enable_irq(); /* * Setup SW2 as send PING */ mDot09.disable_irq(); mDot09.fall(&pb2ISR); /* * need to call this function after rise or fall because rise/fall sets * mode to PullNone */ mDot09.mode(PullUp); mDot09.enable_irq(); /* * Setting other InterruptIn pins with Pull Ups */ mDot12.mode(PullUp); mDot15.mode(PullUp); mDot16.mode(PullUp); printf("Switch IRQs set\r\n"); printf("font table address %p\r\n",&font_6x8); printf("bitmap address %p\r\n",&MultiTech_Logo); // Setup and display logo on LCD evbLCD->startUpdate(); evbLCD->writeBitmap(0,0,MultiTech_Logo); sprintf(txtstr,"MTDOT-EVB"); evbLCD->writeText(24,3,font_6x8,txtstr,strlen(txtstr)); sprintf(txtstr,"Link Check Demo"); evbLCD->writeText(6,4,font_6x8,txtstr,strlen(txtstr)); evbLCD->endUpdate(); printf("\r\n setup mdot\r\n"); // get a mDot handle mdot_radio = mDot::getInstance(); if (mdot_radio) { // reset to default config so we know what state we're in mdot_mutex.lock(); // lock mdot before setting configuration mdot_radio->resetConfig(); // Setting up LED1 as activity LED mdot_radio->setActivityLedPin(PB_0); mdot_radio->setActivityLedEnable(true); // Read node ID mdot_EUI = mdot_radio->getDeviceId(); printf("mDot EUI = "); for (i=0; i<mdot_EUI.size(); i++) { printf("%02x ", mdot_EUI[i]); } printf("\r\n"); // Setting up the mDot with network information. /* * This call sets up private or public mode on the MTDOT. Set the function to true if * connecting to a public network */ printf("setting Private Network Mode\r\n"); if ((mdot_ret = mdot_radio->setPublicNetwork(false)) != mDot::MDOT_OK) { log_error(mdot_radio, "failed to set Public Network Mode", mdot_ret); } /* * Frequency sub-band is valid for NAM only and for Private networks should be set to a value * between 1-8 that matches the the LoRa gateway setting. Public networks use sub-band 0 only. * This function can be commented out for EU networks */ printf("setting frequency sub band\r\n"); if ((mdot_ret = mdot_radio->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) { log_error(mdot_radio, "failed to set frequency sub band", mdot_ret); } /* * Setting TX power for radio. Max allowed is +14dBm for EU and +20 dBm for NAM. Default is +11 dBm */ printf("setting TX Power Level to %2d dBm\r\n", pwr_val); if ((mdot_ret = mdot_radio->setTxPower(pwr_val)) != mDot::MDOT_OK) { log_error(mdot_radio, "failed to set TX power level", mdot_ret); } /* * Setting TX data rate for radio. Max allowed is SF_12 for EU and SF10 dBm for NAM. Default is SF_10 */ printf("setting TX data rate to SF_7\r\n"); if ((mdot_ret = mdot_radio->setTxDataRate(sf_val)) != mDot::MDOT_OK) { log_error(mdot_radio, "failed to set TX data rate", mdot_ret); } sprintf(txtstr,"DR=%2d Pwr=%2d",(12 - sf_val),pwr_val); evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n",txtstr); /* * Setting packet ACK to 1 try. */ printf("setting Packet retry to 1\r\n"); if ((mdot_ret = mdot_radio->setAck(1)) != mDot::MDOT_OK) { log_error(mdot_radio, "failed to set packet retry\r\n", mdot_ret); } /* * setNetworkName is used for private networks. * Use setNetworkID(AppID) for public networks */ // config_app_id.assign(app_id,app_id+7); printf("setting network name\r\n"); if ((mdot_ret = mdot_radio->setNetworkName(config_network_name)) != mDot::MDOT_OK) { // if ((mdot_ret = mdot_radio->setNetworkID(config_app_id)) != mDot::MDOT_OK) { log_error(mdot_radio, "failed to set network name", mdot_ret); } /* * setNetworkPassphrase is used for private networks * Use setNetworkKey for public networks */ // config_app_key.assign(app_key,app_key+15); printf("setting network password\r\n"); if ((mdot_ret = mdot_radio->setNetworkPassphrase(config_network_pass)) != mDot::MDOT_OK) { // if ((mdot_ret = mdot_radio->setNetworkKey(config_app_key)) != mDot::MDOT_OK) { log_error(mdot_radio, "failed to set network password", mdot_ret); } mdot_mutex.unlock(); // unlock mdot mutex before join attempt so SW1 can work // attempt to join the network printf("joining network\r\n"); do { mdot_mutex.lock(); // lock mdot mutex before join attempt mdot_ret = mdot_radio->joinNetwork(); mdot_mutex.unlock(); // unlock mdot mutex after join attempt so SW1 can work if (mdot_ret != mDot::MDOT_OK) { log_error(mdot_radio,"failed to join network:", mdot_ret); if (toggle_text) sprintf(txtstr," > Join Failed <"); else sprintf(txtstr," < Join Failed >"); evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); if (mdot_radio->getFrequencyBand() == mDot::FB_868) { join_delay = mdot_radio->getNextTxMs(); } else { join_delay = 10; } printf("delay = %lu\r\n",join_delay); osDelay(join_delay + 1); toggle_text = !toggle_text; } /* * Setting TX power and Data Rate for radio just in case user requested by SW2 */ mdot_mutex.lock(); // lock mdot mutex before setting change mdot_radio->setTxPower(pwr_val); mdot_radio->setTxDataRate(sf_val); mdot_mutex.unlock(); // unlock mdot mutex after settings change so SW1 can work } while (mdot_ret != mDot::MDOT_OK); sprintf(txtstr,"*Network Joined*"); evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); } else { sprintf(txtstr,"Radio Init Failed!"); evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); printf("%s\r\n",txtstr); exit(1); } mdot_gps = new GPSPARSER(&mDotUART); if (!mdot_gps->gpsDetected()) { sprintf(txtstr,"*No GPS Detected*"); evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr)); printf ("%s\r\n", txtstr); } else { main_single = main_sweep = false; do { osSignalWait(0x10, 2000); if (mdot_gps->getLockStatus()) { sprintf(txtstr,"!!GPS locked!!"); evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n",txtstr); } else { if (toggle_text) sprintf(txtstr," > no GPS lock <"); else sprintf(txtstr," < no GPS lock >"); evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n",txtstr); toggle_text = !toggle_text; } } while ( !(mdot_gps->getLockStatus()) && (!main_single && !main_sweep)); } osDelay(200); evbBackLight->setPWM(NCP5623B::LED_3,16); // enable LED2 on EVB and set to 50% PWM // sets LED2 to 50% max current evbBackLight->setLEDCurrent(16); osDelay (500); // allows other threads to process printf("shutdown LED:\r\n"); evbBackLight->shutdown(); osDelay(500); /* * Main data acquisition loop */ i = 0; do { // Main program waits until SW2 is pressed. main_single = main_sweep = false; sprintf(txtstr,"Ready for Trigger"); evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); printf ("%s\r\n", txtstr); osSignalWait(0x10, osWaitForever); if (main_single) { evbLCD->clearBuffer(); sprintf(txtstr,"**Single Ping**"); evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr)); result = ping_check(pwr_val, sf_val); if (result != 0) printf("Ping check completed\r\n"); else printf("Ping check failed \r\n"); } else if (main_sweep) { evbLCD->clearBuffer(); sprintf(txtstr,"**Ping Sweep**"); evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr)); printf("start sweep and shutdown LED:\r\n"); evbBackLight->shutdown(); for (swp_pwr = 0; swp_pwr < 4; swp_pwr++) { for (swp_sf = 0; swp_sf < 4; swp_sf++) { result = ping_check(sweep_table[0][swp_pwr], sweep_table[1][swp_sf], number_of_pings); if (result != 0) printf("Ping check completed %d attempts\r\n", result); else printf("Ping check failed all attempts\r\n"); osDelay(1000); } } } else { printf("Got here because of code error.\r\n"); osDelay(1000); } } while(i < 1000); printf("End of Test\r\n"); evbLCD->clearBuffer(); sprintf(txtstr,"Exiting Program"); evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr)); } /* * Sets pb1_low flag. Flag is cleared in pb1_debounce thread */ void pb1ISR(void) { if (!pb1_low) pb1_low = true; } /* * Debounces pb1 PB1 changes spreading factor and output power * Cycles through SF_7-SF_10 for 4 power levels */ void pb1_debounce(void const *args) { static uint8_t count = 0; static uint8_t test_now = 0; while (true) { if (pb1_low && (mDot08 == 0)) count++; else { count = 0; pb1_low = false; } if (count == 5) { test_now++; if (test_now > 15) // resets test_now test_now = 0; // selects power output level using upper bits for select switch(test_now >> 2) { case 0: pwr_val = 11; break; case 1: pwr_val = 14; break; case 2: pwr_val = 18; break; case 3: pwr_val = 20; } // sets data rate based on lower bits sf_val = mDot::SF_7 - (test_now & 0x03); sprintf(txtstr,"DR=%2d Pwr=%2d ",(12 - sf_val),pwr_val); evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n",txtstr); } Thread::wait(5); } } /* * Sets pb2_low flag. Flag is cleared in pb2_debounce thread */ void pb2ISR(void) { if (!pb2_low) pb2_low = true; } /* * Debounces pb2 PB2 forces main program out of thread wait mode */ void pb2_debounce(void const *args) { static uint8_t count = 0; while (true) { if (pb2_low && (mDot09 == 0)) { count++; if (count == 100) { // sets LED2 to 50% max current evbBackLight->setPWM(NCP5623B::LED_3,16); // enable LED2 on EVB and set to 50% PWM evbBackLight->setLEDCurrent(16); } } else { if ((count > 5) && (count <= 100)) { main_single = true; osSignalSet(mainThreadID, 0x10); } else if (count > 100) { main_sweep = true; osSignalSet(mainThreadID, 0x10); } count = 0; pb2_low = false; } Thread::wait(5); } } /* * Function that print clear text verion of mDot errors */ void log_error(mDot* dot, const char* msg, int32_t retval) { printf("%s - %ld:%s, %s\r\n", msg, retval, mDot::getReturnCodeString(retval).c_str(), dot->getLastError().c_str()); } // return = number of ping checks that passed uint8_t ping_check(uint8_t set_pwr, uint8_t set_sf, uint8_t pings_per_check) { uint8_t result = 0; uint8_t ping_cnt; mDot::ping_response ping_data; mDot::rssi_stats rssi_data; mDot::snr_stats snr_data; struct tm gps_timestamp; GPSPARSER::longitude evb_longitude; GPSPARSER::latitude evb_latitude; GPSPARSER::satellite_prn gps_sat_prn; uint8_t gps_fix_quality; int16_t evb_altitude; uint8_t gps_num_satellites; uint8_t gps_fix_status; std::vector<uint8_t> mdot_data; mdot_mutex.lock(); // lock mdot mutex before changing radio parameters if ((mdot_ret = mdot_radio->setTxPower(set_pwr)) != mDot::MDOT_OK) { log_error(mdot_radio, "failed to set TX power level", mdot_ret); } if ((mdot_ret = mdot_radio->setTxDataRate(set_sf)) != mDot::MDOT_OK) { log_error(mdot_radio, "failed to set DataRate value", mdot_ret); } mdot_mutex.unlock(); // unlock mdot mutex after changing radio parameters for (ping_cnt = 0; ping_cnt < pings_per_check; ping_cnt++) { evbLCD->startUpdate(); evbLCD->clearBuffer(); mdot_mutex.lock(); // lock mdot mutex before ping ping_data = mdot_radio->ping(); mdot_mutex.unlock(); // unlock mdot mutex after ping if (ping_data.status == mDot::MDOT_OK) { rssi_data = mdot_radio->getRssiStats(); snr_data = mdot_radio->getSnrStats(); gps_fix_status = mdot_gps->getFixStatus(); gps_fix_quality = mdot_gps->getFixQuality(); gps_num_satellites = mdot_gps->getNumSatellites(); printf ("\r\n GPS Fix Status= %d num of sats = %d\r\n", gps_fix_status, gps_num_satellites); sprintf(txtstr,"PGOOD DR=%2d P=%2d",(12 - set_sf),set_pwr); evbLCD->writeText(0,0,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n",txtstr); sprintf(txtstr,"UP %3d dBm %2d.%1d",ping_data.rssi, ping_data.snr/10, abs(ping_data.snr)%10); evbLCD->writeText(0,1,font_6x8,txtstr,strlen(txtstr)); printf("Link Quality %s \r\n",txtstr); sprintf(txtstr,"DWN %3d dBm %2d.%02d",rssi_data.last, snr_data.last/4, abs(snr_data.last)%4*25); evbLCD->writeText(0,2,font_6x8,txtstr,strlen(txtstr)); printf("Link Quality %s \r\n",txtstr); mdot_data.clear(); mdot_data.push_back(0x1D); // key for start of data structure mdot_data.push_back(0x1A); // key for uplink QOS + RF Pwr convertS.f_s = ping_data.rssi; mdot_data.push_back(convertS.t_u[1]); mdot_data.push_back(convertS.t_u[0]); mdot_data.push_back((ping_data.snr/10) & 0xFF); mdot_data.push_back(set_pwr); mdot_data.push_back(0x1B); // key for downlink QOS convertS.f_s=rssi_data.last; mdot_data.push_back(convertS.t_u[1]); mdot_data.push_back(convertS.t_u[0]); mdot_data.push_back(snr_data.last); // collect GPS data if GPS device detected if (mdot_gps->gpsDetected() && (set_sf != mDot::SF_10)) { mdot_data.push_back(0x19); // key for GPS Lock Status data = ( gps_num_satellites << 4 ) | ( gps_fix_status & 0x0F ); mdot_data.push_back(data); if (mdot_gps->getLockStatus()) { // if gps has a lock evb_longitude = mdot_gps->getLongitude(); evb_latitude = mdot_gps->getLatitude(); evb_altitude = mdot_gps->getAltitude(); gps_timestamp = mdot_gps->getTimestamp(); sprintf(txtstr,"%3d %2d %2d.%03d",abs(evb_longitude.degrees),evb_longitude.minutes,(evb_longitude.seconds*6)/1000,(evb_longitude.seconds*6)%1000); if (evb_longitude.degrees < 0) strncat(txtstr," W",2); else strncat(txtstr," E",2); evbLCD->writeText(0,3,font_6x8,txtstr,strlen(txtstr)); printf("Longitude: %s \r\n",txtstr); sprintf(txtstr,"%3d %2d %2d.%03d",abs(evb_latitude.degrees),evb_latitude.minutes,(evb_latitude.seconds*6)/1000,(evb_latitude.seconds*6)%1000); if (evb_latitude.degrees < 0) strncat(txtstr," S",2); else strncat(txtstr," N",2); evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr)); printf("Latitude: %s \r\n",txtstr); sprintf(txtstr,"Time %02d:%02d:%02d ",gps_timestamp.tm_hour,gps_timestamp.tm_min,gps_timestamp.tm_sec); evbLCD->writeText(0,5,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n",txtstr); sprintf(txtstr,"Date %02d/%02d/%04d",gps_timestamp.tm_mon + 1,gps_timestamp.tm_mday,gps_timestamp.tm_year +1900); evbLCD->writeText(0,6,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n\r\n",txtstr); // Send GPS data if GSP device locked mdot_data.push_back(0x15); // key for GPS Latitude mdot_data.push_back(evb_latitude.degrees); mdot_data.push_back(evb_latitude.minutes); convertS.f_s = evb_latitude.seconds; mdot_data.push_back(convertS.t_u[1]); mdot_data.push_back(convertS.t_u[0]); mdot_data.push_back(0x16); // key for GPS Longitude convertS.f_s = evb_longitude.degrees; mdot_data.push_back(convertS.t_u[1]); mdot_data.push_back(convertS.t_u[0]); mdot_data.push_back(evb_longitude.minutes); convertS.f_s = evb_longitude.seconds; mdot_data.push_back(convertS.t_u[1]); mdot_data.push_back(convertS.t_u[0]); } else { sprintf(txtstr,"no GPS lock"); evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n",txtstr); } } // key for end of data structure mdot_data.push_back(0x1D); // if SF_10 this sends 11 bytes of data, otherwise sends full data packet mdot_mutex.lock(); // lock mdot mutex before packet send mdot_ret = mdot_radio->send(mdot_data); mdot_mutex.unlock(); // unlock mdot mutex after packet send if (mdot_ret != mDot::MDOT_OK) { sprintf(txtstr,"mDot Send failed"); evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); log_error(mdot_radio, txtstr, mdot_ret); } else { sprintf(txtstr,"mDot Send success"); evbLCD->writeText(0,7,font_6x8,txtstr,strlen(txtstr)); printf("successfully sent data to gateway\r\n"); result++; } } else { sprintf(txtstr,"Ping Check Failed"); evbLCD->writeText(0,2,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n",txtstr); sprintf(txtstr,"DR=%2d P=%2d",(12 - set_sf),set_pwr); evbLCD->writeText(0,3,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n",txtstr); strncpy(txtstr,mDot::getReturnCodeString(ping_data.status).c_str(),17); evbLCD->writeText(0,4,font_6x8,txtstr,strlen(txtstr)); printf("%s \r\n",txtstr); } evbLCD->endUpdate(); osDelay(1000); } return result; }