mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-06-04 22:17:01 +08:00
b8c77189c0
This was already once proposed and mergd with #1589 (and reverted again) since with these changes the simulators don't work anymore. So this needs some more work and checking before it can be integrated again.
518 lines
13 KiB
C
518 lines
13 KiB
C
/*
|
|
* Copyright (C) 2009 ENAC, Arnaud Quintard, Pascal Brisset
|
|
*
|
|
* This file is part of paparazzi.
|
|
*
|
|
* paparazzi is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* paparazzi is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with paparazzi; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
http://www.telit.com/en/products/gsm-gprs.php?p_ac=show&p=12#downloads
|
|
|
|
Init:
|
|
Out: ATE0
|
|
In: OK
|
|
Out: AT+CMGF=1
|
|
In: OK
|
|
Out: AT+CNMI=1,1,0,0,0
|
|
In: OK
|
|
Out : AT+CPMS=\"SM\"
|
|
In: +CPMS:
|
|
|
|
Reporting:
|
|
Out: AT+CSQ
|
|
In: +CSQ: <rssi>,<ber>
|
|
In: OK
|
|
Out: AT+CMGS=\"GCS_NUMBER\"
|
|
In: >
|
|
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
|
|
|
|
Receiving:
|
|
In: +CMTI: ...,<number>
|
|
Out: AT+CMGR=<number>
|
|
In: +CMGR ...
|
|
In: B42 (or S42 3.14)
|
|
Out: AT+CMGD=<number>
|
|
In: OK
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "gsm.h"
|
|
#include "mcu_periph/uart.h"
|
|
#include "std.h"
|
|
#include "subsystems/datalink/downlink.h"
|
|
#include "subsystems/gps.h"
|
|
#include "autopilot.h"
|
|
//#include "subsystems/navigation/common_nav.h" //why is should this be needed?
|
|
#include "generated/settings.h"
|
|
|
|
#ifndef GSM_LINK
|
|
#define GSM_LINK UART3100
|
|
#endif
|
|
|
|
#define GSM_MAX_PAYLOAD 160
|
|
|
|
#define GSMLinkDev (&(GSM_LINK).device)
|
|
|
|
#define GSMLinkChAvailable() GSMLinkDev->check_available(GSMLinkDev->periph)
|
|
#define GSMLinkTransmit(_c) GSMLinkDev->put_byte(GSMLinkDev->periph, 0, _c)
|
|
#define GSMLinkGetch() GSMLinkDev->get_byte(GSMLinkDev->periph)
|
|
#define ReadGSMBuffer() { while (GSMLinkChAvailable&&!gsm_line_received) gsm_parse(GSMLinkGetch()); }
|
|
|
|
|
|
#define CTRLZ 0x1A
|
|
#define GSM_ORIGIN_MAXLEN 32
|
|
#define DATA_MAXLEN 128
|
|
|
|
#define CMTI "+CMTI:"
|
|
#define MAXLEN_CMTI_ANSWER 32
|
|
#define MAXLEN_SMS_CONTENT DATA_MAXLEN
|
|
|
|
static bool gsm_line_received;
|
|
static bool prompt_received;
|
|
static bool waiting_for_reply; /* An AT command has been sent and an answer is expected */
|
|
|
|
// static char msg_status[16];
|
|
// static char msg_date[32];
|
|
|
|
static char expected_ack[10];
|
|
static char gsm_buf[GSM_MAX_PAYLOAD] __attribute__((aligned));
|
|
static uint8_t gsm_buf_idx, gsm_buf_len;
|
|
static char origin[GSM_ORIGIN_MAXLEN];
|
|
static char data_to_send[DATA_MAXLEN];
|
|
|
|
#define STATUS_NONE 0
|
|
#define STATUS_CSQ 1
|
|
#define STATUS_REQUESTING_MESSAGE 2
|
|
#define STATUS_SEND_AT 3
|
|
#define STATUS_SEND_CMGF 4
|
|
#define STATUS_SEND_CNMI 5
|
|
#define STATUS_SEND_CPMS 6
|
|
#define STATUS_RECEPTION_SMS2 7
|
|
#define STATUS_WAITING_DATA 8
|
|
#define STATUS_IDLE 9
|
|
#define STATUS_WAITING_PROMPT 10
|
|
#define STATUS_DELETE_SMS 11
|
|
#define STATUS_POWERON 12
|
|
|
|
static uint8_t gsm_status = STATUS_NONE;
|
|
|
|
static uint8_t index_msg;
|
|
|
|
static void Send_AT(void);
|
|
static void Send_CMGF(void);
|
|
static void Send_CNMI(void);
|
|
static void Send_CPMS(void);
|
|
static void Suppr_SMS(int);
|
|
static void gsm_send_report_continue(void);
|
|
static void gsm_parse(uint8_t c);
|
|
static void gsm_got_line(void);
|
|
static void gsm_got_prompt(void);
|
|
static void gsm_receive_content(void);
|
|
static void request_for_msg(void);
|
|
static void Send_CSQ(void);
|
|
static void Send(const char string[]);
|
|
static void parse_msg_header(void);
|
|
static char *indexn(char *, char, uint8_t);
|
|
|
|
|
|
static uint8_t gcs_index;
|
|
static uint8_t gcs_index_max;
|
|
|
|
|
|
/*****************************************************************************/
|
|
void gsm_init(void)
|
|
{
|
|
if (gsm_status == STATUS_NONE) { /* First call */
|
|
LED_ON(GSM_ONOFF_LED);
|
|
gsm_status = STATUS_POWERON;
|
|
//} else { /* Second call */
|
|
// gsm_buf_idx = 0;
|
|
// gsm_line_received = false;
|
|
//
|
|
// Send_AT();
|
|
// gsm_status = STATUS_SEND_AT;
|
|
// gsm_gsm_init_status = false;
|
|
}
|
|
gcs_index = 0;
|
|
gcs_index_max = 0;
|
|
#ifdef GCS_NUMBER_1
|
|
gcs_index_max++;
|
|
#endif
|
|
#ifdef GCS_NUMBER_2
|
|
gcs_index_max++;
|
|
#endif
|
|
}
|
|
|
|
void gsm_init_report(void) /* Second call */
|
|
{
|
|
if (gsm_status != STATUS_NONE) {
|
|
gsm_buf_idx = 0;
|
|
gsm_line_received = false;
|
|
|
|
Send_AT();
|
|
gsm_status = STATUS_SEND_AT;
|
|
gsm_gsm_init_report_status = false;
|
|
}
|
|
}
|
|
|
|
void gsm_event(void)
|
|
{
|
|
if (GSMLinkChAvailable()) {
|
|
ReadGSMBuffer();
|
|
}
|
|
|
|
if (gsm_line_received) {
|
|
if (gsm_buf_len > 0) { DOWNLINK_SEND_DEBUG_GSM_RECEIVE(DefaultChannel, DefaultDevice, gsm_buf_len, gsm_buf); }
|
|
gsm_got_line();
|
|
gsm_line_received = false;
|
|
} else if (prompt_received) {
|
|
DOWNLINK_SEND_DEBUG_GSM_RECEIVE(DefaultChannel, DefaultDevice, 1, ">");
|
|
gsm_got_prompt();
|
|
prompt_received = false;
|
|
}
|
|
}
|
|
|
|
|
|
// A line of length gsm_buf_len is available in the gsm_buf buffer
|
|
static void gsm_got_line(void)
|
|
{
|
|
if (gsm_status == STATUS_WAITING_DATA) { // Currently receiving a SMS
|
|
gsm_receive_content();
|
|
Suppr_SMS(index_msg);
|
|
gsm_status = STATUS_DELETE_SMS;
|
|
} else if (gsm_status == STATUS_IDLE
|
|
&& strncmp(CMTI, gsm_buf, strlen(CMTI)) == 0) {
|
|
/* A SMS is available */
|
|
/* Extracting the index of the message */
|
|
char *first_comma = indexn(gsm_buf, ',', MAXLEN_CMTI_ANSWER);
|
|
if (first_comma) {
|
|
index_msg = atoi(first_comma + 1);
|
|
request_for_msg();
|
|
gsm_status = STATUS_REQUESTING_MESSAGE;
|
|
}
|
|
} else if (waiting_for_reply) { // Other cases
|
|
// Do we get what we were expecting
|
|
|
|
bool gsm_answer = strncmp(expected_ack, gsm_buf, strlen(expected_ack)) == 0;
|
|
if (gsm_answer) {
|
|
waiting_for_reply = false;
|
|
|
|
switch (gsm_status) {
|
|
case STATUS_CSQ :
|
|
gsm_send_report_continue();
|
|
gsm_status = STATUS_WAITING_PROMPT;
|
|
break;
|
|
|
|
case STATUS_REQUESTING_MESSAGE:
|
|
parse_msg_header();
|
|
gsm_status = STATUS_WAITING_DATA;
|
|
break;
|
|
|
|
case STATUS_SEND_AT :
|
|
gsm_answer = false;
|
|
Send_CMGF();
|
|
gsm_status = STATUS_SEND_CMGF;
|
|
break;
|
|
|
|
case STATUS_SEND_CMGF :
|
|
gsm_answer = false;
|
|
Send_CNMI();
|
|
gsm_status = STATUS_SEND_CNMI;
|
|
break;
|
|
|
|
case STATUS_SEND_CNMI :
|
|
gsm_answer = false;
|
|
Send_CPMS();
|
|
gsm_status = STATUS_SEND_CPMS;
|
|
break;
|
|
|
|
case STATUS_SEND_CPMS :
|
|
gsm_answer = false;
|
|
gsm_status = STATUS_IDLE;
|
|
gsm_gsm_send_report_status = MODULES_START; /** Start reporting */
|
|
break;
|
|
|
|
case STATUS_DELETE_SMS :
|
|
gsm_status = STATUS_IDLE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} else { /** We did not get the expected answer */
|
|
/* Let's wait for the next line */
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Receiving a SMS, first step: asking for a given message
|
|
static void request_for_msg(void)
|
|
{
|
|
char demande_lecture_SMS[16];
|
|
|
|
strcpy(expected_ack, "+CMGR");
|
|
sprintf(demande_lecture_SMS, "AT+CMGR=%d", index_msg);
|
|
waiting_for_reply = true;
|
|
Send(demande_lecture_SMS);
|
|
}
|
|
|
|
|
|
/** Receiving a SMS, third step, content in gsm_buf
|
|
Message can be
|
|
Bdd where dd is a block index on two digits. WARNING: dd > 0
|
|
Sdd value where dd>0 is a var index on two digits and value is a float
|
|
*/
|
|
static void gsm_receive_content(void)
|
|
{
|
|
// ?????? sprintf(data_to_send, "%d %s %s %s %s", index_msg, flag, expediteur, dateheure, data_recue);
|
|
// ?????? Send(data_to_send);
|
|
|
|
// Checking the number of the sender
|
|
if (
|
|
//#if ! (defined GCS_NUMBER_1 || defined GCS_NUMBER_2 || defined SAFETY_NUMBER_1 || defined SAFETY_NUMBER_2)
|
|
true
|
|
//#else
|
|
// false
|
|
//#endif
|
|
#ifdef GCS_NUMBER_1
|
|
|| strncmp((char *)GCS_NUMBER_1, origin, strlen(GCS_NUMBER_1)) == 0
|
|
#endif
|
|
#ifdef GCS_NUMBER_2
|
|
|| strncmp((char *)GCS_NUMBER_2, origin, strlen(GCS_NUMBER_2)) == 0
|
|
#endif
|
|
#ifdef SAFETY_NUMBER_1
|
|
|| strncmp((char *)SAFETY_NUMBER_1, origin, strlen(SAFETY_NUMBER_1)) == 0
|
|
#endif
|
|
#ifdef SAFETY_NUMBER_2
|
|
|| strncmp((char *)SAFETY_NUMBER_2, origin, strlen(SAFETY_NUMBER_2)) == 0
|
|
#endif
|
|
) {
|
|
// Decoding the message ...
|
|
|
|
// Search for the instruction
|
|
switch (gsm_buf[0]) {
|
|
case 'B' : {
|
|
uint8_t block_index = atoi(gsm_buf + 1);
|
|
if (block_index > 0) { /* Warning: no way to go to the first block */
|
|
nav_goto_block(block_index);
|
|
}
|
|
break;
|
|
}
|
|
case 'S' : {
|
|
uint8_t var_index = atoi(gsm_buf + 1);
|
|
if (var_index > 0) {
|
|
float value = atof(indexn(gsm_buf, ' ', MAXLEN_SMS_CONTENT) + 1);
|
|
DlSetting(var_index, value);
|
|
}
|
|
}
|
|
|
|
default:
|
|
// Report an error ???
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Deleting a SMS
|
|
void Suppr_SMS(int index_)
|
|
{
|
|
char demande_suppression[20];
|
|
|
|
sprintf(demande_suppression, "AT+CMGD=%d", index_);
|
|
strcpy(expected_ack, "OK");
|
|
waiting_for_reply = true;
|
|
Send(demande_suppression);
|
|
}
|
|
|
|
|
|
// We just have received a prompt ">" (we are sending a SMS)
|
|
static void gsm_got_prompt(void)
|
|
{
|
|
if (gsm_status == STATUS_WAITING_PROMPT) { // We were waiting for a prompt
|
|
char string[strlen(data_to_send) + 3];
|
|
|
|
sprintf(string, "%s%c", data_to_send, CTRLZ);
|
|
Send(string);
|
|
}
|
|
|
|
gsm_status = STATUS_IDLE;
|
|
}
|
|
|
|
/** Message header in gsm_bug
|
|
*/
|
|
static void parse_msg_header(void)
|
|
{
|
|
/* Extraction du flag*/
|
|
/** Extraction(buffer2, '"', 1, 1, '"', 1, 0, msg_status); */
|
|
|
|
/* Extraction de l'expediteur*/
|
|
// Extraction(buffer2, '"', 2, 1, '"', 1, 0, origin);
|
|
|
|
/* Extraction de date heure*/
|
|
// Extraction(buffer2, '"', 4, 1, '"', 1, 0, msg_date);
|
|
|
|
//pb d'ecriture du flag => solution de fortune (pb si flag != rec unread)
|
|
//??????? strncpy(flag, flag, 10);
|
|
}
|
|
|
|
|
|
|
|
// Periodic message, first step (called every 60s)
|
|
void gsm_send_report()
|
|
{
|
|
gsm_status = STATUS_IDLE;
|
|
if (gsm_status == STATUS_IDLE) {
|
|
// Checking the network coverage
|
|
Send_CSQ();
|
|
gsm_status = STATUS_CSQ;
|
|
}
|
|
}
|
|
|
|
|
|
// Sending a message, second step; we have asked for network quality
|
|
void gsm_send_report_continue(void)
|
|
{
|
|
//We got "+CSQ: <rssi>,<ber>" <rssi> and <ber> on 2 digits (cf 3.5.4.4.4)
|
|
// and we expect "OK" on the second line
|
|
uint8_t rssi = atoi(gsm_buf + strlen("+CSQ: "));
|
|
|
|
// Donnee GPS :ne sont pas envoyes gps_mode, gps.tow, gps.utm_pos.zone, gps_nb_ovrn
|
|
// Donnees batterie (seuls vsupply et autopilot_flight_time sont envoyes)
|
|
// concatenation de toutes les infos en un seul message à transmettre
|
|
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,
|
|
gps.gspeed, -gps.ned_vel.z, vsupply, autopilot_flight_time, rssi);
|
|
|
|
// send the number and wait for the prompt
|
|
char buf[32];
|
|
switch (gcs_index) {
|
|
#ifdef GCS_NUMBER_1
|
|
case 0 :
|
|
sprintf(buf, "AT+CMGS=\"%s\"", GCS_NUMBER_1);
|
|
Send(buf);
|
|
break;
|
|
#endif
|
|
#ifdef GCS_NUMBER_2
|
|
case 1 :
|
|
sprintf(buf, "AT+CMGS=\"%s\"", GCS_NUMBER_2);
|
|
Send(buf);
|
|
break;
|
|
#endif
|
|
default :
|
|
gcs_index = 0;
|
|
break;
|
|
}
|
|
gcs_index++;
|
|
if (gcs_index == gcs_index_max) { gcs_index = 0; }
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Send_AT(void)
|
|
{
|
|
strcpy(expected_ack, "OK");
|
|
waiting_for_reply = true;
|
|
|
|
Send("ATE0");
|
|
}
|
|
|
|
static void Send_CMGF(void)
|
|
{
|
|
strcpy(expected_ack, "OK");
|
|
waiting_for_reply = true;
|
|
Send("AT+CMGF=1");
|
|
}
|
|
|
|
static void Send_CSQ(void)
|
|
{
|
|
/***** FIXME ****** strcpy(expected_ack, "+CSQ:"); ****/
|
|
strcpy(expected_ack, "OK");
|
|
waiting_for_reply = true;
|
|
Send("AT+CSQ");
|
|
}
|
|
|
|
static void Send_CNMI(void)
|
|
{
|
|
strcpy(expected_ack, "OK");
|
|
waiting_for_reply = true;
|
|
Send("AT+CNMI=1,1,0,0,0");
|
|
}
|
|
|
|
static void Send_CPMS(void)
|
|
{
|
|
strcpy(expected_ack, "+CPMS:");
|
|
waiting_for_reply = true;
|
|
Send("AT+CPMS=\"SM\"");
|
|
}
|
|
|
|
|
|
static void gsm_parse(uint8_t c)
|
|
{
|
|
switch (c) {
|
|
case GSM_CMD_LINE_TERMINATION:
|
|
break;
|
|
case '>':
|
|
prompt_received = true;
|
|
break;
|
|
case GSM_RESPONSE_FORMATING:
|
|
gsm_buf[gsm_buf_idx] = '\0';
|
|
gsm_line_received = true;
|
|
gsm_buf_len = gsm_buf_idx;
|
|
gsm_buf_idx = 0;
|
|
break;
|
|
default:
|
|
if (gsm_buf_idx < GSM_MAX_PAYLOAD) {
|
|
gsm_buf[gsm_buf_idx] = c;
|
|
gsm_buf_idx++;
|
|
} /* else extra characters are ignored */
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Sending a string to the GSM module (through the UART)
|
|
static void Send(const char string[])
|
|
{
|
|
int i = 0;
|
|
|
|
while (string[i]) {
|
|
GSMTransmit(string[i++]);
|
|
}
|
|
GSMTransmit(GSM_CMD_LINE_TERMINATION);
|
|
|
|
DOWNLINK_SEND_DEBUG_GSM_SEND(DefaultChannel, DefaultDevice, i, string);
|
|
}
|
|
|
|
/* Returns a pointer to the first occurrence of the character c in the firtn
|
|
n chars of string s. Return NULL if not found */
|
|
static char *indexn(char *s, char c, uint8_t n)
|
|
{
|
|
while (n && (*s != c)) {
|
|
n--;
|
|
s++;
|
|
}
|
|
return (n ? s : NULL);
|
|
}
|