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