Paparazzi UAS  v5.12_stable-4-g9b43e9b
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
gsm.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009 ENAC, Arnaud Quintard, Pascal Brisset
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  */
22 
23 /*
24 http://www.telit.com/en/products/gsm-gprs.php?p_ac=show&p=12#downloads
25 
26 Init:
27  Out: ATE0
28  In: OK
29  Out: AT+CMGF=1
30  In: OK
31  Out: AT+CNMI=1,1,0,0,0
32  In: OK
33  Out : AT+CPMS=\"SM\"
34  In: +CPMS:
35 
36 Reporting:
37  Out: AT+CSQ
38  In: +CSQ: <rssi>,<ber>
39  In: OK
40  Out: AT+CMGS=\"GCS_NUMBER\"
41  In: >
42  Out: gps.utm_pos.east, gps.utm_pos.north, gps.course, gps.hmsl, gps.gspeed, -gps.ned_vel.z, vsupply, autopilot.flight_time, rssi CTRLZ
43 
44 Receiving:
45  In: +CMTI: ...,<number>
46  Out: AT+CMGR=<number>
47  In: +CMGR ...
48  In: B42 (or S42 3.14)
49  Out: AT+CMGD=<number>
50  In: OK
51 */
52 
53 #include <stdbool.h>
54 #include <string.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 
58 #include "gsm.h"
59 #include "mcu_periph/uart.h"
60 #include "std.h"
62 #include "subsystems/gps.h"
63 #include "autopilot.h"
64 //#include "subsystems/navigation/common_nav.h" //why is should this be needed?
65 #include "generated/settings.h"
66 
67 #ifndef GSM_LINK
68 #define GSM_LINK UART3100
69 #endif
70 
71 #define GSM_MAX_PAYLOAD 160
72 
73 #define GSMLinkDev (&(GSM_LINK).device)
74 
75 #define GSMLinkChAvailable() GSMLinkDev->check_available(GSMLinkDev->periph)
76 #define GSMLinkTransmit(_c) GSMLinkDev->put_byte(GSMLinkDev->periph, 0, _c)
77 #define GSMLinkGetch() GSMLinkDev->get_byte(GSMLinkDev->periph)
78 #define ReadGSMBuffer() { while (GSMLinkChAvailable&&!gsm_line_received) gsm_parse(GSMLinkGetch()); }
79 
80 
81 #define CTRLZ 0x1A
82 #define GSM_ORIGIN_MAXLEN 32
83 #define DATA_MAXLEN 128
84 
85 #define CMTI "+CMTI:"
86 #define MAXLEN_CMTI_ANSWER 32
87 #define MAXLEN_SMS_CONTENT DATA_MAXLEN
88 
89 static bool gsm_line_received;
90 static bool prompt_received;
91 static bool waiting_for_reply; /* An AT command has been sent and an answer is expected */
92 
93 // static char msg_status[16];
94 // static char msg_date[32];
95 
96 static char expected_ack[10];
97 static char gsm_buf[GSM_MAX_PAYLOAD] __attribute__((aligned));
101 
102 #define STATUS_NONE 0
103 #define STATUS_CSQ 1
104 #define STATUS_REQUESTING_MESSAGE 2
105 #define STATUS_SEND_AT 3
106 #define STATUS_SEND_CMGF 4
107 #define STATUS_SEND_CNMI 5
108 #define STATUS_SEND_CPMS 6
109 #define STATUS_RECEPTION_SMS2 7
110 #define STATUS_WAITING_DATA 8
111 #define STATUS_IDLE 9
112 #define STATUS_WAITING_PROMPT 10
113 #define STATUS_DELETE_SMS 11
114 #define STATUS_POWERON 12
115 
117 
119 
120 static void Send_AT(void);
121 static void Send_CMGF(void);
122 static void Send_CNMI(void);
123 static void Send_CPMS(void);
124 static void Suppr_SMS(int);
125 static void gsm_send_report_continue(void);
126 static void gsm_parse(uint8_t c);
127 static void gsm_got_line(void);
128 static void gsm_got_prompt(void);
129 static void gsm_receive_content(void);
130 static void request_for_msg(void);
131 static void Send_CSQ(void);
132 static void Send(const char string[]);
133 static void parse_msg_header(void);
134 static char *indexn(char *, char, uint8_t);
135 
136 
139 
140 
141 /*****************************************************************************/
142 void gsm_init(void)
143 {
144  if (gsm_status == STATUS_NONE) { /* First call */
145  LED_ON(GSM_ONOFF_LED);
146  gsm_status = STATUS_POWERON;
147  //} else { /* Second call */
148  // gsm_buf_idx = 0;
149  // gsm_line_received = false;
150  //
151  // Send_AT();
152  // gsm_status = STATUS_SEND_AT;
153  // gsm_gsm_init_status = false;
154  }
155  gcs_index = 0;
156  gcs_index_max = 0;
157 #ifdef GCS_NUMBER_1
158  gcs_index_max++;
159 #endif
160 #ifdef GCS_NUMBER_2
161  gcs_index_max++;
162 #endif
163 }
164 
165 void gsm_init_report(void) /* Second call */
166 {
167  if (gsm_status != STATUS_NONE) {
168  gsm_buf_idx = 0;
169  gsm_line_received = false;
170 
171  Send_AT();
172  gsm_status = STATUS_SEND_AT;
173  gsm_gsm_init_report_status = false;
174  }
175 }
176 
177 void gsm_event(void)
178 {
179  if (GSMLinkChAvailable()) {
180  ReadGSMBuffer();
181  }
182 
183  if (gsm_line_received) {
184  if (gsm_buf_len > 0) { DOWNLINK_SEND_DEBUG_GSM_RECEIVE(DefaultChannel, DefaultDevice, gsm_buf_len, gsm_buf); }
185  gsm_got_line();
186  gsm_line_received = false;
187  } else if (prompt_received) {
188  DOWNLINK_SEND_DEBUG_GSM_RECEIVE(DefaultChannel, DefaultDevice, 1, ">");
189  gsm_got_prompt();
190  prompt_received = false;
191  }
192 }
193 
194 
195 // A line of length gsm_buf_len is available in the gsm_buf buffer
196 static void gsm_got_line(void)
197 {
198  if (gsm_status == STATUS_WAITING_DATA) { // Currently receiving a SMS
200  Suppr_SMS(index_msg);
201  gsm_status = STATUS_DELETE_SMS;
202  } else if (gsm_status == STATUS_IDLE
203  && strncmp(CMTI, gsm_buf, strlen(CMTI)) == 0) {
204  /* A SMS is available */
205  /* Extracting the index of the message */
206  char *first_comma = indexn(gsm_buf, ',', MAXLEN_CMTI_ANSWER);
207  if (first_comma) {
208  index_msg = atoi(first_comma + 1);
209  request_for_msg();
210  gsm_status = STATUS_REQUESTING_MESSAGE;
211  }
212  } else if (waiting_for_reply) { // Other cases
213  // Do we get what we were expecting
214 
215  bool gsm_answer = strncmp(expected_ack, gsm_buf, strlen(expected_ack)) == 0;
216  if (gsm_answer) {
217  waiting_for_reply = false;
218 
219  switch (gsm_status) {
220  case STATUS_CSQ :
222  gsm_status = STATUS_WAITING_PROMPT;
223  break;
224 
227  gsm_status = STATUS_WAITING_DATA;
228  break;
229 
230  case STATUS_SEND_AT :
231  gsm_answer = false;
232  Send_CMGF();
233  gsm_status = STATUS_SEND_CMGF;
234  break;
235 
236  case STATUS_SEND_CMGF :
237  gsm_answer = false;
238  Send_CNMI();
239  gsm_status = STATUS_SEND_CNMI;
240  break;
241 
242  case STATUS_SEND_CNMI :
243  gsm_answer = false;
244  Send_CPMS();
245  gsm_status = STATUS_SEND_CPMS;
246  break;
247 
248  case STATUS_SEND_CPMS :
249  gsm_answer = false;
250  gsm_status = STATUS_IDLE;
251  gsm_gsm_send_report_status = MODULES_START;
252  break;
253 
254  case STATUS_DELETE_SMS :
255  gsm_status = STATUS_IDLE;
256  break;
257 
258  default:
259  break;
260  }
261  } else {
262  /* Let's wait for the next line */
263  }
264  }
265 }
266 
267 
268 
269 // Receiving a SMS, first step: asking for a given message
270 static void request_for_msg(void)
271 {
272  char demande_lecture_SMS[16];
273 
274  strcpy(expected_ack, "+CMGR");
275  sprintf(demande_lecture_SMS, "AT+CMGR=%d", index_msg);
276  waiting_for_reply = true;
277  Send(demande_lecture_SMS);
278 }
279 
280 
286 static void gsm_receive_content(void)
287 {
288  // ?????? sprintf(data_to_send, "%d %s %s %s %s", index_msg, flag, expediteur, dateheure, data_recue);
289  // ?????? Send(data_to_send);
290 
291  // Checking the number of the sender
292  if (
293 //#if ! (defined GCS_NUMBER_1 || defined GCS_NUMBER_2 || defined SAFETY_NUMBER_1 || defined SAFETY_NUMBER_2)
294  true
295 //#else
296 // false
297 //#endif
298 #ifdef GCS_NUMBER_1
299  || strncmp((char *)GCS_NUMBER_1, origin, strlen(GCS_NUMBER_1)) == 0
300 #endif
301 #ifdef GCS_NUMBER_2
302  || strncmp((char *)GCS_NUMBER_2, origin, strlen(GCS_NUMBER_2)) == 0
303 #endif
304 #ifdef SAFETY_NUMBER_1
305  || strncmp((char *)SAFETY_NUMBER_1, origin, strlen(SAFETY_NUMBER_1)) == 0
306 #endif
307 #ifdef SAFETY_NUMBER_2
308  || strncmp((char *)SAFETY_NUMBER_2, origin, strlen(SAFETY_NUMBER_2)) == 0
309 #endif
310  ) {
311  // Decoding the message ...
312 
313  // Search for the instruction
314  switch (gsm_buf[0]) {
315  case 'B' : {
316  uint8_t block_index = atoi(gsm_buf + 1);
317  if (block_index > 0) { /* Warning: no way to go to the first block */
318  nav_goto_block(block_index);
319  }
320  break;
321  }
322  case 'S' : {
323  uint8_t var_index = atoi(gsm_buf + 1);
324  if (var_index > 0) {
325  float value = atof(indexn(gsm_buf, ' ', MAXLEN_SMS_CONTENT) + 1);
326  DlSetting(var_index, value);
327  }
328  }
329 
330  default:
331  // Report an error ???
332  break;
333  }
334  }
335 }
336 
337 
338 // Deleting a SMS
339 void Suppr_SMS(int index_)
340 {
341  char demande_suppression[20];
342 
343  sprintf(demande_suppression, "AT+CMGD=%d", index_);
344  strcpy(expected_ack, "OK");
345  waiting_for_reply = true;
346  Send(demande_suppression);
347 }
348 
349 
350 // We just have received a prompt ">" (we are sending a SMS)
351 static void gsm_got_prompt(void)
352 {
353  if (gsm_status == STATUS_WAITING_PROMPT) { // We were waiting for a prompt
354  char string[strlen(data_to_send) + 3];
355 
356  sprintf(string, "%s%c", data_to_send, CTRLZ);
357  Send(string);
358  }
359 
360  gsm_status = STATUS_IDLE;
361 }
362 
365 static void parse_msg_header(void)
366 {
367  /* Extraction du flag*/
370  /* Extraction de l'expediteur*/
371  // Extraction(buffer2, '"', 2, 1, '"', 1, 0, origin);
372 
373  /* Extraction de date heure*/
374  // Extraction(buffer2, '"', 4, 1, '"', 1, 0, msg_date);
375 
376  //pb d'ecriture du flag => solution de fortune (pb si flag != rec unread)
377  //??????? strncpy(flag, flag, 10);
378 }
379 
380 
381 
382 // Periodic message, first step (called every 60s)
384 {
385  gsm_status = STATUS_IDLE;
386  if (gsm_status == STATUS_IDLE) {
387  // Checking the network coverage
388  Send_CSQ();
389  gsm_status = STATUS_CSQ;
390  }
391 }
392 
393 
394 // Sending a message, second step; we have asked for network quality
396 {
397  //We got "+CSQ: <rssi>,<ber>" <rssi> and <ber> on 2 digits (cf 3.5.4.4.4)
398  // and we expect "OK" on the second line
399  uint8_t rssi = atoi(gsm_buf + strlen("+CSQ: "));
400 
401  // Donnee GPS :ne sont pas envoyes gps_mode, gps.tow, gps.utm_pos.zone, gps_nb_ovrn
402  // Donnees batterie (seuls vsupply et autopilot.flight_time sont envoyes)
403  // concatenation de toutes les infos en un seul message à transmettre
404  sprintf(data_to_send, "%ld %ld %d %ld %d %d %d %d %d", gps.utm_pos.east, gps.utm_pos.north, gps_course, gps.hmsl,
406 
407  // send the number and wait for the prompt
408  char buf[32];
409  switch (gcs_index) {
410 #ifdef GCS_NUMBER_1
411  case 0 :
412  sprintf(buf, "AT+CMGS=\"%s\"", GCS_NUMBER_1);
413  Send(buf);
414  break;
415 #endif
416 #ifdef GCS_NUMBER_2
417  case 1 :
418  sprintf(buf, "AT+CMGS=\"%s\"", GCS_NUMBER_2);
419  Send(buf);
420  break;
421 #endif
422  default :
423  gcs_index = 0;
424  break;
425  }
426  gcs_index++;
427  if (gcs_index == gcs_index_max) { gcs_index = 0; }
428 }
429 
430 
431 
432 
433 static void Send_AT(void)
434 {
435  strcpy(expected_ack, "OK");
436  waiting_for_reply = true;
437 
438  Send("ATE0");
439 }
440 
441 static void Send_CMGF(void)
442 {
443  strcpy(expected_ack, "OK");
444  waiting_for_reply = true;
445  Send("AT+CMGF=1");
446 }
447 
448 static void Send_CSQ(void)
449 {
450  /***** FIXME ****** strcpy(expected_ack, "+CSQ:"); ****/
451  strcpy(expected_ack, "OK");
452  waiting_for_reply = true;
453  Send("AT+CSQ");
454 }
455 
456 static void Send_CNMI(void)
457 {
458  strcpy(expected_ack, "OK");
459  waiting_for_reply = true;
460  Send("AT+CNMI=1,1,0,0,0");
461 }
462 
463 static void Send_CPMS(void)
464 {
465  strcpy(expected_ack, "+CPMS:");
466  waiting_for_reply = true;
467  Send("AT+CPMS=\"SM\"");
468 }
469 
470 
471 static void gsm_parse(uint8_t c)
472 {
473  switch (c) {
474  case GSM_CMD_LINE_TERMINATION:
475  break;
476  case '>':
477  prompt_received = true;
478  break;
479  case GSM_RESPONSE_FORMATING:
480  gsm_buf[gsm_buf_idx] = '\0';
481  gsm_line_received = true;
482  gsm_buf_len = gsm_buf_idx;
483  gsm_buf_idx = 0;
484  break;
485  default:
486  if (gsm_buf_idx < GSM_MAX_PAYLOAD) {
487  gsm_buf[gsm_buf_idx] = c;
488  gsm_buf_idx++;
489  } /* else extra characters are ignored */
490  break;
491  }
492 }
493 
494 
495 // Sending a string to the GSM module (through the UART)
496 static void Send(const char string[])
497 {
498  int i = 0;
499 
500  while (string[i]) {
501  GSMTransmit(string[i++]);
502  }
503  GSMTransmit(GSM_CMD_LINE_TERMINATION);
504 
505  DOWNLINK_SEND_DEBUG_GSM_SEND(DefaultChannel, DefaultDevice, i, string);
506 }
507 
508 /* Returns a pointer to the first occurrence of the character c in the firtn
509  n chars of string s. Return NULL if not found */
510 static char *indexn(char *s, char c, uint8_t n)
511 {
512  while (n && (*s != c)) {
513  n--;
514  s++;
515  }
516  return (n ? s : NULL);
517 }
#define GSM_MAX_PAYLOAD
Definition: gsm.c:71
static bool gsm_line_received
Definition: gsm.c:89
int32_t north
in centimeters
static uint8_t gsm_buf_idx
Definition: gsm.c:98
arch independent UART (Universal Asynchronous Receiver/Transmitter) API
static char data_to_send[DATA_MAXLEN]
Definition: gsm.c:100
static bool waiting_for_reply
Definition: gsm.c:91
#define STATUS_REQUESTING_MESSAGE
Definition: gsm.c:104
static void Suppr_SMS(int)
Definition: gsm.c:339
static uint8_t gcs_index
Definition: gsm.c:137
uint16_t flight_time
flight time in seconds
Definition: autopilot.h:61
#define GSM_ORIGIN_MAXLEN
Definition: gsm.c:82
static void parse_msg_header(void)
Message header in gsm_bug.
Definition: gsm.c:365
#define STATUS_SEND_AT
Definition: gsm.c:105
#define ReadGSMBuffer()
Definition: gsm.c:78
static char * indexn(char *, char, uint8_t)
Definition: gsm.c:510
void gsm_init_report(void)
Definition: gsm.c:165
static void gsm_receive_content(void)
Receiving a SMS, third step, content in gsm_buf Message can be Bdd where dd is a block index on two d...
Definition: gsm.c:286
static void gsm_got_prompt(void)
Definition: gsm.c:351
int32_t east
in centimeters
static char origin[GSM_ORIGIN_MAXLEN]
Definition: gsm.c:99
int32_t z
Down.
#define STATUS_CSQ
Definition: gsm.c:103
struct UtmCoor_i utm_pos
position in UTM (north,east: cm; alt: mm over MSL)
Definition: gps.h:87
#define MAXLEN_SMS_CONTENT
Definition: gsm.c:87
#define DATA_MAXLEN
Definition: gsm.c:83
static void Send_CSQ(void)
Definition: gsm.c:448
struct pprz_autopilot autopilot
Global autopilot structure.
Definition: autopilot.c:50
void gsm_send_report()
Definition: gsm.c:383
#define MAXLEN_CMTI_ANSWER
Definition: gsm.c:86
static uint8_t gsm_buf_len
Definition: gsm.c:98
static void Send(const char string[])
Definition: gsm.c:496
#define STATUS_WAITING_PROMPT
Definition: gsm.c:112
uint16_t vsupply
Supply voltage in deciVolt.
void gsm_event(void)
Definition: gsm.c:177
static uint8_t gcs_index_max
Definition: gsm.c:138
static uint8_t index_msg
Definition: gsm.c:118
Communications through GSM.
int32_t hmsl
height above mean sea level (MSL) in mm
Definition: gps.h:88
static void gsm_parse(uint8_t c)
Definition: gsm.c:471
#define STATUS_IDLE
Definition: gsm.c:111
#define GSMLinkChAvailable()
Definition: gsm.c:75
Device independent GPS code (interface)
#define STATUS_SEND_CPMS
Definition: gsm.c:108
static uint8_t gsm_status
Definition: gsm.c:116
static bool prompt_received
Definition: gsm.c:90
#define STATUS_WAITING_DATA
Definition: gsm.c:110
#define STATUS_SEND_CMGF
Definition: gsm.c:106
#define STATUS_NONE
Definition: gsm.c:102
Core autopilot interface common to all firmwares.
#define CMTI
Definition: gsm.c:85
#define STATUS_POWERON
Definition: gsm.c:114
unsigned char uint8_t
Definition: types.h:14
static void Send_CPMS(void)
Definition: gsm.c:463
static void gsm_got_line(void)
Definition: gsm.c:196
#define CTRLZ
Definition: gsm.c:81
static char gsm_buf[GSM_MAX_PAYLOAD]
Definition: gsm.c:97
static void gsm_send_report_continue(void)
Definition: gsm.c:395
static void request_for_msg(void)
Definition: gsm.c:270
#define STATUS_SEND_CNMI
Definition: gsm.c:107
uint16_t gspeed
norm of 2d ground speed in cm/s
Definition: gps.h:91
#define LED_ON(i)
Definition: led_hw.h:50
static char expected_ack[10]
Definition: gsm.c:96
static void Send_AT(void)
Definition: gsm.c:433
static void Send_CNMI(void)
Definition: gsm.c:456
#define STATUS_DELETE_SMS
Definition: gsm.c:113
void gsm_init(void)
Definition: gsm.c:142
void nav_goto_block(uint8_t b)
struct NedCoor_i ned_vel
speed NED in cm/s
Definition: gps.h:90
struct GpsState gps
global GPS state
Definition: gps.c:75
static void Send_CMGF(void)
Definition: gsm.c:441