Paparazzi UAS  v6.0_unstable-53-gfe8bbd3-dirty
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, electrical.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/electrical.h"
65 //#include "subsystems/navigation/common_nav.h" //why is should this be needed?
66 #include "generated/settings.h"
67 #include "led.h"
68 
69 #ifndef GSM_LINK
70 #define GSM_LINK UART3100
71 #endif
72 
73 #define GSM_MAX_PAYLOAD 160
74 
75 #define GSMLinkDev (&(GSM_LINK).device)
76 
77 #define GSMLinkChAvailable() GSMLinkDev->check_available(GSMLinkDev->periph)
78 #define GSMLinkTransmit(_c) GSMLinkDev->put_byte(GSMLinkDev->periph, 0, _c)
79 #define GSMLinkGetch() GSMLinkDev->get_byte(GSMLinkDev->periph)
80 #define ReadGSMBuffer() { while (GSMLinkChAvailable&&!gsm_line_received) gsm_parse(GSMLinkGetch()); }
81 
82 
83 #define CTRLZ 0x1A
84 #define GSM_ORIGIN_MAXLEN 32
85 #define DATA_MAXLEN 128
86 
87 #define CMTI "+CMTI:"
88 #define MAXLEN_CMTI_ANSWER 32
89 #define MAXLEN_SMS_CONTENT DATA_MAXLEN
90 
91 static bool gsm_line_received;
92 static bool prompt_received;
93 static bool waiting_for_reply; /* An AT command has been sent and an answer is expected */
94 
95 // static char msg_status[16];
96 // static char msg_date[32];
97 
98 static char expected_ack[10];
99 static char gsm_buf[GSM_MAX_PAYLOAD] __attribute__((aligned));
103 
104 #define STATUS_NONE 0
105 #define STATUS_CSQ 1
106 #define STATUS_REQUESTING_MESSAGE 2
107 #define STATUS_SEND_AT 3
108 #define STATUS_SEND_CMGF 4
109 #define STATUS_SEND_CNMI 5
110 #define STATUS_SEND_CPMS 6
111 #define STATUS_RECEPTION_SMS2 7
112 #define STATUS_WAITING_DATA 8
113 #define STATUS_IDLE 9
114 #define STATUS_WAITING_PROMPT 10
115 #define STATUS_DELETE_SMS 11
116 #define STATUS_POWERON 12
117 
119 
121 
122 static void Send_AT(void);
123 static void Send_CMGF(void);
124 static void Send_CNMI(void);
125 static void Send_CPMS(void);
126 static void Suppr_SMS(int);
127 static void gsm_send_report_continue(void);
128 static void gsm_parse(uint8_t c);
129 static void gsm_got_line(void);
130 static void gsm_got_prompt(void);
131 static void gsm_receive_content(void);
132 static void request_for_msg(void);
133 static void Send_CSQ(void);
134 static void Send(const char string[]);
135 static void parse_msg_header(void);
136 static char *indexn(char *, char, uint8_t);
137 
138 
141 
142 
143 /*****************************************************************************/
144 void gsm_init(void)
145 {
146  if (gsm_status == STATUS_NONE) { /* First call */
147  LED_ON(GSM_ONOFF_LED);
148  gsm_status = STATUS_POWERON;
149  //} else { /* Second call */
150  // gsm_buf_idx = 0;
151  // gsm_line_received = false;
152  //
153  // Send_AT();
154  // gsm_status = STATUS_SEND_AT;
155  // gsm_gsm_init_status = false;
156  }
157  gcs_index = 0;
158  gcs_index_max = 0;
159 #ifdef GCS_NUMBER_1
160  gcs_index_max++;
161 #endif
162 #ifdef GCS_NUMBER_2
163  gcs_index_max++;
164 #endif
165 }
166 
167 void gsm_init_report(void) /* Second call */
168 {
169  if (gsm_status != STATUS_NONE) {
170  gsm_buf_idx = 0;
171  gsm_line_received = false;
172 
173  Send_AT();
174  gsm_status = STATUS_SEND_AT;
175  gsm_gsm_init_report_status = false;
176  }
177 }
178 
179 void gsm_event(void)
180 {
181  if (GSMLinkChAvailable()) {
182  ReadGSMBuffer();
183  }
184 
185  if (gsm_line_received) {
186  if (gsm_buf_len > 0) { DOWNLINK_SEND_DEBUG_GSM_RECEIVE(DefaultChannel, DefaultDevice, gsm_buf_len, gsm_buf); }
187  gsm_got_line();
188  gsm_line_received = false;
189  } else if (prompt_received) {
190  DOWNLINK_SEND_DEBUG_GSM_RECEIVE(DefaultChannel, DefaultDevice, 1, ">");
191  gsm_got_prompt();
192  prompt_received = false;
193  }
194 }
195 
196 
197 // A line of length gsm_buf_len is available in the gsm_buf buffer
198 static void gsm_got_line(void)
199 {
200  if (gsm_status == STATUS_WAITING_DATA) { // Currently receiving a SMS
202  Suppr_SMS(index_msg);
203  gsm_status = STATUS_DELETE_SMS;
204  } else if (gsm_status == STATUS_IDLE
205  && strncmp(CMTI, gsm_buf, strlen(CMTI)) == 0) {
206  /* A SMS is available */
207  /* Extracting the index of the message */
208  char *first_comma = indexn(gsm_buf, ',', MAXLEN_CMTI_ANSWER);
209  if (first_comma) {
210  index_msg = atoi(first_comma + 1);
211  request_for_msg();
212  gsm_status = STATUS_REQUESTING_MESSAGE;
213  }
214  } else if (waiting_for_reply) { // Other cases
215  // Do we get what we were expecting
216 
217  bool gsm_answer = strncmp(expected_ack, gsm_buf, strlen(expected_ack)) == 0;
218  if (gsm_answer) {
219  waiting_for_reply = false;
220 
221  switch (gsm_status) {
222  case STATUS_CSQ :
224  gsm_status = STATUS_WAITING_PROMPT;
225  break;
226 
229  gsm_status = STATUS_WAITING_DATA;
230  break;
231 
232  case STATUS_SEND_AT :
233  gsm_answer = false;
234  Send_CMGF();
235  gsm_status = STATUS_SEND_CMGF;
236  break;
237 
238  case STATUS_SEND_CMGF :
239  gsm_answer = false;
240  Send_CNMI();
241  gsm_status = STATUS_SEND_CNMI;
242  break;
243 
244  case STATUS_SEND_CNMI :
245  gsm_answer = false;
246  Send_CPMS();
247  gsm_status = STATUS_SEND_CPMS;
248  break;
249 
250  case STATUS_SEND_CPMS :
251  gsm_answer = false;
252  gsm_status = STATUS_IDLE;
253  gsm_gsm_send_report_status = MODULES_START;
254  break;
255 
256  case STATUS_DELETE_SMS :
257  gsm_status = STATUS_IDLE;
258  break;
259 
260  default:
261  break;
262  }
263  } else {
264  /* Let's wait for the next line */
265  }
266  }
267 }
268 
269 
270 
271 // Receiving a SMS, first step: asking for a given message
272 static void request_for_msg(void)
273 {
274  char demande_lecture_SMS[16];
275 
276  strcpy(expected_ack, "+CMGR");
277  sprintf(demande_lecture_SMS, "AT+CMGR=%d", index_msg);
278  waiting_for_reply = true;
279  Send(demande_lecture_SMS);
280 }
281 
282 
288 static void gsm_receive_content(void)
289 {
290  // ?????? sprintf(data_to_send, "%d %s %s %s %s", index_msg, flag, expediteur, dateheure, data_recue);
291  // ?????? Send(data_to_send);
292 
293  // Checking the number of the sender
294  if (
295 //#if ! (defined GCS_NUMBER_1 || defined GCS_NUMBER_2 || defined SAFETY_NUMBER_1 || defined SAFETY_NUMBER_2)
296  true
297 //#else
298 // false
299 //#endif
300 #ifdef GCS_NUMBER_1
301  || strncmp((char *)GCS_NUMBER_1, origin, strlen(GCS_NUMBER_1)) == 0
302 #endif
303 #ifdef GCS_NUMBER_2
304  || strncmp((char *)GCS_NUMBER_2, origin, strlen(GCS_NUMBER_2)) == 0
305 #endif
306 #ifdef SAFETY_NUMBER_1
307  || strncmp((char *)SAFETY_NUMBER_1, origin, strlen(SAFETY_NUMBER_1)) == 0
308 #endif
309 #ifdef SAFETY_NUMBER_2
310  || strncmp((char *)SAFETY_NUMBER_2, origin, strlen(SAFETY_NUMBER_2)) == 0
311 #endif
312  ) {
313  // Decoding the message ...
314 
315  // Search for the instruction
316  switch (gsm_buf[0]) {
317  case 'B' : {
318  uint8_t block_index = atoi(gsm_buf + 1);
319  if (block_index > 0) { /* Warning: no way to go to the first block */
320  nav_goto_block(block_index);
321  }
322  break;
323  }
324  case 'S' : {
325  uint8_t var_index = atoi(gsm_buf + 1);
326  if (var_index > 0) {
327  float value = atof(indexn(gsm_buf, ' ', MAXLEN_SMS_CONTENT) + 1);
328  DlSetting(var_index, value);
329  }
330  }
331 
332  default:
333  // Report an error ???
334  break;
335  }
336  }
337 }
338 
339 
340 // Deleting a SMS
341 void Suppr_SMS(int index_)
342 {
343  char demande_suppression[20];
344 
345  sprintf(demande_suppression, "AT+CMGD=%d", index_);
346  strcpy(expected_ack, "OK");
347  waiting_for_reply = true;
348  Send(demande_suppression);
349 }
350 
351 
352 // We just have received a prompt ">" (we are sending a SMS)
353 static void gsm_got_prompt(void)
354 {
355  if (gsm_status == STATUS_WAITING_PROMPT) { // We were waiting for a prompt
356  char string[strlen(data_to_send) + 3];
357 
358  sprintf(string, "%s%c", data_to_send, CTRLZ);
359  Send(string);
360  }
361 
362  gsm_status = STATUS_IDLE;
363 }
364 
367 static void parse_msg_header(void)
368 {
369  /* Extraction du flag*/
372  /* Extraction de l'expediteur*/
373  // Extraction(buffer2, '"', 2, 1, '"', 1, 0, origin);
374 
375  /* Extraction de date heure*/
376  // Extraction(buffer2, '"', 4, 1, '"', 1, 0, msg_date);
377 
378  //pb d'ecriture du flag => solution de fortune (pb si flag != rec unread)
379  //??????? strncpy(flag, flag, 10);
380 }
381 
382 
383 
384 // Periodic message, first step (called every 60s)
386 {
387  gsm_status = STATUS_IDLE;
388  if (gsm_status == STATUS_IDLE) {
389  // Checking the network coverage
390  Send_CSQ();
391  gsm_status = STATUS_CSQ;
392  }
393 }
394 
395 
396 // Sending a message, second step; we have asked for network quality
398 {
399  //We got "+CSQ: <rssi>,<ber>" <rssi> and <ber> on 2 digits (cf 3.5.4.4.4)
400  // and we expect "OK" on the second line
401  uint8_t rssi = atoi(gsm_buf + strlen("+CSQ: "));
402 
403  // Donnee GPS :ne sont pas envoyes gps_mode, gps.tow, gps.utm_pos.zone, gps_nb_ovrn
404  // Donnees batterie (seuls vsupply et autopilot.flight_time sont envoyes)
405  // concatenation de toutes les infos en un seul message à transmettre
406  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,
408 
409  // send the number and wait for the prompt
410  char buf[32];
411  switch (gcs_index) {
412 #ifdef GCS_NUMBER_1
413  case 0 :
414  sprintf(buf, "AT+CMGS=\"%s\"", GCS_NUMBER_1);
415  Send(buf);
416  break;
417 #endif
418 #ifdef GCS_NUMBER_2
419  case 1 :
420  sprintf(buf, "AT+CMGS=\"%s\"", GCS_NUMBER_2);
421  Send(buf);
422  break;
423 #endif
424  default :
425  gcs_index = 0;
426  break;
427  }
428  gcs_index++;
429  if (gcs_index == gcs_index_max) { gcs_index = 0; }
430 }
431 
432 
433 
434 
435 static void Send_AT(void)
436 {
437  strcpy(expected_ack, "OK");
438  waiting_for_reply = true;
439 
440  Send("ATE0");
441 }
442 
443 static void Send_CMGF(void)
444 {
445  strcpy(expected_ack, "OK");
446  waiting_for_reply = true;
447  Send("AT+CMGF=1");
448 }
449 
450 static void Send_CSQ(void)
451 {
452  /***** FIXME ****** strcpy(expected_ack, "+CSQ:"); ****/
453  strcpy(expected_ack, "OK");
454  waiting_for_reply = true;
455  Send("AT+CSQ");
456 }
457 
458 static void Send_CNMI(void)
459 {
460  strcpy(expected_ack, "OK");
461  waiting_for_reply = true;
462  Send("AT+CNMI=1,1,0,0,0");
463 }
464 
465 static void Send_CPMS(void)
466 {
467  strcpy(expected_ack, "+CPMS:");
468  waiting_for_reply = true;
469  Send("AT+CPMS=\"SM\"");
470 }
471 
472 
473 static void gsm_parse(uint8_t c)
474 {
475  switch (c) {
476  case GSM_CMD_LINE_TERMINATION:
477  break;
478  case '>':
479  prompt_received = true;
480  break;
481  case GSM_RESPONSE_FORMATING:
482  gsm_buf[gsm_buf_idx] = '\0';
483  gsm_line_received = true;
484  gsm_buf_len = gsm_buf_idx;
485  gsm_buf_idx = 0;
486  break;
487  default:
488  if (gsm_buf_idx < GSM_MAX_PAYLOAD) {
489  gsm_buf[gsm_buf_idx] = c;
490  gsm_buf_idx++;
491  } /* else extra characters are ignored */
492  break;
493  }
494 }
495 
496 
497 // Sending a string to the GSM module (through the UART)
498 static void Send(const char string[])
499 {
500  int i = 0;
501 
502  while (string[i]) {
503  GSMTransmit(string[i++]);
504  }
505  GSMTransmit(GSM_CMD_LINE_TERMINATION);
506 
507  DOWNLINK_SEND_DEBUG_GSM_SEND(DefaultChannel, DefaultDevice, i, string);
508 }
509 
510 /* Returns a pointer to the first occurrence of the character c in the firtn
511  n chars of string s. Return NULL if not found */
512 static char *indexn(char *s, char c, uint8_t n)
513 {
514  while (n && (*s != c)) {
515  n--;
516  s++;
517  }
518  return (n ? s : NULL);
519 }
#define GSM_MAX_PAYLOAD
Definition: gsm.c:73
static bool gsm_line_received
Definition: gsm.c:91
int32_t north
in centimeters
static uint8_t gsm_buf_idx
Definition: gsm.c:100
arch independent UART (Universal Asynchronous Receiver/Transmitter) API
static uint32_t s
static char data_to_send[DATA_MAXLEN]
Definition: gsm.c:102
static bool waiting_for_reply
Definition: gsm.c:93
#define STATUS_REQUESTING_MESSAGE
Definition: gsm.c:106
static void Suppr_SMS(int)
Definition: gsm.c:341
static uint8_t gcs_index
Definition: gsm.c:139
uint16_t flight_time
flight time in seconds
Definition: autopilot.h:65
#define GSM_ORIGIN_MAXLEN
Definition: gsm.c:84
static void parse_msg_header(void)
Message header in gsm_bug.
Definition: gsm.c:367
#define STATUS_SEND_AT
Definition: gsm.c:107
#define ReadGSMBuffer()
Definition: gsm.c:80
float vsupply
supply voltage in V
Definition: electrical.h:45
static char * indexn(char *, char, uint8_t)
Definition: gsm.c:512
void gsm_init_report(void)
Definition: gsm.c:167
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:288
static void gsm_got_prompt(void)
Definition: gsm.c:353
int32_t east
in centimeters
static char origin[GSM_ORIGIN_MAXLEN]
Definition: gsm.c:101
int32_t z
Down.
#define STATUS_CSQ
Definition: gsm.c:105
struct UtmCoor_i utm_pos
position in UTM (north,east: cm; alt: mm over MSL)
Definition: gps.h:93
#define MAXLEN_SMS_CONTENT
Definition: gsm.c:89
#define DATA_MAXLEN
Definition: gsm.c:85
static void Send_CSQ(void)
Definition: gsm.c:450
struct pprz_autopilot autopilot
Global autopilot structure.
Definition: autopilot.c:50
void gsm_send_report()
Definition: gsm.c:385
#define MAXLEN_CMTI_ANSWER
Definition: gsm.c:88
static uint8_t gsm_buf_len
Definition: gsm.c:100
static void Send(const char string[])
Definition: gsm.c:498
#define STATUS_WAITING_PROMPT
Definition: gsm.c:114
void gsm_event(void)
Definition: gsm.c:179
static uint8_t gcs_index_max
Definition: gsm.c:140
static uint8_t index_msg
Definition: gsm.c:120
Communications through GSM.
int32_t hmsl
height above mean sea level (MSL) in mm
Definition: gps.h:94
static void gsm_parse(uint8_t c)
Definition: gsm.c:473
Interface for electrical status: supply voltage, current, battery status, etc.
#define STATUS_IDLE
Definition: gsm.c:113
#define GSMLinkChAvailable()
Definition: gsm.c:77
Device independent GPS code (interface)
#define STATUS_SEND_CPMS
Definition: gsm.c:110
static uint8_t gsm_status
Definition: gsm.c:118
static bool prompt_received
Definition: gsm.c:92
#define STATUS_WAITING_DATA
Definition: gsm.c:112
#define STATUS_SEND_CMGF
Definition: gsm.c:108
#define STATUS_NONE
Definition: gsm.c:104
Core autopilot interface common to all firmwares.
#define CMTI
Definition: gsm.c:87
static uint16_t rssi
Definition: cc2500_rx.c:85
#define STATUS_POWERON
Definition: gsm.c:116
static void Send_CPMS(void)
Definition: gsm.c:465
static void gsm_got_line(void)
Definition: gsm.c:198
#define CTRLZ
Definition: gsm.c:83
static char gsm_buf[GSM_MAX_PAYLOAD]
Definition: gsm.c:99
static void gsm_send_report_continue(void)
Definition: gsm.c:397
static void request_for_msg(void)
Definition: gsm.c:272
arch independent LED (Light Emitting Diodes) API
#define STATUS_SEND_CNMI
Definition: gsm.c:109
uint16_t gspeed
norm of 2d ground speed in cm/s
Definition: gps.h:97
#define LED_ON(i)
Definition: led_hw.h:51
static char expected_ack[10]
Definition: gsm.c:98
struct Electrical electrical
Definition: electrical.c:66
static void Send_AT(void)
Definition: gsm.c:435
static void Send_CNMI(void)
Definition: gsm.c:458
#define STATUS_DELETE_SMS
Definition: gsm.c:115
void gsm_init(void)
Definition: gsm.c:144
void nav_goto_block(uint8_t b)
struct NedCoor_i ned_vel
speed NED in cm/s
Definition: gps.h:96
struct GpsState gps
global GPS state
Definition: gps.c:69
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98
static void Send_CMGF(void)
Definition: gsm.c:443