Демонстрационная прошивка отладочного комплекта МТС NB-IoT
menu_handlers.c
См. документацию.
1 #include "menu_handlers.h"
2 
9 #define RF_MODULE_BUGFIX 0
10 
11 #if RF_MODULE_BUGFIX == 1
12 #warning The firmware compiled with additional code to fix the bug in RF module.
13 static uint8_t receive_bug_fixed=0; //A flag to determine if the bug with no receive function available until a message is sent was treated
14 #endif
15 
16 uint8_t execute_AT_command(const uint8_t *atcmd)
17 {
18  uint8_t data_buffer[255];
19  uint16_t resp_length;
20  uint8_t error;
21 
22  delay_ms(1000);
23 
24  snprintf(data_buffer,255,"%s\r\n",atcmd);
25  AT_SendCommand(data_buffer);
26  resp_length = AT_ReadReponseBuffer(data_buffer,255,NULL,NULL,&error,3*CYCLES_PER_1SEC);
27 
28  if (resp_length==0)
29  {
30  printf("%s - no answer from the module.\r\n",atcmd);
31  }
32  else
33  {
34  data_buffer[resp_length] = 0;
35  printf("%s\r\n",data_buffer);
36  }
37 
38  if ((resp_length==0) || (error==1))
39  {
40  return 0;
41  }
42 
43  return 1;
44 }
45 
46 uint8_t is_alphanumeric(uint8_t ch)
47 {
48  if (((ch>='A') && (ch<='Z')) || ((ch>='a') && (ch<='z')) || ((ch>='0') && (ch<='9')))
49  {
50  return 1;
51  }
52  else
53  {
54  return 0;
55  }
56 }
57 
67 #define USER_INPUT_LENGTH 80
68 static uint8_t user_input[USER_INPUT_LENGTH];
69 
70 void set_target_URL(device_setup_data_t *settings)
71 {
72  printf("Current URL saved in EEPROM: %s\r\n",settings->target_URL);
73  printf("New URL (127 characters max!):\r\n");
74  scanf("%s",user_input);
75  apply_backspace(user_input,USER_INPUT_LENGTH);
76  /* Remember, strlen() DOES NOT count NULL character! */
77  if (strlen(user_input)>127)
78  {
79  printf("String too long.\r\n");
80  }
81  else
82  {
83  strcpy(settings->target_URL,user_input);
84  store_device_settings(settings);
85  }
86 }
87 
88 void set_server_IP(device_setup_data_t *settings)
89 {
90  uint32_t version;
91  uint16_t error_state;
92 
93  printf("Current server IP saved in EEPROM: %s\r\n",settings->target_server_IP);
94 
95  printf("Enter IP version you want to use, 4 for IPv4 or 6 for IPv6: ");
96  scanf("%d",&version);
97  printf("\r\n");
98 
99  if ((version != 4) && (version != 6))
100  {
101  printf("Unknown protocol version.\r\n");
102 
103  return;
104  }
105 
106  printf("New server IP (%d characters max!):\r\n",sizeof(settings->target_server_IP));
107  scanf("%s",user_input);
108  apply_backspace(user_input,USER_INPUT_LENGTH);
109  if (strlen(user_input)>sizeof(settings->target_server_IP))
110  {
111  printf("String too long.\r\n");
112  }
113  else
114  {
115  strcpy(settings->target_server_IP,user_input);
116  store_device_settings(settings);
117  }
118 
119  printf("Applying RF module settings for a chosen mode...\r\n");
120 
121  error_state = 0;
122 
123  if (version == 4)
124  {
125  error_state += !execute_AT_command("AT+UPSD=0,0,0");
126  }
127  else
128  {
129  //Any option except no. 6 was excluded earlier
130  error_state += !execute_AT_command("AT+UPSD=0,0,1");
131  }
132 
133  if (error_state != 0)
134  {
135  printf("Failed to apply settings for a chosen IP version; the module may not work properly.\r\n");
136  }
137 }
138 
139 void set_server_port(device_setup_data_t *settings)
140 {
141  printf("Current port saved in EEPROM: %d\r\n",settings->target_server_port);
142  printf("New port (0 - 65535):\r\n");
143  scanf("%d",&(settings->target_server_port));
144  store_device_settings(settings);
145 }
146 
147 void set_NIDD_APN(device_setup_data_t *settings)
148 {
149  uint32_t cmp1,cmp2;
150 
151  printf("Current APN: %s\r\n",settings->NIDD_APN_name);
152  printf("Enter new APN value (63 characters max!),\r\nor enter \"nidd=1\" or \"nidd=0\" to turn NIDD ON/OFF:\r\n");
153  scanf("%s",user_input);
154  printf("\r\n");
155  apply_backspace(user_input,USER_INPUT_LENGTH);
156  if (strlen(user_input)>63)
157  {
158  printf("String too long.\r\n");
159  }
160  else
161  {
162  cmp1 = strcmp(user_input,"nidd=1");
163  cmp2 = strcmp(user_input,"nidd=0");
164 
165  if (cmp1==0)
166  {
167  if (settings->NIDD_APN_name[0]=='\0')
168  {
169  printf("NIDD APN not set, so NIDD cannot be switched on!\r\n");
170  }
171  else
172  {
173  printf("Saving NIDD mode ON...\r\n");
174  settings->use_NIDD=1;
175  SARA_init(settings->use_NIDD,settings->NIDD_APN_name);
176  }
177  }
178 
179  if (cmp2==0)
180  {
181  settings->use_NIDD=0;
182  printf("Saving NIDD mode OFF...\r\n");
183  SARA_init(settings->use_NIDD,settings->NIDD_APN_name);
184  }
185 
186  if ((cmp1!=0) && (cmp2!=0))
187  {
188  strcpy(settings->NIDD_APN_name,user_input);
189  printf("Saving new APN...\r\n");
190  }
191 
192  store_device_settings(settings);
193  }
194 }
195 
196 void test_transmit_telemetry(device_setup_data_t *settings)
197 {
198  uint8_t temp_ICCID[50];
199 
200  AT_ReadICCID(temp_ICCID,CYCLES_PER_1SEC);
201 
202  if (settings->gnss_privacy_mode==0)
203  {
204  printf("Your actual location could be sent to a server. Do you really want to continue (y/n)?\r\n\
205 You can turn on GNSS privacy mode to avoid unplanned location disclosure.\r\n");
206  scanf("%s",user_input);
207  apply_backspace(user_input,USER_INPUT_LENGTH);
208 
209  if ((user_input[0]=='y') || (user_input[0]=='Y'))
210  {
212  settings->target_URL,
213  settings->target_server_port,
214  temp_ICCID,
215  settings->use_NIDD,
216  settings->gnss_privacy_mode);
217 
218 #if RF_MODULE_BUGFIX == 1
219  receive_bug_fixed = 1; //A transmit action fixes the receive bug in NIDD mode
220 #endif
221  }
222  }
223  else
224  {
226  settings->target_URL,
227  settings->target_server_port,
228  temp_ICCID,
229  settings->use_NIDD,
230  settings->gnss_privacy_mode);
231 #if RF_MODULE_BUGFIX == 1
232  receive_bug_fixed = 1;
233 #endif
234  }
235 }
236 
237 void true_direct_mode(device_setup_data_t *settings)
238 {
239  printf("Entering true direct mode.\r\n\
240 From now on everything you type into this terminal will be transferred to the RF module as is \r\n(and similarly in reverse direction).\r\n\
241 NOTICE: No special commands supported here, for nothing is between you and the RF module.\r\n\
242 YOU NEED TO REBOOT THE BOARD PHYSICALLY TO EXIT THIS MODE.\r\n---\r\n");
243 
244  //Enable DMA1 to transfer data between USART2 and USART3, from console to RF module and vice versa
245  RCC->AHBENR |= RCC_AHBENR_DMA1EN;
246  //In this direct mode interrupt is not needed, for all the data transfers are done using DMA
247  NVIC_DisableIRQ(USART3_IRQn);
248 
249  //Move data from USART3 (RF module data) to USART1 (console) on USART3 RX event
250  USART3->CR3 |= USART_CR3_DMAR;
251  DMA1_Channel3->CPAR = (uint32_t)(&(USART3->DR));
252  DMA1_Channel3->CMAR = (uint32_t)(&(USART1->DR));
253  DMA1_Channel3->CNDTR = 1;
254  DMA1_Channel3->CCR = DMA_CCR3_MSIZE_0 | DMA_CCR3_PSIZE_0 | DMA_CCR3_CIRC | DMA_CCR3_EN;
255 
256  //Move data from USART1 (console) to USART3 (RF module) on USART1 RX event
257  USART1->CR3 |= USART_CR3_DMAR;
258  DMA1_Channel5->CPAR = (uint32_t)(&(USART1->DR));
259  DMA1_Channel5->CMAR = (uint32_t)(&(USART3->DR));
260  DMA1_Channel5->CNDTR = 1;
261  DMA1_Channel5->CCR = DMA_CCR5_MSIZE_0 | DMA_CCR5_PSIZE_0 | DMA_CCR5_CIRC | DMA_CCR5_EN;
262 
263  while (1)
264  {
265  }
266 }
267 
268 void direct_AT_mode(device_setup_data_t *settings)
269 {
270  printf("Entering direct AT-command mode.\r\n\
271 Everything you type in will be passed to RF module directly, except special commands:\r\n\
272 \t\"exit\" - exit direct AT command mode\r\n\
273 \t\"pwrp\" - generate low pulse on PWR_ON pin of a module and wait for startup, useful when using PSM (to wake up the module).\r\n");
274 
275  while (1)
276  {
277  printf("> ");
278  scanf("%s",user_input);
279  printf("\r\n");
280  apply_backspace(user_input,USER_INPUT_LENGTH);
281 
282  if (strcmp(user_input,"exit")==0)
283  {
284  break;
285  }
286  else
287  {
288  if (strcmp(user_input,"pwrp")==0)
289  {
290  printf("Generating pulse on PWR_ON...\r\n");
292  printf("Waiting module to start...\r\n");
293  /*
294  When greeting message is set to "BOOT OK", this call will return on "OK", as designed.
295  If the message is not set, it will return after five seconds or so, which is sufficient for the module to start up.
296  This is effectively a small hack to determine when the module is ready.
297  */
298  AT_ReadReponseBuffer(NULL,0,NULL,NULL,NULL,5*CYCLES_PER_1SEC);
299  printf("Module ready.\r\n");
300  }
301  else
302  {
303  execute_AT_command(user_input);
304  }
305  }
306  }
307 }
308 
309 void print_identification_data(device_setup_data_t *settings)
310 {
311  uint32_t *MCU_unique_ID_addr;
312  uint8_t str[50];
313 
314  MCU_unique_ID_addr = MCU_UNIQUE_IDENTIFIER_ADDRESS;
315 
316  printf("Board identification data\r\n");
318  printf("\r\nSIM card ICCID: %s\r\n",str);
319  execute_AT_command("AT+CCID");
321  printf("\r\nRF module IMEI: %s\r\n",str);
322  execute_AT_command("AT+CGSN");
323  printf("\r\nIMSI:\r\n");
324  execute_AT_command("AT+CIMI");
325  printf("\r\nRF module model:\r\n");
326  execute_AT_command("AT+GMM");
327  printf("\r\nRF module firmware version:\r\n");
328  execute_AT_command("AT+GMR");
329 
330  printf("\r\nMCU firmware version:\r\n%s\r\n",FIRMWARE_VERSION);
331  printf("\r\nMCU serial number:\r\n0x%X%X%X\r\n",MCU_unique_ID_addr[2],MCU_unique_ID_addr[1],MCU_unique_ID_addr[0]);
332 }
333 
334 //As AT_ReadResponseBuffer() supports having NULL for a buffer pointer, this function supports this too
335 uint8_t execute_AT_command_silent(const uint8_t *cmd,uint8_t *response_out)
336 {
337  uint8_t error;
338 
339  AT_SendCommand(cmd);
340  AT_ReadReponseBuffer(response_out,512,NULL,NULL,&error,3*CYCLES_PER_1SEC);
341 
342  return error;
343 }
344 
345 void print_network_info(device_setup_data_t *settings)
346 {
347  static uint8_t resp_buffer[512];
348  uint8_t error;
349  int32_t RSSI;
350  int32_t RSRP;
351  int32_t RSRQ;
352  int32_t CellID;
353  int32_t EARFCN;
354 
355  if (execute_AT_command_silent("AT+CSQ\r\n",resp_buffer)==0)
356  {
357  sscanf(resp_buffer,"%*s\r\r\n+CSQ: %d",&RSSI);
358  printf("RSSI\t= %d dBm (valid range is -111 to -51 dBm)\r\n",(RSSI*2) - 113);
359  }
360  else
361  {
362  printf("Unable to execute AT+CSQ\r\n");
363  }
364 
365  if (execute_AT_command_silent("AT+CESQ\r\n",resp_buffer)==0)
366  {
367  sscanf(resp_buffer,"%*s\r\r\n+CESQ: %*d,%*d,%*d,%*d,%d,%d",&RSRQ,&RSRP);
368  printf("SNR\t= %d dB\r\nRSRP\t= %d dBm (valid range is -141 to -44 dBm)\r\n",RSRQ,RSRP - 141);
369  }
370  else
371  {
372  printf("Unable to execute AT+CESQ\r\n");
373  }
374 
375  AT_SendCommand("AT+CEREG?\r\n");
376  AT_ReadReponseBuffer(resp_buffer,512,NULL,NULL,&error,3*CYCLES_PER_1SEC);
377 
378  if (execute_AT_command_silent("AT+CEREG=2\r\n",NULL)!=0)
379  {
380  printf("Unable to set up CEREG request mode.\r\n");
381  }
382  else
383  {
384  if (execute_AT_command_silent("AT+CEREG?\r\n",resp_buffer)==0)
385  {
386  sscanf(resp_buffer,"%*s\r\r\n+CEREG: %*d,%*d,\"%*lx\",\"%lx",&CellID);
387  printf("Cell ID\t= %d\r\n",CellID);
388  }
389  else
390  {
391  printf("Unable to request Cell ID.\r\n");
392  }
393  }
394 
395  if (execute_AT_command_silent("AT+UCGED=5\r\n",NULL)!=0)
396  {
397  printf("Unable to set UCGED request mode.\r\n");
398  }
399  else
400  {
401  if (execute_AT_command_silent("AT+UCGED?\r\n",resp_buffer)==0)
402  {
403  sscanf(resp_buffer,"%*s\r\r\n+RSRP: %*d,%d",&EARFCN);
404  printf("EARFCN\t= %d\r\n",EARFCN);
405  }
406  else
407  {
408  printf("Unable to request EARFCN.\r\n");
409  }
410  }
411 }
412 
413 void wait_NIDD_URC(device_setup_data_t *settings)
414 {
415  uint32_t timeout_ms;
416  uint32_t current_time;
417  uint32_t start_time;
418  uint16_t NIDD_resp_len;
419  static uint8_t NIDD_data[512]; //Making large variable static to offload the stack
420 
421  if (settings->use_NIDD == 0)
422  {
423  printf("NIDD method is not enabled. Please first enable NIDD.\r\n");
424 
425  return;
426  }
427 
428 #if RF_MODULE_BUGFIX == 1
429  if (receive_bug_fixed == 0)
430  {
431  printf("This is the first time in this session that you use the NIDD receive function;\r\n\
432 due to bug in the RF module firmware, in NIDD mode it is necessary to first send something to uplink before it will be possible to receive data.\r\n\
433 For this reason, a telemetry packet will be sent now.\r\n");
434 
435  test_transmit_telemetry(settings);
436 
437  receive_bug_fixed = 1;
438  }
439 #endif
440 
441  printf("Please enter timeout (seconds): ");
442  scanf("%d",&timeout_ms);
443  printf("\r\n");
444 
445  timeout_ms *= 1000; //Convert to milliseconds
446 
447  NIDD_resp_len = 0;
448  start_time = get_uptime_ms();
449  current_time = start_time;
450 
451  execute_AT_command("AT+CRTDCP=1\r\n");
452 
453  printf("Waiting for message via NIDD...\r\n");
454 
455  printf("Timeout: %d sec. \r",(timeout_ms - (current_time - start_time))/1000);
456 
457  while ((NIDD_resp_len == 0) && ((current_time - start_time) < timeout_ms))
458  {
459  NIDD_resp_len = AT_CheckNIDDReceived(NIDD_data);
460  current_time = get_uptime_ms();
461 
462  if ((current_time % 1000) == 0)
463  {
464  printf("Timeout: %d sec. \r",(timeout_ms - (current_time - start_time))/1000);
465  }
466  }
467 
468  if (NIDD_resp_len == 0)
469  {
470  printf("No NIDD data received; stopping due to timeout.\r\n");
471  }
472  else
473  {
474  printf("NIDD data (%d bytes):\r\n%s\r\n",NIDD_resp_len,NIDD_data);
475  }
476 }
477 
478 void set_telemetry_interval(device_setup_data_t *settings)
479 {
480  printf("Enter telemetry transmission interval in milliseconds (min=1000, max=16000):\r\n");
481  scanf("%i",&(settings->telemetry_interval_ms));
482 
483  if (settings->telemetry_interval_ms<1000)
484  {
485  settings->telemetry_interval_ms = 1000;
486  printf("Interval too short, corrected to minimum of 1000 ms.\r\n");
487  }
488 
489  if (settings->telemetry_interval_ms>16000)
490  {
491  settings->telemetry_interval_ms = 16000;
492  printf("Interval too long, corrected to maximum of 16000 ms.\r\n");
493  }
494 
495  store_device_settings(settings);
496 }
497 
498 void set_GNSS_privacy(device_setup_data_t *settings)
499 {
500  printf("GNSS privacy mode: 1 - enabled (default), 0 - disabled (use with care):\r\n");
501  scanf("%s",user_input);
502  apply_backspace(user_input,USER_INPUT_LENGTH);
503 
504  if (user_input[0]=='0')
505  {
506  settings->gnss_privacy_mode = 0;
507  }
508  else
509  {
510  settings->gnss_privacy_mode = 1;
511  }
512 
513  store_device_settings(settings);
514 }
515 
516 void set_startup_mode(device_setup_data_t *settings)
517 {
518  printf("Firmware startup mode: 0 - this menu (default), 1 - logger mode:\r\n");
519  scanf("%s",user_input);
520  printf("\r\n");
521  apply_backspace(user_input,USER_INPUT_LENGTH);
522 
523  if (user_input[0]=='1')
524  {
526  }
527  else
528  {
529  settings->logger_mode_on_startup = 0;
530  }
531 
532  store_device_settings(settings);
533 
534  printf("This setting will take effect after MCU restart.\r\n");
535 }
536 
537 void test_sensors(device_setup_data_t *settings)
538 {
539  uint8_t error_state;
540  int8_t Tamb;
541  int16_t accel_X,accel_Y,accel_Z;
542  uint8_t accel_signature;
543  uint8_t temp_GNSS_string[80];
544  double latitude;
545  double longitude;
546 
547 #if USE_DS1721 == 1
548  Tamb = DS1721_ReadTemperature(LOCAL_TSENSOR_I2C_ADDR);
549 #else
551 #endif
552  LIS3DH_ReadXYZ(LOCAL_ACCEL_I2C_ADDR,&accel_X,&accel_Y,&accel_Z);
553  accel_signature = LIS3DH_ReadSignature(LOCAL_ACCEL_I2C_ADDR);
554 
555  printf("On-board sensors data:\r\n\ttemperature:\t%d\r\n\r\n\taccelerometer:\tX = %d\tY = %d\tZ = %d\r\n",Tamb,accel_X,accel_Y,accel_Z);
556 
557  if (accel_signature==0x33)
558  {
559  printf("\tAccelerometer signature value is correct.\r\n\r\n");
560  }
561  else
562  {
563  printf("\tAccelerometer signature value is wrong.\r\n\r\n");
564  }
565 
566  printf("Testing GNSS option...\r\n");
567  //Resetting the FSM to get the freshest data
568  GNSS_ReadLocationData(NULL,0);
569  //Should be enough for the GNSS module to generate some data, if the shield is present
570  delay_ms(1200);
571  error_state = GNSS_ReadLocationData(temp_GNSS_string,80);
572 
573  if (error_state==0)
574  {
575  printf("GNSS shield is not fitted or does not function properly.\r\n");
576  }
577  else
578  {
579  printf("GNSS string:\r\n%s\r\n",temp_GNSS_string);
580 
581  if (!NMEA_to_LatLon(temp_GNSS_string,&latitude,&longitude))
582  {
583  printf("Unable to convert NMEA to decimal degrees data;\r\nthis is probably because GNSS fix is not achieved yet.\r\n");
584  }
585  else
586  {
587  printf("Parsed data:\r\n\tlatitude = %.6f\r\n\tlongitude = %.6f\r\n",latitude,longitude);
588  }
589  }
590 }
591 
592 void perform_system_reset(device_setup_data_t *settings)
593 {
594  NVIC_SystemReset();
595 }
596 
597 void perform_RF_module_reset(device_setup_data_t *settings)
598 {
599  execute_AT_command("AT+CFUN=15");
600 }
601 
603 {
604  uint16_t error_state;
605  int8_t Tamb;
606  uint16_t cmd_resp_length;
607  uint8_t k;
608  uint8_t res;
609 
610  printf("Applying default values to settings (%d bytes)...\r\n",sizeof(device_setup_data_t));
611  snprintf(settings->target_server_IP,24,"%s",MTS_COAP_SERVER_IP);
612  settings->target_URL[0] = '\0';
613  settings->NIDD_APN_name[0] = '\0';
614  settings->target_server_port = MTS_COAP_SERVER_PORT;
615  settings->use_NIDD = 0;
616  settings->gnss_privacy_mode=1;
617  settings->logger_mode_on_startup=0;
618  settings->telemetry_interval_ms = 1000;
619  settings->reserved[0] = SETTINGS_SIGNATURE_0;
620  settings->reserved[1] = SETTINGS_SIGNATURE_1;
621  settings->reserved[2] = SETTINGS_SIGNATURE_2;
622  printf("Saving data...\r\n");
623  store_device_settings(settings);
624  printf("EEPROM data structure initialized.\r\n");
625 
626  printf("Checking the RF module activity...\r\n");
627 
628  k=0;
629  do
630  {
631  printf("Attempt %d...\r\n",k+1);
632  AT_SendCommand("AT\r\n");
633  cmd_resp_length = AT_ReadReponseBuffer(NULL,0,NULL,NULL,NULL,CYCLES_PER_1SEC);
634  if (cmd_resp_length==0)
635  {
636  printf("No answer.\r\n");
637  }
638  k++;
639  }
640  while ((k<3) && (cmd_resp_length==0));
641 
642  if (cmd_resp_length==0)
643  {
644  printf("RF module does not seem to be active, running startup algorithm...");
645  SARA_init(0,settings->NIDD_APN_name);
646  }
647 
648  printf("Configuring the module...\r\n");
649 
650  error_state = 0;
651 
652  error_state += !execute_AT_command("AT+UMNOPROF=100");
653  printf("Rebooting module...\r\n");
654  error_state += !execute_AT_command("AT+CFUN=15");
655  delay_ms(5000);
656  printf("error_state = %d\r\n",error_state);
657 
658  /*
659  This command is executed, but not included in error checking
660  */
661  k=0;
662  res=0;
663 
664  while ((k<5) && (res == 0))
665  {
666  res = execute_AT_command("AT+UFOTACONF=2,-1");
667 
668  if (res == 0)
669  {
670  delay_ms(2000);
671  }
672 
673  k++;
674  }
675 
676  error_state += !execute_AT_command("AT+CSGT=1,\"BOOT OK\"");
677  error_state += !execute_AT_command("AT+CFUN=0");
678  error_state += !execute_AT_command("AT+CPSMS=0");
679  printf("Rebooting module...\r\n");
680  error_state += !execute_AT_command("AT+CFUN=15");
681  delay_ms(5000);
682  printf("error_state = %d\r\n",error_state);
683 
684  error_state += !execute_AT_command("AT+CFUN=0");
685  error_state += !execute_AT_command("AT+CEDRXS=0,5,\"0010\"");
686  error_state += !execute_AT_command("AT+CEDRXS=0,4,\"0010\"");
687  printf("Rebooting module...\r\n");
688  error_state += !execute_AT_command("AT+CFUN=15");
689  delay_ms(5000);
690  printf("error_state = %d\r\n",error_state);
691 
692  error_state += !execute_AT_command("AT+CGDCONT=1,\"IPV4V6\",\"iot\"");
693  printf("Rebooting module...\r\n");
694  error_state += !execute_AT_command("AT+CFUN=15");
695  delay_ms(5000);
696  printf("error_state = %d\r\n",error_state);
697 
698  error_state += !execute_AT_command("AT+URAT=8");
699  printf("Rebooting module...\r\n");
700  error_state += !execute_AT_command("AT+CFUN=15");
701  delay_ms(5000);
702  printf("error_state = %d\r\n",error_state);
703 
704  error_state += !execute_AT_command("AT+UBANDMASK=0,0");
705  error_state += !execute_AT_command("AT+UBANDMASK=1,524420");
706  printf("Rebooting module...\r\n");
707  error_state += !execute_AT_command("AT+CFUN=15");
708  delay_ms(5000);
709  printf("error_state = %d\r\n",error_state);
710 
711  error_state += !execute_AT_command("AT+UGPIOC=16,2");
712  printf("error_state = %d\r\n",error_state);
713 
715  {
716  printf("Accelerometer signature is wrong.\r\n");
717  error_state++;
718  }
719  else
720  {
721  printf("Accelerometer OK.\r\n");
722  }
723 
724 #if USE_DS1721 == 1
725  printf("Firmware compiled with DS1721 support instead of TMP75.\r\n");
726  DS1721_StartConversion(LOCAL_TSENSOR_I2C_ADDR);
727  printf("DS1721 initialized.\r\n");
728  Tamb = DS1721_ReadTemperature(LOCAL_TSENSOR_I2C_ADDR);
729 #else
731 #endif
732 
733  if ((Tamb<15) || (Tamb>35))
734  {
735  printf("The temperature is out of the sane range (%d deg. C); the temperature sensor is possibly not functional.\r\n",Tamb);
736  error_state++;
737  }
738  else
739  {
740  printf("Temperature sensor OK (%d deg. C measured).\r\n",Tamb);
741  }
742 
743  print_identification_data(settings);
744 
745  printf("\r\n--------------------------------------------------------------------------------\r\n");
746 
747  if (error_state!=0)
748  {
749  printf("CONFIG_OK=0\r\n");
750  }
751  else
752  {
753  printf("CONFIG_OK=1\r\n");
754  }
755 
756  printf("\r\n--------------------------------------------------------------------------------\r\n");
757 }
758 
764 #define MAX_JSON_LENGTH 200
765 #define MAX_COAP_MSG_LEN (MAX_JSON_LENGTH + MAX_URI_LENGTH + 50)
766 uint8_t wait_coap_server_response(uint32_t wait_time)
767 {
768  uint32_t start_time,t;
769  uint8_t rx_socket_ID;
770  uint16_t rx_data_length;
771  CoAP_header_info_t hdr_info;
772  uint8_t *coap_data_start_ptr;
773  uint8_t CoAP_msg[MAX_COAP_MSG_LEN];
774 
775  start_time = get_uptime_ms();
776  t=start_time;
777  rx_socket_ID = INVALID_SOCKET_ID;
778 
779  while ((rx_socket_ID == INVALID_SOCKET_ID) && ((t - start_time)<wait_time))
780  {
781  AT_CheckUDPReceived(&rx_socket_ID,&rx_data_length);
782  t = get_uptime_ms();
783  if ((t % 1000) == 0)
784  {
785  printf("%d \r",(wait_time/1000) - ((t - start_time)/1000));
786  }
787  }
788  printf("\r\n");
789 
790  if (rx_socket_ID == INVALID_SOCKET_ID)
791  {
792  printf("No response from the server, reception terminated by timeout.\r\n");
793 
794  return 0;
795  }
796 
797  AT_ReadUDPData(rx_socket_ID,rx_data_length,NULL,NULL,CoAP_msg,1*CYCLES_PER_1SEC);
798 
799  CoAP_parse_message_header(CoAP_msg,&hdr_info);
800 
801  printf("Server responded %d.%02d\r\n",hdr_info.code_class,hdr_info.code_detail);
802  CoAP_msg[rx_data_length] = 0;
803  CoAP_parse_message(CoAP_msg,rx_data_length,&coap_data_start_ptr);
804 
805  if (coap_data_start_ptr != NULL)
806  {
807  printf("Data: %s\r\n",coap_data_start_ptr);
808  }
809  else
810  {
811  printf("No data in response.\r\n");
812  }
813 
814  return 1;
815 }
816 
817 /*
818  As of 05.09.2020 MTS server has a bug. According to the standard, a server should respond to the GET request with
819  the OBSERVE option set the same way as to an ordinary GET request, and it also must include into the response the
820  OBSERVE option with the subscription ID. Currently server does not do this. So it is required to modify behavior of
821  the firmware to account for this. When the workaround is used, the firmware will not wait for the initial response
822  from a server.
823 */
824 #define USE_SERVER_BUG_WORKAROUND 1
825 
826 void test_CoAP_observe_function(device_setup_data_t *settings)
827 {
828  static uint8_t res_url[80];
829  static uint8_t CoAP_msg[MAX_COAP_MSG_LEN];
830  uint16_t CoAP_msg_len;
831  uint8_t socket_ID;
832  uint32_t wait_time;
833  uint16_t k;
834 
835  if (settings->use_NIDD != 0)
836  {
837  printf("The device is in NIDD mode. CoAP observe function cannot be used, because NIDD does not use CoAP.\r\n");
838 
839  return;
840  }
841 
842  printf("Please enter the URL of a resource to be observed:\r\n");
843  scanf("%s",res_url);
844  printf("\r\n");
845  apply_backspace(res_url,80);
846 
847  printf("Please enter the maximum time to wait for server responses (seconds):\r\n");
848  scanf("%i",&wait_time);
849  printf("\r\n");
850 
851  wait_time *= 1000; //Convert to milliseconds
852 
853  CoAP_msg_len = CoAP_assemble_request_extended(COAP_METHOD_GET,1,CoAP_msg,MAX_COAP_MSG_LEN,res_url,NULL,0);
854 
855  if (CoAP_msg_len==0)
856  {
857  printf("Unable to assemble CoAP request; please check the URL; in particular, it must start with '/'.\r\n");
858  return;
859  }
860 
861  printf("CoAP OBSERVE message:\r\n");
862  for (k=0; k<CoAP_msg_len; k++)
863  {
864  printf("%02X ",CoAP_msg[k]);
865  }
866  printf("\r\n");
867 
868  socket_ID = AT_CreateUDPSocket(2*CYCLES_PER_1SEC);
869 
870  if (socket_ID == INVALID_SOCKET_ID)
871  {
872  printf("Unable to create a UDP socket.\r\n");
873  return;
874  }
875 
876  if (AT_SendUDPData(socket_ID,settings->target_server_IP,settings->target_server_port,CoAP_msg,CoAP_msg_len,3*CYCLES_PER_1SEC) != AT_NO_ERROR)
877  {
878  printf("Faled to send CoAP message to server.\r\n");
879  return;
880  }
881 
882  printf("CoAP message with an OBSERVE option was sent.\r\n");
883 
884 #if USE_SERVER_BUG_WORKAROUND != 1
885  printf("Waiting for the initial server response...\r\n");
886 
887  if (wait_coap_server_response(wait_time) == 0)
888  {
890  return;
891  }
892 #else
893 #warning The firmware is compiled with the server bug workaround included. Notice that this version will not work correctly with a standard-compliant server.
894 #endif
895 
896  printf("Waiting for the resource change notification...\r\n");
897 
898  wait_coap_server_response(wait_time);
899 
901 }
902 
904  {set_target_URL,"set the URL of the resource JSON data will be transmitted to"},
905  {set_server_IP,"set the IP address"},
906  {set_server_port,"set the port"},
907  {set_NIDD_APN,"set an APN for NIDD access or turn NIDD mode ON or OFF"},
908  {test_transmit_telemetry,"force send telemetry packet"},
909  {wait_NIDD_URC,"wait for incoming NIDD data during specified timeout (and then exit)"},
910  {test_CoAP_observe_function,"test CoAP OBSERVE function"},
911  {direct_AT_mode,"enter direct AT-command mode"},
912  {true_direct_mode,"enter true direct mode to access the RF module\r\n\t\tCAUTION: to exit this mode you will have to reboot the board physically"},
913  {print_identification_data,"show board identification data (serial numbers, firmware versions, etc.)"},
914  {print_network_info,"show network information"},
915  {set_telemetry_interval,"set telemetry transmission interval"},
916  {set_GNSS_privacy,"set GNSS privacy mode\r\n\t\t(hide actual location data when transmitting on server)"},
917  {set_startup_mode,"set firmware startup mode (setup or logger)"},
918  {test_sensors,"read on-board sensors and try to acquire GNSS data"},
919  {perform_system_reset,"reboot MCU"},
920  {perform_RF_module_reset,"reboot RF module"},
921  {perform_initial_setup,"factory setup & test\r\n\t\t(do not use this unless you really know what you want)"},
922  {NULL,"\0"}
923 };
CYCLES_PER_1SEC
volatile uint32_t CYCLES_PER_1SEC
Калиброванное значение: количество итераций пустого цикла за 1 секунду при текущей тактовой частоте....
Definition: board_support_api.c:11
SETTINGS_SIGNATURE_0
#define SETTINGS_SIGNATURE_0
См. описание поля reserved структуры device_setup_data_t.
Definition: board_support_api.h:90
transmit_telemetry
uint8_t transmit_telemetry(uint8_t *target_IP, uint8_t *target_url, uint16_t target_port, uint8_t *ICCID_string, uint8_t use_NIDD, uint8_t private_gnss)
Передача телеметрии
Definition: main.c:662
device_setup_data_t::logger_mode_on_startup
uint8_t logger_mode_on_startup
Definition: board_support_api.h:120
SETTINGS_SIGNATURE_2
#define SETTINGS_SIGNATURE_2
См. описание поля reserved структуры device_setup_data_t.
Definition: board_support_api.h:94
device_setup_data_t::use_NIDD
uint8_t use_NIDD
Флаг использования технологии NIDD. Если записана единица, передача будет выполняться через NIDD,...
Definition: board_support_api.h:112
CoAP_header_info_t
Definition: coap_essentials.h:102
LIS3DH_ReadXYZ
void LIS3DH_ReadXYZ(uint8_t i2c_addr, int16_t *X, int16_t *Y, int16_t *Z)
Прочесть значения ускорений по осям
Definition: lis3dh_driver.c:67
AT_ReadReponseBuffer
uint16_t AT_ReadReponseBuffer(uint8_t *buffer_out, uint16_t buffer_length, uint8_t *is_overflowed, uint8_t *overrun_detected, uint8_t *error_status, uint32_t max_wait_time)
Чтение ответа модуля.
Definition: at_cmd_support.c:243
get_uptime_ms
uint32_t get_uptime_ms(void)
Возвращает время с момента начала работы прошивки
Definition: board_support_api.c:83
AT_CheckNIDDReceived
uint16_t AT_CheckNIDDReceived(uint8_t *data_out)
Проверка наличия NIDD-данных и, при их наличии, чтение принятой строки
Definition: at_cmd_support.c:498
device_setup_data_t::target_server_IP
uint8_t target_server_IP[48]
IP/IPv6-адрес сервера для передачи телеметрии через IP/IPv6.
Definition: board_support_api.h:101
AT_ReadICCID
uint8_t AT_ReadICCID(uint8_t *ICCID, uint32_t timeout)
Чтение ICCID SIM-карты/чипа
Definition: at_cmd_support.c:683
device_setup_data_t::gnss_privacy_mode
uint8_t gnss_privacy_mode
Если переменная отлична от нуля, в пакет телеметрии не будут включаться истинные данные,...
Definition: board_support_api.h:122
AT_CheckUDPReceived
uint8_t AT_CheckUDPReceived(uint8_t *socket_id, uint16_t *packet_length)
Позволяет проверить, есть ли в буфере радиомодуля входящий UDP-пакет.
Definition: at_cmd_support.c:441
perform_initial_setup
void perform_initial_setup(device_setup_data_t *settings)
Функция, выполняющая заводскую настройку платы и радиомодуля.
Definition: menu_handlers.c:602
is_alphanumeric
uint8_t is_alphanumeric(uint8_t ch)
Вспомогательная функция. Проверяет принадлежность символа к буквам либо цифрам.
Definition: menu_handlers.c:46
CoAP_header_info_t::code_class
uint8_t code_class
Definition: coap_essentials.h:111
device_setup_data_t
Структура, хранящая настройки работы основного демонстрационного приложения
Definition: board_support_api.h:99
LOCAL_ACCEL_I2C_ADDR
#define LOCAL_ACCEL_I2C_ADDR
Адрес акселерометра LIS3DH, установленного на плате
Definition: board_support_api.h:54
LIS3DH_ReadSignature
uint8_t LIS3DH_ReadSignature(uint8_t i2c_addr)
Прочесть индентификационный код акселерометра
Definition: lis3dh_driver.c:23
INVALID_SOCKET_ID
#define INVALID_SOCKET_ID
См. AT_CreateUDPSocket()
Definition: at_cmd_support.h:38
SETTINGS_SIGNATURE_1
#define SETTINGS_SIGNATURE_1
См. описание поля reserved структуры device_setup_data_t.
Definition: board_support_api.h:92
execute_AT_command
uint8_t execute_AT_command(const uint8_t *atcmd)
Вспомогательная функция. Выполняет AT-команду
Definition: menu_handlers.c:16
TMP75_ReadTemperatureCentigrade
int8_t TMP75_ReadTemperatureCentigrade(uint8_t device_addr)
Читает значение регистра температуры из датчика TMP75.
Definition: tmp75_driver.c:9
AT_ReadUDPData
at_udp_error_t AT_ReadUDPData(uint8_t socket_id, uint16_t read_length, uint8_t *source_IP, uint16_t *source_port, uint8_t *data_out, uint32_t max_wait_time)
Чтение данных из указанного UDP-сокета
Definition: at_cmd_support.c:555
AT_SendUDPData
at_udp_error_t AT_SendUDPData(uint8_t socket_id, uint8_t *target_IP_string, uint16_t target_port, uint8_t *data, uint16_t data_length, uint32_t max_wait_time)
Посылает пакет UDP по указанному адресу.
Definition: at_cmd_support.c:390
device_setup_data_t::target_server_port
uint16_t target_server_port
Номер порта на сервере для передачи телеметрии через IP.
Definition: board_support_api.h:110
device_setup_data_t::NIDD_APN_name
uint8_t NIDD_APN_name[64]
Имя APN для NIDD.
Definition: board_support_api.h:105
execute_AT_command_silent
uint8_t execute_AT_command_silent(const uint8_t *cmd, uint8_t *response_out)
Вспомогательная функция. Выполняет AT-команду без вывода результата в консоль
Definition: menu_handlers.c:335
LOCAL_TSENSOR_I2C_ADDR
#define LOCAL_TSENSOR_I2C_ADDR
Адрес термодатчика TMP75, установленного на плате
Definition: board_support_api.h:52
delay_ms
void delay_ms(uint32_t N)
Приостанавливает выполнение программы на заданное время. Значение задержки задается в миллисекундах.
Definition: board_support_api.c:88
SARA_init
uint8_t SARA_init(uint8_t use_NIDD, uint8_t *NIDD_APN)
Инициализация радиомодуля
Definition: main.c:348
CoAP_parse_message
CoAP_parsing_error_t CoAP_parse_message(uint8_t *buf, uint16_t buf_length, uint8_t **data_start)
Выполняет поиск данных в пакете CoAP.
Definition: coap_essentials.c:99
GNSS_ReadLocationData
uint8_t GNSS_ReadLocationData(uint8_t *str_out, uint16_t max_length)
Прочесть данные о местоположении, полученные от GNSS-приемника
Definition: gnss_support.c:80
LOGGER_MODE_VALUE
#define LOGGER_MODE_VALUE
См. описание device_setup_data_t.
Definition: board_support_api.h:87
SARA_R410_PWR_ON_pulse
void SARA_R410_PWR_ON_pulse(void)
Генерирует импульс низкого уровня продолжительностью примерно 500 мс на линии PWR_ON радиомодуля.
Definition: board_support_api.c:129
menu_item_descriptor_t
Definition: menu_handlers.h:32
AT_CreateUDPSocket
uint8_t AT_CreateUDPSocket(uint32_t max_wait_time)
Создает UDP-сокет средствами радиомодуля.
Definition: at_cmd_support.c:324
NMEA_to_LatLon
uint8_t NMEA_to_LatLon(uint8_t *NMEA_string_in, double *dd_lat_out, double *dd_lon_out)
Преобразует данные в формате NMEA (с широтой и долготой в градусах и минутах) в градусы с дробной час...
Definition: main.c:536
device_setup_data_t::target_URL
uint8_t target_URL[128]
URL на сервере для передачи телеметрии через IP.
Definition: board_support_api.h:103
store_device_settings
void store_device_settings(device_setup_data_t *data)
Сохранение настроек устройства в область EEPROM.
Definition: board_support_api.c:158
AT_NO_ERROR
Definition: at_cmd_support.h:50
AT_ReadIMEI
uint8_t AT_ReadIMEI(uint8_t *IMEI, uint32_t timeout)
Чтение IMEI радиомодуля
Definition: at_cmd_support.c:726
AT_SendCommand
void AT_SendCommand(const uint8_t *cmd)
Посылает AT-команду в модуль.
Definition: at_cmd_support.c:318
CoAP_assemble_request_extended
uint16_t CoAP_assemble_request_extended(uint8_t request_method, uint8_t is_observe_request, uint8_t *msg_buffer, uint16_t buffer_length, uint8_t *url_string, uint8_t *data, uint16_t data_length)
Формирует CoAP-сообщение с запросом к серверу
Definition: coap_essentials.c:174
CoAP_parse_message_header
void CoAP_parse_message_header(uint8_t *hdr, CoAP_header_info_t *out)
Выполняет разбор заголовка CoAP-сообщения с извлечением информации в структуру типа CoAP_header_info_...
Definition: coap_essentials.c:12
AT_CloseUDPSocket
uint8_t AT_CloseUDPSocket(uint8_t socket_id, uint32_t max_wait_time)
Закрывает ранее созданный сокет UDP.
Definition: at_cmd_support.c:365
device_setup_data_t::telemetry_interval_ms
uint32_t telemetry_interval_ms
Интервал передачи телеметрии в миллисекундах
Definition: board_support_api.h:108
menu_handlers.h
CoAP_header_info_t::code_detail
uint8_t code_detail
Definition: coap_essentials.h:113
menu_items
const menu_item_descriptor_t menu_items[]
Массив, сопоставляющий указатели на функции, реализующие опции меню настроек, и их описания
Definition: menu_handlers.c:903
device_setup_data_t::reserved
uint8_t reserved[3]
Definition: board_support_api.h:128
apply_backspace
void apply_backspace(uint8_t *str, uint16_t max_length)
Модифицирует строку с учетом символов backspace.
Definition: board_support_api.c:170