lorawan-ed-test-shell.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135
  1. /*
  2. * Copyright (c) 2006-2020, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * forest-rain
  9. */
  10. /* Includes ------------------------------------------------------------------*/
  11. #include <rtthread.h>
  12. #include <board.h>
  13. #include "lorawan-ed-aps.h"
  14. #define DBG_LVL DBG_INFO
  15. #define LOG_TAG "LORAWAN.APP"
  16. #include "lorawan-ed-debug.h"
  17. /* Private typedef -----------------------------------------------------------*/
  18. /* Private define ------------------------------------------------------------*/
  19. /* Private macro -------------------------------------------------------------*/
  20. #define LORAWAN_MAX_BAT 254
  21. /*!
  22. * CAYENNE_LPP is myDevices Application server.
  23. */
  24. //#define CAYENNE_LPP
  25. #define LPP_DATATYPE_DIGITAL_INPUT 0x00
  26. #define LPP_DATATYPE_DIGITAL_OUTPUT 0x01
  27. #define LPP_DATATYPE_HUMIDITY 0x68
  28. #define LPP_DATATYPE_TEMPERATURE 0x67
  29. #define LPP_DATATYPE_BAROMETER 0x73
  30. #define LPP_APP_PORT 99
  31. /*!
  32. * Defines the application data join duty cycle. 10s, value in [ms].
  33. */
  34. #define APP_JOIN_DUTYCYCLE 10000
  35. /*!
  36. * Defines the application data transmission duty cycle. 5s, value in [ms].
  37. */
  38. #define APP_TX_DUTYCYCLE 5000
  39. /*!
  40. * Defines the ping transmission duty cycle. 3s, value in [ms].
  41. */
  42. #define PING_TX_DUTYCYCLE 3000
  43. /*!
  44. * Defines the application data transmission random. 5s, value in [ms].
  45. */
  46. #define APP_TX_DUTYCYCLE_RANDOM 5000
  47. /*!
  48. * User application data buffer size
  49. */
  50. #define LORAWAN_ED_APP_DATA_BUFF_SIZE 64
  51. /*!
  52. * User application demo fport
  53. */
  54. #define LORAWAN_ED_APP_DEMO_FPORT 3
  55. #define LED_Toggle( x )
  56. #define LED_On( x )
  57. #define LED_Off( x )
  58. // lorawan application event
  59. #define EV_LORAWAN_APL_START_JOIN_NETWORK 0x0001
  60. #define EV_LORAWAN_APL_REJOIN_NETWORK 0x0002
  61. #define EV_LORAWAN_APL_PERIODIC_TX_DATA 0x0004
  62. #define EV_LORAWAN_APL_MAC_PROCESS_NOTIFY 0x8000
  63. /* event control */
  64. static struct rt_event ev_lorawan_apl;
  65. static struct rt_thread lorwan_ed_test_shell_thread;
  66. static rt_uint8_t rt_lorwan_ed_test_shell_thread_stack[4096];
  67. /*!
  68. * User application data
  69. */
  70. static uint8_t lorawan_ed_app_data_buff[LORAWAN_ED_APP_DATA_BUFF_SIZE];
  71. /* Private function prototypes -----------------------------------------------*/
  72. /* callback when LoRaWAN End-Device has received a frame*/
  73. static void lorawan_ed_receive_message(lorawan_ed_appdata_t *lorawan_ed_app_data);
  74. /* callback when LoRaWAN End-Device has received a linkcheck ans*/
  75. static void lorawan_ed_receive_linkcheck(MlmeConfirm_t *mlmeConfirm);
  76. /* callback when LoRaWAN End-Device has just joined*/
  77. static void lorawan_ed_joined(void);
  78. static void lorawan_ed_tx_confirm(McpsConfirm_t *mcpsConfirm);
  79. /* callback when LoRaWAN End-Device has just switch the class*/
  80. static void lorawan_ed_confirm_device_class(DeviceClass_t Class);
  81. /* callback when server needs End-Device to send a frame */
  82. static void lorawan_ed_tx_dummy(void);
  83. /* LoRaWAN class a ping test */
  84. static lorawan_ed_error_status_t lorawan_ed_tx_ping_packet(uint8_t len);
  85. /* callback to get the battery level in % of full charge (254 full charge, 0 no charge)*/
  86. static uint8_t lorawan_ed_get_battery_level(void);
  87. /* tx timer callback function*/
  88. static void on_tx_timer_event(void);
  89. /* Private variables ---------------------------------------------------------*/
  90. /*!
  91. * Specifies the state of the application LED
  92. */
  93. static uint8_t app_led_state_on = RESET;
  94. static TimerEvent_t TxTimer;
  95. static uint32_t app_tx_period = APP_TX_DUTYCYCLE;
  96. // ping statistics
  97. static bool ping_test_flag = false;
  98. static uint8_t payload_len = 32;
  99. static uint32_t tx_seq_cnt = 0;
  100. static uint16_t max_tx_nbtrials = 10;
  101. static uint32_t rx_correct_cnt = 0;
  102. static int16_t rssi_value = -255;
  103. static int16_t rssi_value_min = -255;
  104. static int16_t rssi_value_max = -255;
  105. static int32_t rssi_value_total = 0;
  106. static int8_t snr_value = -128;
  107. static int8_t snr_value_min = -128;
  108. static int8_t snr_value_max = -128;
  109. static int32_t snr_value_total = 0;
  110. static int8_t gw_demod_margin_value = -128;
  111. static int8_t gw_demod_margin_value_min = -128;
  112. static int8_t gw_demod_margin_value_max = -128;
  113. static int32_t gw_demod_margin_value_total = 0;
  114. static uint8_t gw_received_nb;
  115. static uint32_t tx_timestamp;
  116. static uint32_t rx_timestamp;
  117. uint32_t tx_total_byte;
  118. uint32_t rx_total_byte;
  119. /* Public variables ---------------------------------------------------------*/
  120. /*!
  121. * User application data structure
  122. */
  123. lorawan_ed_appdata_t lorawan_ed_app_data = { lorawan_ed_app_data_buff, 32, LORAWAN_ED_STACK_MAC_PARAMETER_APPLICATION_FPORT };
  124. /* LoRaWAN End-Device app callbacks structure*/
  125. lorawan_ed_app_callback_t lorawan_ed_user_app_callback =
  126. {
  127. lorawan_ed_get_battery_level,
  128. NULL,//GetTemperatureLevel,
  129. lorawan_ed_joined,
  130. lorawan_ed_tx_confirm,
  131. lorawan_ed_receive_message,
  132. lorawan_ed_receive_linkcheck,
  133. lorawan_ed_confirm_device_class,
  134. lorawan_ed_tx_dummy,
  135. #ifndef LORAWAN_ED_STACK_USING_ON_RTOS_RT_THREAD
  136. NULL//LoraMacProcessNotify
  137. #endif
  138. };
  139. /* Initialize the LoRaWAN End-Device Parameters */
  140. lorawan_ed_params_t lorawan_ed_init_params_default =
  141. {
  142. 0,
  143. CLASS_A,
  144. LORAWAN_ED_ACTIVATION_TYPE_OTAA,
  145. LORAWAN_ED_DATA_MESSAGE_TYPE_UNCONFIRMED,
  146. 1, /* ADR ON */
  147. 5, /* DR5( SF7 BW125 ) */
  148. 1 /* Public */
  149. };
  150. lorawan_ed_params_t lorawan_ed_init_params =
  151. {
  152. 0,/* nvm flag loaded from NVM */
  153. LORAWAN_ED_STACK_MAC_PARAMETER_DEVICE_TYPE,
  154. LORAWAN_ED_STACK_MAC_PARAMETER_ACTIVATION_TYPE,
  155. LORAWAN_ED_STACK_MAC_PARAMETER_DATA_MESSAGE_TYPE,
  156. LORAWAN_ED_STACK_MAC_PARAMETER_ADR,
  157. LORAWAN_ED_STACK_PHY_PARAMETER_DEFAULT_DATARATE,
  158. LORAWAN_ED_STACK_MAC_PARAMETER_LORAWAN_NETWORK_ATTRIBUTE
  159. };
  160. /* Public functions ---------------------------------------------------------*/
  161. /**
  162. * @brief lorawan_ed_app_thread_entry
  163. * @param void * parameter
  164. * @retval None
  165. */
  166. void lorawan_ed_app_thread_entry(void* parameter)
  167. {
  168. rt_uint32_t ev;
  169. LORAWAN_ED_DEBUG_LOG(LORAWAN_ED_STACK_DEBUG_APP, DBG_LVL, "LORAMAC_VERSION= %02X.%02X.%02X.%02X\r\n", (uint8_t)(__LORA_MAC_VERSION >> 24), (uint8_t)(__LORA_MAC_VERSION >> 16), (uint8_t)(__LORA_MAC_VERSION >> 8), (uint8_t)__LORA_MAC_VERSION);
  170. rt_event_init(&ev_lorawan_apl, "ev_lorawan_apl", RT_IPC_FLAG_PRIO);//RT_IPC_FLAG_FIFO);
  171. while (1)
  172. {
  173. if (rt_event_recv(&ev_lorawan_apl, (EV_LORAWAN_APL_START_JOIN_NETWORK |
  174. EV_LORAWAN_APL_REJOIN_NETWORK |
  175. EV_LORAWAN_APL_PERIODIC_TX_DATA),
  176. ( RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR ),
  177. RT_WAITING_FOREVER, &ev) == RT_EOK)
  178. {
  179. if (ev == EV_LORAWAN_APL_START_JOIN_NETWORK)
  180. {
  181. uint32_t start_join_timestamp = app_tx_period + randr(-APP_TX_DUTYCYCLE_RANDOM, APP_TX_DUTYCYCLE_RANDOM);
  182. LORAWAN_ED_DEBUG_LOG(LORAWAN_ED_STACK_DEBUG_APP, DBG_LVL,
  183. "After Random Delay(%d ms),Start to Join Network.", start_join_timestamp);
  184. TimerSetValue(&TxTimer, start_join_timestamp);
  185. TimerStart(&TxTimer);
  186. }
  187. else if (ev == EV_LORAWAN_APL_REJOIN_NETWORK)
  188. {
  189. /* Not joined, try again later */
  190. lorawan_ed_start_join_network();
  191. }
  192. else if (ev == EV_LORAWAN_APL_PERIODIC_TX_DATA)
  193. {
  194. /* Triggle for next tx slot */
  195. TimerSetValue(&TxTimer, app_tx_period);
  196. TimerStart(&TxTimer);
  197. if (ping_test_flag)
  198. {
  199. /* for first time of printf info */
  200. if (!tx_seq_cnt)
  201. {
  202. rt_kprintf("Pinging with %d bytes of data for %d counters:", payload_len, max_tx_nbtrials);
  203. }
  204. lorawan_ed_tx_ping_packet(payload_len);
  205. }
  206. else
  207. {
  208. lorawan_ed_send(&lorawan_ed_app_data);
  209. }
  210. tx_seq_cnt++;
  211. }
  212. }
  213. }
  214. }
  215. /* Private functions ---------------------------------------------------------*/
  216. static void lorawan_ed_joined(void)
  217. {
  218. lorawan_ed_request_device_class((DeviceClass_t)lorawan_ed_init_params.Class);
  219. }
  220. static void lorawan_ed_tx_confirm(McpsConfirm_t *mcpsConfirm)
  221. {
  222. }
  223. static void lorawan_ed_receive_message(lorawan_ed_appdata_t *app_data)
  224. {
  225. #ifdef LORAWAN_ED_STACK_DEBUG_APP_DATA_CONFIG
  226. if(app_data->BuffSize)
  227. {
  228. LORAWAN_ED_DEBUG_LOG(LORAWAN_ED_STACK_DEBUG_APP_DATA, DBG_LVL,"[App Payload(%d)]:",app_data->BuffSize);
  229. for( uint8_t i = 0; i < app_data->BuffSize; i++ )
  230. {
  231. LORAWAN_ED_DEBUG_LOG_RAW(LORAWAN_ED_STACK_DEBUG_APP_DATA, " %02X",app_data->Buff[i]);
  232. }
  233. LORAWAN_ED_DEBUG_LOG_RAW(LORAWAN_ED_STACK_DEBUG_APP_DATA, "\r\n");
  234. }
  235. #endif
  236. switch (app_data->Port)
  237. {
  238. case LORAWAN_ED_APP_DEMO_FPORT:
  239. {
  240. /* this port switches the class */
  241. if (app_data->BuffSize == 1)
  242. {
  243. switch (app_data->Buff[0])
  244. {
  245. case 0:
  246. {
  247. lorawan_ed_request_device_class(CLASS_A);
  248. break;
  249. }
  250. case 1:
  251. {
  252. lorawan_ed_request_device_class(CLASS_B);
  253. break;
  254. }
  255. case 2:
  256. {
  257. lorawan_ed_request_device_class(CLASS_C);
  258. break;
  259. }
  260. default:
  261. break;
  262. }
  263. }
  264. break;
  265. }
  266. case LORAWAN_ED_STACK_MAC_PARAMETER_APPLICATION_FPORT:
  267. {
  268. if ( app_data->BuffSize == 1 )
  269. {
  270. app_led_state_on = app_data->Buff[0] & 0x01;
  271. if (app_led_state_on == RESET)
  272. {
  273. LORAWAN_ED_DEBUG_LOG(LORAWAN_ED_STACK_DEBUG_APP, DBG_LVL, "LED OFF\r\n", app_data->Port);
  274. LED_Off(LED_BLUE) ;
  275. }
  276. else
  277. {
  278. LORAWAN_ED_DEBUG_LOG(LORAWAN_ED_STACK_DEBUG_APP, DBG_LVL, "LED ON\r\n", app_data->Port);
  279. LED_On(LED_BLUE) ;
  280. }
  281. }
  282. break;
  283. }
  284. case LPP_APP_PORT:
  285. {
  286. app_led_state_on = (app_data->Buff[2] == 100) ? 0x01 : 0x00;
  287. if (app_led_state_on == RESET)
  288. {
  289. LORAWAN_ED_DEBUG_LOG(LORAWAN_ED_STACK_DEBUG_APP, DBG_LVL, "LED OFF\r\n", app_data->Port);
  290. LED_Off(LED_BLUE) ;
  291. }
  292. else
  293. {
  294. LORAWAN_ED_DEBUG_LOG(LORAWAN_ED_STACK_DEBUG_APP, DBG_LVL, "LED ON\r\n", app_data->Port);
  295. LED_On(LED_BLUE) ;
  296. }
  297. break;
  298. }
  299. default:
  300. /* receive MAC ACK only */
  301. if( ping_test_flag )
  302. {
  303. rx_correct_cnt++;
  304. rssi_value = app_data->Rssi;
  305. snr_value = app_data->Snr;
  306. /* only used for first rx */
  307. if( rssi_value_max == -255 )
  308. {
  309. rssi_value_min = rssi_value_max = app_data->Rssi;
  310. }
  311. if( snr_value_max == -128 )
  312. {
  313. snr_value_min = snr_value_max = app_data->Snr;
  314. }
  315. /* update max and min */
  316. if( rssi_value < rssi_value_min )
  317. {
  318. rssi_value_min = rssi_value;
  319. }
  320. else if( rssi_value > rssi_value_max )
  321. {
  322. rssi_value_max = rssi_value;
  323. }
  324. if( snr_value < snr_value_min )
  325. {
  326. snr_value_min = snr_value;
  327. }
  328. else if( snr_value > rssi_value_max )
  329. {
  330. snr_value_max = snr_value;
  331. }
  332. rssi_value_total += rssi_value;
  333. snr_value_total += snr_value;
  334. rx_total_byte += app_data->BuffSize + LORA_MAC_FRMPAYLOAD_OVERHEAD;
  335. rt_kprintf("Reply from Server:seqno=%d, dn_fcnt=%d, bytes=%d, Total time=%d ms, ed_rssi=%d, ed_snr=%d, gw_demod_margin=%d, gw_received_nb=%d\r\n",
  336. tx_seq_cnt, app_data->DownLinkCounter, app_data->BuffSize + LORA_MAC_FRMPAYLOAD_OVERHEAD,( rx_timestamp - tx_timestamp ), app_data->Rssi, app_data->Snr, gw_demod_margin_value, gw_received_nb);
  337. }
  338. break;
  339. }
  340. }
  341. static void lorawan_ed_receive_linkcheck(MlmeConfirm_t *mlmeConfirm)
  342. {
  343. if( ping_test_flag )
  344. {
  345. rx_timestamp = TimerGetCurrentTime();
  346. if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
  347. {
  348. gw_demod_margin_value = mlmeConfirm->DemodMargin;
  349. gw_received_nb = mlmeConfirm->NbGateways;
  350. /* only used for first rx */
  351. if( gw_demod_margin_value_max == -128 )
  352. {
  353. gw_demod_margin_value_min = gw_demod_margin_value_max = mlmeConfirm->DemodMargin;
  354. }
  355. /* update max and min */
  356. if( gw_demod_margin_value < gw_demod_margin_value_min )
  357. {
  358. gw_demod_margin_value_min = gw_demod_margin_value;
  359. }
  360. else if( rssi_value > gw_demod_margin_value_max )
  361. {
  362. gw_demod_margin_value_max = gw_demod_margin_value;
  363. }
  364. gw_demod_margin_value_total += gw_demod_margin_value;
  365. }
  366. else
  367. {
  368. rt_kprintf("Request Server timed out: seqno=%d, time=%d ms\r\n", tx_seq_cnt, ( rx_timestamp - tx_timestamp ) );
  369. }
  370. }
  371. }
  372. static void on_tx_timer_event(void)
  373. {
  374. TimerStop(&TxTimer);
  375. if ( lorawan_ed_join_status() == LORAWAN_ED_NOT_JOIN_NETWORK )
  376. {
  377. if( app_tx_period )
  378. {
  379. rt_event_send(&ev_lorawan_apl, EV_LORAWAN_APL_REJOIN_NETWORK);
  380. }
  381. }
  382. else
  383. {
  384. /* tx_seq_cnt start from 0 */
  385. if( tx_seq_cnt < max_tx_nbtrials || max_tx_nbtrials == 0 )
  386. {
  387. if( app_tx_period )
  388. {
  389. rt_event_send(&ev_lorawan_apl, EV_LORAWAN_APL_PERIODIC_TX_DATA);
  390. }
  391. }
  392. else
  393. {
  394. if( ping_test_flag )
  395. {
  396. uint16_t per = 100 - ( (float) rx_correct_cnt / tx_seq_cnt ) * 100;
  397. tx_total_byte = tx_seq_cnt * ( payload_len + LORA_MAC_FRMPAYLOAD_OVERHEAD );
  398. uint32_t tx_total_kbyte_integer = tx_total_byte >> 10; // / 1024
  399. uint32_t tx_total_kbyte_decimal = tx_total_byte & 0x3FF; // % 1024
  400. uint32_t rx_total_kbyte_integer = rx_total_byte >> 10; // / 1024
  401. uint32_t rx_total_kbyte_decimal = rx_total_byte & 0x3FF; // % 1024
  402. int32_t avg_ed_rssi = -255;
  403. int32_t avg_ed_snr = -128;
  404. int32_t avg_gw_demod_margin = -128;
  405. if( rx_correct_cnt )
  406. {
  407. avg_ed_rssi = rssi_value_total / (int32_t)rx_correct_cnt;
  408. avg_ed_snr = snr_value_total / (int32_t)rx_correct_cnt;
  409. avg_gw_demod_margin = gw_demod_margin_value_total / (int32_t)rx_correct_cnt;
  410. }
  411. rt_kprintf("\r\n====== LoRaWAN End-Device Ping statistics: ======\r\n");
  412. rt_kprintf("-> Tx pakcets: sent = %d, tx_total = %d.%d KByte\r\n",tx_seq_cnt, tx_total_kbyte_integer, tx_total_kbyte_decimal);
  413. rt_kprintf("-> Rx pakcets: received = %d, lost = %d, per = %d%, rx_total = %d.%d KByte\r\n",rx_correct_cnt, tx_seq_cnt - rx_correct_cnt, per,rx_total_kbyte_integer,rx_total_kbyte_decimal);
  414. rt_kprintf("--> End-Device Rx rssi: max_rssi = %d, min_rssi = %d, avg_rssi = %d\r\n",rssi_value_max,rssi_value_min,avg_ed_rssi);
  415. rt_kprintf("--> End-Device Rx snr : max_snr = %d, min_snr = %d, avg_snr = %d\r\n",snr_value_max,snr_value_min,avg_ed_snr);
  416. rt_kprintf("--> Gateway RX DemodMargin : max_margin = %d, min_margin = %d, avg_margin = %d\r\n",gw_demod_margin_value_max,gw_demod_margin_value_min,avg_gw_demod_margin);
  417. rt_kprintf("--> Gateway RX Numbers : %d\r\n",gw_received_nb);
  418. rt_kprintf("====== LoRaWAN End-Device Ping Test Finished ======\r\n");
  419. }
  420. }
  421. }
  422. }
  423. static void lorawan_ed_tx_dummy(void)
  424. {
  425. lorawan_ed_app_data.BuffSize = 0;
  426. lorawan_ed_app_data.Port = LORAWAN_ED_STACK_MAC_PARAMETER_APPLICATION_FPORT;
  427. lorawan_ed_send(&lorawan_ed_app_data);
  428. }
  429. static void lorawan_ed_confirm_device_class(DeviceClass_t Class)
  430. {
  431. LORAWAN_ED_DEBUG_LOG(LORAWAN_ED_STACK_DEBUG_APP, DBG_LVL, "Switch to Class %c Done\r\n", "ABC"[Class]);
  432. /*Optionnal*/
  433. /*informs the server that switch has occurred ASAP,mainly for Class B*/
  434. lorawan_ed_tx_dummy();
  435. }
  436. static lorawan_ed_error_status_t lorawan_ed_tx_ping_packet(uint8_t len)
  437. {
  438. uint8_t index = 0;
  439. tx_timestamp = TimerGetCurrentTime();
  440. lorawan_ed_app_data.BuffSize = len;
  441. lorawan_ed_app_data.Port = LORAWAN_ED_STACK_MAC_PARAMETER_APPLICATION_FPORT;
  442. MlmeReq_t mlmeReq;
  443. mlmeReq.Type = MLME_LINK_CHECK;
  444. if( LoRaMacMlmeRequest( &mlmeReq ) != LORAMAC_STATUS_OK )
  445. {
  446. return LORAWAN_ED_STATUS_ERROR;
  447. }
  448. // data
  449. lorawan_ed_app_data.Buff[index++] = 'P';
  450. lorawan_ed_app_data.Buff[index++] = 'I';
  451. lorawan_ed_app_data.Buff[index++] = 'N';
  452. lorawan_ed_app_data.Buff[index++] = 'G';
  453. // 00,01,02...
  454. for( uint8_t i = 0; i < len - index ; i++)
  455. {
  456. lorawan_ed_app_data.Buff[index + i] = i;
  457. }
  458. if( lorawan_ed_send(&lorawan_ed_app_data) != true )
  459. {
  460. return LORAWAN_ED_STATUS_ERROR;
  461. }
  462. return LORAWAN_ED_STATUS_SUCCESS;
  463. }
  464. /**
  465. * @brief This function return the battery level
  466. * @param none
  467. * @retval the battery level 1 (very low) to 254 (fully charged)
  468. */
  469. static uint8_t lorawan_ed_get_battery_level(void)
  470. {
  471. uint8_t batteryLevel = 0;
  472. /* todo */
  473. return batteryLevel;
  474. }
  475. #ifdef PKG_USING_EASYFLASH
  476. #ifndef ART_PI_USING_OTA_LIB
  477. static int rt_flash_init(void)
  478. {
  479. #include <spi_flash.h>
  480. #include <drv_spi.h>
  481. extern rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name);
  482. extern int fal_init(void);
  483. rt_hw_spi_device_attach("spi1", "spi10", GPIOA, GPIO_PIN_4);
  484. /* initialize SPI Flash device */
  485. rt_sfud_flash_probe("norflash0", "spi10");
  486. fal_init();
  487. return 0;
  488. }
  489. INIT_ENV_EXPORT(rt_flash_init);
  490. #endif /* ART_PI_USING_OTA_LIB */
  491. #endif
  492. int lorawan_test_shell_init(void)
  493. {
  494. if( lorwan_ed_test_shell_thread.entry == RT_NULL)
  495. {
  496. rt_err_t result = RT_EOK;
  497. TimerInit(&TxTimer, on_tx_timer_event);
  498. /* Configure the LoRaWAN End-Device Stack*/
  499. lorawan_ed_stack_init(&lorawan_ed_user_app_callback);
  500. result = rt_thread_init(&lorwan_ed_test_shell_thread,
  501. "lw-test-shell",
  502. lorawan_ed_app_thread_entry,
  503. RT_NULL,
  504. &rt_lorwan_ed_test_shell_thread_stack[0],
  505. sizeof(rt_lorwan_ed_test_shell_thread_stack),
  506. 4,
  507. 20);
  508. if( result == RT_EOK )
  509. {
  510. rt_thread_startup(&lorwan_ed_test_shell_thread);
  511. }
  512. else
  513. {
  514. rt_kprintf("lorwan_ed_test_shell_thread creat fail!\r\n");
  515. }
  516. }
  517. return 0;
  518. }
  519. INIT_APP_EXPORT(lorawan_test_shell_init);
  520. // for finish\msh
  521. typedef enum
  522. {
  523. CMD_LORAWAN_ED_STACK_DEVEUI_INDEX = 0,
  524. CMD_LORAWAN_ED_STACK_JOINEUI_INDEX,
  525. CMD_LORAWAN_ED_STACK_APPKEY_INDEX,
  526. CMD_LORAWAN_ED_STACK_DEVADDR_INDEX,
  527. CMD_LORAWAN_ED_STACK_APPSKEY_INDEX,
  528. CMD_LORAWAN_ED_STACK_NWKSENCKEY_INDEX,
  529. CMD_LORAWAN_ED_STACK_CLASS_INDEX,
  530. CMD_LORAWAN_ED_STACK_CONFIRM_INDEX,
  531. CMD_LORAWAN_ED_STACK_ACTIVATION_INDEX,
  532. CMD_LORAWAN_ED_STACK_ADR_INDEX,
  533. CMD_LORAWAN_ED_STACK_JOIN_INDEX, // LoRaWAN End-device Join
  534. CMD_LORAWAN_ED_STACK_PING_INDEX, // LoRaWAN End-device ping test
  535. CMD_LORAWAN_ED_STACK_TX_INDEX, // LoRaWAN End-device TX data
  536. CMD_LORAWAN_ED_STACK_SAVE_INDEX, // LoRaWAN End-device save
  537. CMD_LORAWAN_ED_STACK_FACTORY_INDEX, // LoRaWAN End-device factory
  538. }lorawan_shell_index_t;
  539. const char* lorawan_help_info[] =
  540. {
  541. [CMD_LORAWAN_ED_STACK_DEVEUI_INDEX] = "lorawan deveui <hex0..7> - set/get DevEui(8 Bytes)",
  542. [CMD_LORAWAN_ED_STACK_JOINEUI_INDEX] = "lorawan joineui<hex0..7> - set/get JoinEui(8 Bytes)",
  543. [CMD_LORAWAN_ED_STACK_APPKEY_INDEX] = "lorawan appkey <hex0..15> - set/get AppKey(16 Bytes)",
  544. [CMD_LORAWAN_ED_STACK_DEVADDR_INDEX] = "lorawan devaddr <hex0..3> - set/get DevAddr(4 Bytes)",
  545. [CMD_LORAWAN_ED_STACK_APPSKEY_INDEX] = "lorawan appskey <hex0..15> - set/get AppSKey(16 Bytes)",
  546. [CMD_LORAWAN_ED_STACK_NWKSENCKEY_INDEX] = "lorawan nwkskey <hex0..15> - set/get NwkSEncKey(16 Bytes)",
  547. [CMD_LORAWAN_ED_STACK_CLASS_INDEX] = "lorawan class <0/1/2> - set/get Class Type: A,B,C",
  548. [CMD_LORAWAN_ED_STACK_CONFIRM_INDEX] = "lorawan confirm <0/1> - set/get Data Message Type: Unconfirm,Confirm",
  549. [CMD_LORAWAN_ED_STACK_ACTIVATION_INDEX] = "lorawan activation <0/1> - set/get Activation Type: OTAA,ABP",
  550. [CMD_LORAWAN_ED_STACK_ADR_INDEX] = "lorawan adr <0/1> - set/get ADR: disable,enable",
  551. [CMD_LORAWAN_ED_STACK_JOIN_INDEX] = "lorawan join <nbtrial> <interval> - join network:nbtrial-max join num",
  552. [CMD_LORAWAN_ED_STACK_PING_INDEX] = "lorawan ping <nbtrial> <interval> - ping network:nbtrial-max ping num",
  553. [CMD_LORAWAN_ED_STACK_TX_INDEX] = "lorawan tx <mode> <cfm> <port> <len> <data> - tx data: mode:0-stop,1-once,2~1500-cnt,>1500-period,cfm:0/1",
  554. #ifdef PKG_USING_EASYFLASH
  555. [CMD_LORAWAN_ED_STACK_SAVE_INDEX] = "lorawan save <cfg/dev> - save config or device info",
  556. [CMD_LORAWAN_ED_STACK_FACTORY_INDEX] = "lorawan factory - recover to factory setup",
  557. #endif
  558. };
  559. static void lorawan_shell_usage(void)
  560. {
  561. size_t i = 0;
  562. /* parameter error */
  563. rt_kprintf("Usage:\r\n");
  564. for (i = 0; i < sizeof(lorawan_help_info) / sizeof(char*); i++)
  565. {
  566. rt_kprintf("%s\r\n", lorawan_help_info[i]);
  567. }
  568. rt_kprintf("\r\n");
  569. }
  570. /* LoRaWAN End-Device shell function */
  571. static int lorawan(int argc, char *argv[])
  572. {
  573. if (argc < 2)
  574. {
  575. lorawan_shell_usage();
  576. }
  577. else
  578. {
  579. const char *cmd = argv[1];
  580. MibRequestConfirm_t mibReq;
  581. /* SET \ GET */
  582. if (!rt_strcmp("deveui", cmd))
  583. {
  584. if( argc > 2 )
  585. {
  586. uint8_t deveui[8] = { 0 };
  587. for(uint8_t i = 0;i < 8;i++)
  588. {
  589. deveui[i] = get_hex_byte(&argv[2]);
  590. }
  591. rt_kprintf("DevEUI=%02X%02X%02X%02X%02X%02X%02X%02X", HEX8(deveui));
  592. if( lorawan_ed_set_deveui(deveui) == RT_EOK )
  593. {
  594. rt_kprintf(" Set OK\r\n");
  595. }
  596. else
  597. {
  598. rt_kprintf(" Set Failed\r\n");
  599. }
  600. }
  601. else
  602. {
  603. rt_kprintf("DevEUI=%02X%02X%02X%02X%02X%02X%02X%02X\r\n", HEX8(lorawan_ed_get_deveui()));
  604. }
  605. }
  606. else if (!rt_strcmp("joineui", cmd))
  607. {
  608. uint8_t joineui[8] = { 0 };
  609. if( argc > 2 )
  610. {
  611. for(uint8_t i = 0;i < 8;i++)
  612. {
  613. joineui[i] = get_hex_byte(&argv[2]);
  614. }
  615. rt_kprintf("JoinEUI=%02X%02X%02X%02X%02X%02X%02X%02X", HEX8(joineui));
  616. if( lorawan_ed_set_joineui(joineui) == RT_EOK )
  617. {
  618. rt_kprintf(" Set OK\r\n", HEX8(joineui));
  619. }
  620. else
  621. {
  622. rt_kprintf(" Set Failed\r\n", HEX8(joineui));
  623. }
  624. }
  625. else
  626. {
  627. rt_kprintf("JoinEUI=%02X%02X%02X%02X%02X%02X%02X%02X\r\n", HEX8(lorawan_ed_get_joineui()));
  628. }
  629. }
  630. else if (!rt_strcmp("appkey", cmd))
  631. {
  632. if( argc > 2 )
  633. {
  634. uint8_t appkey[16] = { 0 };
  635. for(uint8_t i = 0;i < 16;i++)
  636. {
  637. appkey[i] = get_hex_byte(&argv[2]);
  638. }
  639. rt_kprintf("AppKey=%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", HEX16(appkey));
  640. if( lorawan_ed_set_appkey(appkey) == RT_EOK )
  641. {
  642. rt_kprintf(" Set OK\r\n");
  643. }
  644. else
  645. {
  646. rt_kprintf(" Set Failed\r\n");
  647. }
  648. }
  649. else
  650. {
  651. rt_kprintf("AppKey=%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\r\n", HEX16(lorawan_ed_get_appkey()));
  652. }
  653. }
  654. else if (!rt_strcmp("devaddr", cmd))
  655. {
  656. if( argc > 2 )
  657. {
  658. #if ( defined LORAWAN_ED_STACK_MAC_PARAMETER_ACTIVATION_TYPE_ABP ) || (defined LORAWAN_ED_STACK_USING_ACTIVATION_TYPE_ABP)
  659. uint8_t devaddr[4] = { 0 };
  660. for(uint8_t i = 0;i < 4; i++)
  661. {
  662. devaddr[i] = get_hex_byte(&argv[2]);
  663. }
  664. rt_kprintf("DevAddr=%08X", devaddr[0] << 24 | devaddr[1] << 16 | devaddr[2] << 8 | devaddr[3]);
  665. if (lorawan_ed_set_devaddr(devaddr) == RT_EOK)
  666. {
  667. rt_kprintf(" Set OK\r\n");
  668. }
  669. else
  670. {
  671. rt_kprintf(" Set Fail\r\n");
  672. }
  673. #else
  674. rt_kprintf("Error,Enable ABP function Please.\r\n");
  675. #endif
  676. }
  677. else
  678. {
  679. uint32_t devaddr = lorawan_ed_get_devaddr();
  680. rt_kprintf("DevAddr=%08X\r\n", devaddr);
  681. }
  682. }
  683. else if (!rt_strcmp("appskey", cmd))
  684. {
  685. if (argc > 2)
  686. {
  687. #if ( defined LORAWAN_ED_STACK_MAC_PARAMETER_ACTIVATION_TYPE_ABP ) || (defined LORAWAN_ED_STACK_USING_ACTIVATION_TYPE_ABP)
  688. uint8_t appskey[16] = { 0 };
  689. for (uint8_t i = 0; i < 16; i++)
  690. {
  691. appskey[i] = get_hex_byte(&argv[2]);
  692. }
  693. rt_kprintf("AppSKey=%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",HEX16(appskey));
  694. if (lorawan_ed_set_appskey(appskey) == RT_EOK)
  695. {
  696. rt_kprintf(" Set OK\r\n");
  697. }
  698. else
  699. {
  700. rt_kprintf(" Set Failed\r\n");
  701. }
  702. #else
  703. rt_kprintf("Error,Enable ABP function Please.\r\n");
  704. #endif
  705. }
  706. else
  707. {
  708. rt_kprintf("AppSKey=%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\r\n",
  709. HEX16(lorawan_ed_get_appskey()));
  710. }
  711. }
  712. else if (!rt_strcmp("nwkskey", cmd))
  713. {
  714. if (argc > 2)
  715. {
  716. #if ( defined LORAWAN_ED_STACK_MAC_PARAMETER_ACTIVATION_TYPE_ABP ) || (defined LORAWAN_ED_STACK_USING_ACTIVATION_TYPE_ABP)
  717. uint8_t nwkskey[16] = { 0 };
  718. for (uint8_t i = 0; i < 16; i++)
  719. {
  720. nwkskey[i] = get_hex_byte(&argv[2]);
  721. }
  722. rt_kprintf("AppSKey=%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",HEX16(nwkskey));
  723. if (lorawan_ed_set_nwkskey(nwkskey) == RT_EOK)
  724. {
  725. rt_kprintf(" Set OK\r\n");
  726. }
  727. else
  728. {
  729. rt_kprintf(" Set Failed\r\n");
  730. }
  731. #else
  732. rt_kprintf("Error,Enable ABP function Please.\r\n");
  733. #endif
  734. }
  735. else
  736. {
  737. rt_kprintf("AppSKey=%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\r\n",
  738. HEX16(lorawan_ed_get_nwkskey()));
  739. }
  740. }
  741. else if (!rt_strcmp("class", cmd))
  742. {
  743. mibReq.Type = MIB_DEVICE_CLASS;
  744. if (argc > 2)
  745. {
  746. DeviceClass_t class_type = (DeviceClass_t) atol(argv[2]);
  747. if (class_type <= CLASS_C)
  748. {
  749. lorawan_ed_init_params.Class = class_type;
  750. mibReq.Param.Class = class_type;
  751. LoRaMacMibSetRequestConfirm(&mibReq);
  752. }
  753. else
  754. {
  755. rt_kprintf("Class Type:%d Is NOT Supported", class_type);
  756. }
  757. }
  758. else
  759. {
  760. LoRaMacMibGetRequestConfirm(&mibReq);
  761. }
  762. rt_kprintf("Class Type: %c, %c\r\n", "ABC"[lorawan_ed_init_params.Class],"ABC"[(mibReq.Param.Class & 0x03)]);
  763. }
  764. else if (!rt_strcmp("nbtrials", cmd))
  765. {
  766. mibReq.Type = MIB_CHANNELS_NB_TRANS;
  767. if( argc > 2 )
  768. {
  769. uint8_t nbtrials = atoi(argv[2]);
  770. if( nbtrials <= 15 )
  771. {
  772. mibReq.Param.ChannelsNbTrans = nbtrials;
  773. LoRaMacMibSetRequestConfirm( &mibReq );
  774. }
  775. else
  776. {
  777. rt_kprintf("Nbtrials:%d Is NOT Supported",nbtrials);
  778. }
  779. }
  780. else
  781. {
  782. LoRaMacMibGetRequestConfirm( &mibReq );
  783. }
  784. rt_kprintf("nbtrials: %d\r\n", mibReq.Param.ChannelsNbTrans);
  785. }
  786. else if (!rt_strcmp("confirm", cmd))
  787. {
  788. if( argc > 2 )
  789. {
  790. lorawan_ed_init_params.DataMessageType = atoi(argv[2]);
  791. }
  792. rt_kprintf("Data Message Type: %s\r\n", lorawan_ed_init_params.DataMessageType?"Confirm":"UnConfirm");
  793. }
  794. else if (!rt_strcmp("activation", cmd))
  795. {
  796. if( argc > 2 )
  797. {
  798. lorawan_ed_init_params.ActivationType = atoi(argv[2]);
  799. }
  800. rt_kprintf("Activation Type: %s\r\n", lorawan_ed_init_params.ActivationType?"ABP":"OTAA");
  801. }
  802. else if (!rt_strcmp("adr", cmd))
  803. {
  804. if( argc > 2 )
  805. {
  806. lorawan_ed_init_params.AdrEnable = atoi(argv[2]);
  807. }
  808. rt_kprintf("ADR: %s\r\n", lorawan_ed_init_params.AdrEnable?"Enable":"Disable");
  809. }
  810. /* JOIN */
  811. else if (!rt_strcmp(cmd, "join"))
  812. {
  813. /* otaa */
  814. lorawan_ed_init_params.ActivationType = LORAWAN_ED_ACTIVATION_TYPE_OTAA;
  815. app_tx_period = APP_JOIN_DUTYCYCLE;
  816. if (argc > 2)
  817. {
  818. /*
  819. * nbtrials
  820. * 0 - stop join
  821. * > 0 - join max nbtrials
  822. * */
  823. max_tx_nbtrials = atoi(argv[2]);
  824. if (argc > 3)
  825. {
  826. uint16_t period = atol(argv[3]);
  827. /* min join period */
  828. if (period < 8)
  829. {
  830. rt_kprintf("Join Period Error!\r\n");
  831. }
  832. else
  833. {
  834. app_tx_period = period;
  835. }
  836. }
  837. }
  838. if ( max_tx_nbtrials )
  839. {
  840. rt_event_send(&ev_lorawan_apl, EV_LORAWAN_APL_START_JOIN_NETWORK);
  841. }
  842. else
  843. {
  844. /* stop periodic join */
  845. app_tx_period = 0;
  846. TimerStop(&TxTimer);
  847. rt_kprintf("Stop Join\r\n");
  848. }
  849. }
  850. else if (!rt_strcmp(cmd, "ping")) /* Ping test */
  851. {
  852. ping_test_flag = true;
  853. tx_seq_cnt = 0;
  854. rx_correct_cnt = 0;
  855. max_tx_nbtrials = 10;
  856. app_tx_period = PING_TX_DUTYCYCLE; // 3s
  857. // initlize default value
  858. rssi_value = -255;
  859. rssi_value_min = -255;
  860. rssi_value_max = -255;
  861. rssi_value_total = 0;
  862. snr_value = -128;
  863. snr_value_min = -128;
  864. snr_value_max = -128;
  865. snr_value_total = 0;
  866. gw_demod_margin_value = -128;
  867. gw_demod_margin_value_min = -128;
  868. gw_demod_margin_value_max = -128;
  869. gw_demod_margin_value_total = 0;
  870. if ( lorawan_ed_join_status() == LORAWAN_ED_NOT_JOIN_NETWORK )
  871. {
  872. rt_kprintf("==== Please Join Network first ====\r\n");
  873. return 1;
  874. }
  875. if (argc > 2)
  876. {
  877. max_tx_nbtrials = atoi(argv[2]);
  878. if (argc > 3)
  879. {
  880. app_tx_period = atoi(argv[3]);
  881. }
  882. }
  883. on_tx_timer_event();
  884. }
  885. else if (!rt_strcmp(cmd, "tx")) /* TX test */
  886. {
  887. /* tx_mode define:
  888. * - =0, stop periodic tx
  889. * - =1, tx immediately,tx counter = 1
  890. * - 2~1500, periodic tx with max counter, period is 10 sec,tx counters = tx_mode
  891. * - £¾1500, periodic tx forever,period = tx_mode, unit is ms
  892. */
  893. uint32_t tx_mode = 0;
  894. /* tx_mode */
  895. if (argc > 2)
  896. {
  897. tx_mode = atol(argv[2]);
  898. /* data message type
  899. * 0 - unconfirm
  900. * 1 - confirm
  901. */
  902. if (argc > 3)
  903. {
  904. lorawan_ed_init_params.DataMessageType = atoi(argv[3]);
  905. /* fport 1~223 */
  906. if (argc > 4)
  907. {
  908. uint8_t fport = atoi(argv[4]);
  909. if ((fport > 0) && (fport < 224))
  910. {
  911. lorawan_ed_app_data.Port = atoi(argv[4]);
  912. }
  913. else
  914. {
  915. LORAWAN_ED_DEBUG_LOG(LORAWAN_ED_STACK_DEBUG_APP, DBG_LVL,
  916. "==== fport=%d is not in range 1~223 ====", fport);
  917. }
  918. /* data len */
  919. if (argc > 5)
  920. {
  921. uint16_t i = 0;
  922. lorawan_ed_app_data.BuffSize = atoi(argv[5]);
  923. /* user data */
  924. for (i = 0; i < lorawan_ed_app_data.BuffSize; i++)
  925. {
  926. lorawan_ed_app_data.Buff[i] = get_hex_byte(&argv[i + 6]);
  927. }
  928. }
  929. }
  930. }
  931. }
  932. if ( tx_mode )
  933. {
  934. tx_seq_cnt = 0;
  935. ping_test_flag = false;
  936. /* tx immediately,only once */
  937. if (tx_mode == 1)
  938. {
  939. if (lorawan_ed_join_status() == LORAWAN_ED_JOINED_NETWORK)
  940. {
  941. lorawan_ed_send(&lorawan_ed_app_data);
  942. }
  943. else
  944. {
  945. rt_kprintf("==== Please Join Network first ====\r\n");
  946. }
  947. }
  948. else
  949. {
  950. /* periodic tx */
  951. if ( tx_mode >= 1500 )
  952. {
  953. app_tx_period = tx_mode; /* tx period */
  954. max_tx_nbtrials = 0;
  955. }
  956. else
  957. {
  958. app_tx_period = APP_TX_DUTYCYCLE;
  959. max_tx_nbtrials = app_tx_period;
  960. }
  961. LORAWAN_ED_DEBUG_LOG(LORAWAN_ED_STACK_DEBUG_APP, DBG_LVL,
  962. "\r\n==== Started Periodic Report Data-Message Timer,Report Period: %d ms, %s, fport: %d====",\
  963. app_tx_period,(lorawan_ed_init_params.DataMessageType?"Confirm":"UnConfirm"),lorawan_ed_app_data.Port);
  964. on_tx_timer_event();
  965. }
  966. }
  967. else
  968. {
  969. /* stop periodic tx */
  970. TimerStop(&TxTimer);
  971. app_tx_period = 0;
  972. rt_kprintf("Stop Periodic Tx\r\n");
  973. }
  974. }
  975. #ifdef PKG_USING_EASYFLASH
  976. else if(!rt_strcmp(cmd, "save")) /* save to flash */
  977. {
  978. /* device id info */
  979. if (!rt_strcmp(argv[2], "dev"))
  980. {
  981. lorawan_ed_save_dev_info();
  982. rt_kprintf("save dev done\r\n");
  983. }
  984. else // if (!rt_strcmp(argv[2], "cfg"))
  985. {
  986. lorawan_ed_save_cfg();
  987. rt_kprintf("save cfg done\r\n");
  988. }
  989. }
  990. else if(!rt_strcmp(cmd, "factory"))
  991. {
  992. /* clear cfg parameters */
  993. lorawan_ed_init_params = lorawan_ed_init_params_default;
  994. lorawan_ed_save_cfg();
  995. rt_kprintf("save cfg done\r\n");
  996. }
  997. #endif /* PKG_USING_EASYFLASH */
  998. else
  999. {
  1000. rt_kprintf("Parameter Error\r\n");
  1001. }
  1002. }
  1003. return 1;
  1004. }
  1005. MSH_CMD_EXPORT(lorawan, lorawan end-device test);