Commit ee520636 authored by Guillaume Gonnet's avatar Guillaume Gonnet
Browse files

Continue driver module implementation.

parent a56a4bff
......@@ -37,7 +37,7 @@ USEMODULE += cubsat-app
# USEMODULE += cubsat-app-benchmark
USEMODULE += cubsat-app-cmds
USEMODULE += cubsat-app-providers
# USEMODULE += cubsat-app-drivers
USEMODULE += cubsat-app-drivers
USEMODULE += lorariot-ctrl
USEMODULE += lorariot-adapter
USEMODULE += lorariot-region
......
......@@ -8,6 +8,7 @@ MODULE := cubsat-app
DIRS += commands
DIRS += providers
DIRS += drivers
INCLUDES += $(LORARIOT_INC) -I$(CURDIR)
......
......@@ -2,6 +2,7 @@
Driver for the DS75LX digital thermometer.
Copyright (C) 2019, ENSIMAG students
This file is based on DS75LX module from IBM LMIC, under Eclipse Public License
v1.0.
......
......@@ -3,19 +3,521 @@
Decode GPS data.
Copyright (C) 2019, ENSIMAG students
This project is under the MIT license
This file is based on LoRaMAC-node from Semtech, under Revised BSD License.
*/
#include "app.h"
gps_isr_info_t gps_isr_info = { MUTEX_INIT, 0, 0, "\0" };
uint8_t gps_parse_data(void)
{
// TODO.
// TODO: limit update.
return 0;
}
#define TRIGGER_GPS_CNT 10
// Various type of NMEA data we can receive with the GPS.
static const char NmeaDataTypeGPGGA[] = "GPGGA";
static const char NmeaDataTypeGPRMC[] = "GPRMC";
// Value used for the conversion of the position from DMS to decimal.
static const int32_t MaxNorthPosition = 8388607; // 2^23 - 1
static const int32_t MaxSouthPosition = 8388608; // -2^23
static const int32_t MaxEastPosition = 8388607; // 2^23 - 1
static const int32_t MaxWestPosition = 8388608; // -2^23
gps_nmea_t gps_nmea;
// Parsed data in double and binary formats.
static double HasFix = false;
static double latitude = 0;
static double longitude = 0;
static int32_t latitude_bin = 0;
static int32_t longitude_bin = 0;
static int16_t altitude = 0xFFFF;
// Get the lastest GPS position in binary format.
uint8_t gps_position_binary(int32_t *latiBin, int32_t *longiBin)
{
// TODO: lock mutex
uint8_t status = HasFix ? GPS_SUCCESS : GPS_FAIL;
if (!HasFix)
GpsResetPosition();
*latiBin = LatitudeBinary;
*longiBin = LongitudeBinary;
return status;
}
// Get the lastest GPS altitude.
int16_t gps_altitude(void)
{
// TODO: lock mutex
BoardDisableIrq( );
if( HasFix == true )
{
Altitude = atoi( NmeaGpsData.NmeaAltitude );
}
else
{
Altitude = 0xFFFF;
}
BoardEnableIrq( );
return Altitude;
}
void GpsConvertPositionIntoBinary(void)
{
long double temp;
if (latitude >= 0) { // North
temp = latitude * MaxNorthPosition;
latitude_bin = temp / 90;
}
else { // South
temp = latitude * MaxSouthPosition;
latitude_bin = temp / 90;
}
if (longitude >= 0) { // East
temp = longitude * MaxEastPosition;
longitude_bin = temp / 180;
}
else { // West
temp = longitude * MaxWestPosition;
longitude_bin = temp / 180;
}
}
// Convert GPS positions from ASCII to double values.
static void positions_to_double(void)
{
double valueTmp1, valueTmp2, valueTmp3, valueTmp4;
// Convert the latitude from ASCII to uint8_t values.
for (int i = 0 ; i < 10 ; i++ )
gps_nmea.latitude[i] = gps_nmea.latitude[i] & 0xF;
// Convert latitude from degree/minute/second (DMS) format into decimal.
valueTmp1 = (double)gps_nmea.latitude[0] * 10.0 + (double)gps_nmea.latitude[1];
valueTmp2 = (double)gps_nmea.latitude[2] * 10.0 + (double)gps_nmea.latitude[3];
valueTmp3 = (double)gps_nmea.latitude[5] * 1000.0 + (double)gps_nmea.latitude[6] * 100.0 +
(double)gps_nmea.latitude[7] * 10.0 + (double)gps_nmea.latitude[8];
latitude = valueTmp1 + ((valueTmp2 + (valueTmp3 * 0.0001)) / 60.0);
if (gps_nmea.latitude_pole[0] == 'S')
latitude *= -1;
// Convert the longitude from ASCII to uint8_t values.
for (int i = 0 ; i < 10 ; i++)
gps_nmea.longitude[i] = gps_nmea.longitude[i] & 0xF;
// Convert longitude from degree/minute/second (DMS) format into decimal.
valueTmp1 = (double)gps_nmea.longitude[0] * 100.0 + (double)gps_nmea.longitude[1] * 10.0 + (double)gps_nmea.longitude[2];
valueTmp2 = (double)gps_nmea.longitude[3] * 10.0 + (double)gps_nmea.longitude[4];
valueTmp3 = (double)gps_nmea.longitude[6] * 1000.0 + (double)gps_nmea.longitude[7] * 100;
valueTmp4 = (double)gps_nmea.longitude[8] * 10.0 + (double)gps_nmea.longitude[9];
longitude = valueTmp1 + (valueTmp2 / 60.0) + (((valueTmp3 + valueTmp4) * 0.0001) / 60.0);
if (gps_nmea.longitude_pole[0] == 'W')
Longitude *= -1;
}
// Calculates the checksum for a NMEA sentence (and return the position of the
// checksum in the sentence).
static int32_t nmea_checksum(int8_t *nmeaStr, int32_t nmeaStrSize, int8_t *checksum)
{
int i = 0;
uint8_t checkNum = 0;
if ((nmeaStr == NULL) || (checksum == NULL) || (nmeaStrSize <= 1))
return -1;
if (nmeaStr[i] == '$')
i += 1; // Skip the first '$' if necessary.
while (nmeaStr[i] != '*') {
checkNum ^= nmeaStr[i]; // XOR until '*' or max length is reached.
i += 1;
if (i >= nmeaStrSize)
return -1;
}
// Convert checksum value to 2 hexadecimal characters.
checksum[0] = Nibble2HexChar(checkNum / 16); // upper nibble
checksum[1] = Nibble2HexChar(checkNum % 16); // lower nibble
return i + 1;
}
// Calculate the checksum of a NMEA frame and compare it to the checksum that
// is present at the end of it (return true if it matches).
static bool nmea_validate_checksum(int8_t *serialBuff, int32_t buffSize)
{
int32_t checksumIndex;
int8_t checksum[2]; // 2 characters to calculate NMEA checksum.
checksumIndex = nmea_checksum(serialBuff, buffSize, checksum);
if (checksumIndex < 0)
return false;
if (checksumIndex >= (buffSize - 2))
return false; // Not enough char in the serial buffer to read checksum.
return // Check the checksum.
(serialBuff[checksumIndex + 0] == checksum[0]) &&
(serialBuff[checksumIndex + 1] == checksum[1]);
}
// TODO: rename this function.
uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
uint8_t i = 1;
uint8_t j = 0;
if (!nmea_validate_checksum(rxBuffer, rxBufferSize))
return GPS_FAIL;
uint8_t fieldSize = 0;
while (rxBuffer[i + fieldSize++] != ',') {
if (fieldSize > 6)
return GPS_FAIL;
}
for (j = 0; j < fieldSize; j++, i++)
gps_nmea.data_type[j] = rxBuffer[i];
// Parse the GPGGA data.
if (strncmp(gps_nmea.data_type, NmeaDataTypeGPGGA, 5) == 0)
{
// NmeaUtcTime
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 11 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaUtcTime[j] = rxBuffer[i];
}
// NmeaLatitude
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 10 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaLatitude[j] = rxBuffer[i];
}
// NmeaLatitudePole
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaLatitudePole[j] = rxBuffer[i];
}
// NmeaLongitude
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 11 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaLongitude[j] = rxBuffer[i];
}
// NmeaLongitudePole
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaLongitudePole[j] = rxBuffer[i];
}
// NmeaFixQuality
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaFixQuality[j] = rxBuffer[i];
}
// NmeaSatelliteTracked
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 3 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaSatelliteTracked[j] = rxBuffer[i];
}
// NmeaHorizontalDilution
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 6 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaHorizontalDilution[j] = rxBuffer[i];
}
// NmeaAltitude
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 8 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaAltitude[j] = rxBuffer[i];
}
// NmeaAltitudeUnit
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaAltitudeUnit[j] = rxBuffer[i];
}
// NmeaHeightGeoid
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 8 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaHeightGeoid[j] = rxBuffer[i];
}
// NmeaHeightGeoidUnit
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaHeightGeoidUnit[j] = rxBuffer[i];
}
GpsFormatGpsData( );
return SUCCESS;
}
else if (strncmp(NmeaGpsData.NmeaDataType, NmeaDataTypeGPRMC, 5) == 0)
{
// NmeaUtcTime
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 11 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaUtcTime[j] = rxBuffer[i];
}
// NmeaDataStatus
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaDataStatus[j] = rxBuffer[i];
}
// NmeaLatitude
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 10 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaLatitude[j] = rxBuffer[i];
}
// NmeaLatitudePole
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaLatitudePole[j] = rxBuffer[i];
}
// NmeaLongitude
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 11 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
gps_nmea.NmeaLongitude[j] = rxBuffer[i];
}
// NmeaLongitudePole
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 2 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaLongitudePole[j] = rxBuffer[i];
}
// NmeaSpeed
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 8 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaSpeed[j] = rxBuffer[i];
}
// NmeaDetectionAngle
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 8 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaDetectionAngle[j] = rxBuffer[i];
}
// NmeaDate
fieldSize = 0;
while( rxBuffer[i + fieldSize++] != ',' )
{
if( fieldSize > 8 )
{
return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
{
NmeaGpsData.NmeaDate[j] = rxBuffer[i];
}
GpsFormatGpsData( );
return SUCCESS;
}
else
{
return GPS_FAIL;
}
}
void GpsFormatGpsData( void )
{
if( strncmp( ( const char* )NmeaGpsData.NmeaDataType, ( const char* )NmeaDataTypeGPGGA, 5 ) == 0 )
{
HasFix = ( NmeaGpsData.NmeaFixQuality[0] > 0x30 ) ? true : false;
}
else if ( strncmp( ( const char* )NmeaGpsData.NmeaDataType, ( const char* )NmeaDataTypeGPRMC, 5 ) == 0 )
{
HasFix = ( NmeaGpsData.NmeaDataStatus[0] == 0x41 ) ? true : false;
}
positions_to_double( );
GpsConvertPositionIntoBinary( );
}
void GpsResetPosition( void )
{
Altitude = 0xFFFF;
Latitude = 0;
Longitude = 0;
LatitudeBinary = 0;
LongitudeBinary = 0;
}
/*
Decode GPS data.
Copyright (C) 2019, ENSIMAG students
This file is based on LoRaMAC-node from Semtech, under Revised BSD License.
*/
#pragma once
// Return codes.
#define GPS_SUCCESS 0
#define GPS_FAIL 1
// Store the GPS parsed data in ASCII.
typedef struct {
char data_type[6];
char utc_time[11];
char data_status[2];
char latitude[10];
char latitude_pole[2];
char longitude[11];
char longitude_pole[2];
char fix_quality[2];
char satellite_tracked[3];
char horizontal_dilution[6];
char altitude[8];
char altitude_unit[2];
char height_geoid[8];
char height_geoid_unit[2];
char speed[8];
char detection_angle[8];
char date[8];
} gps_nmea_t;
/**
* @brief Get the lastest GPS position in binary format.
* @param latiBin Where to store the latitude.
* @param latiBin Where to store the longitude.
* @return Either `GPS_SUCCESS` or `GPS_FAIL`.
*/
uint8_t gps_position_binary(int32_t *latiBin, int32_t *longiBin);
/**
* @brief Get the lastest GPS altitude.
* @return Altitude (in m) or `0xFFFF` on error.
*/
int16_t gps_altitude(void);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment