mirror of
https://github.com/adrcs/ip400.git
synced 2025-04-21 11:13:42 +03:00
403 lines
10 KiB
C
403 lines
10 KiB
C
/*---------------------------------------------------------------------------
|
|
Project: WL33_NUCLEO_UART
|
|
|
|
File Name: beacon.c
|
|
|
|
Author: MartinA
|
|
|
|
Description: Beacon task. Sends a beacon frame periodically, based on timer in the setup
|
|
structure. The beacon include position data in a readable format, which
|
|
can come from a GPS receiver or the setup struct. Lat/Long data
|
|
is sent in DDMM.MMMMM format.
|
|
|
|
Define __ENABLE_GPS to enable the code.
|
|
|
|
This program 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 of the License, or
|
|
(at your option) any later version, provided this copyright notice
|
|
is included.
|
|
|
|
Copyright (c) Alberta Digital Radio Communications Society
|
|
All rights reserved.
|
|
|
|
Revision History:
|
|
|
|
---------------------------------------------------------------------------*/
|
|
#include <math.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include <cmsis_os2.h>
|
|
#include <FreeRTOS.h>
|
|
#include <stm32wl3x_hal.h>
|
|
|
|
#include "config.h"
|
|
#include "frame.h"
|
|
#include "tasks.h"
|
|
#include "setup.h"
|
|
#include "utils.h"
|
|
#include "tod.h"
|
|
#include "usart.h"
|
|
|
|
// config
|
|
#define __SPEED_DAEMON 0 // send beacon every 5 seconds for testing purposes
|
|
|
|
// local defines
|
|
#define MAX_BEACON 80 // max beacon string
|
|
#define GPS_FIX_LEN 20 // gps fix length
|
|
#define GPS_BFR_SIZE 140 // GPS buffer size
|
|
|
|
#if __ENABLE_GPS
|
|
// NMEA GGA Sentence fields
|
|
char *nmeaMsgTag = "RMC"; // sentence we are processing
|
|
enum {
|
|
NMEA_TAG=0, // message tag
|
|
NMEA_TIMESTAMP, // time of fix'
|
|
NMEA_STATUS, // status
|
|
NMEA_LATITUDE, // latitude
|
|
NMEA_NS_HEMI, // latitude hemisphere
|
|
NMEA_LONGITUDE, // longitude
|
|
NMEA_EW_HEMI, // longitude hemisphere
|
|
NMEA_MIN_FLDS // minimum fields in GPS message
|
|
};
|
|
|
|
// NMEA processing states
|
|
enum {
|
|
NMEA_STATE_SOM=0, // start of message
|
|
NMEA_STATE_MSG, // in the message
|
|
};
|
|
|
|
#define N_NMEA_SEN 14 // number of NMEA sentences
|
|
enum {
|
|
NMEA_CMD_DISABLED=0, // disabled
|
|
NMEA_CMD_ONCE, // once per fix
|
|
NMEA_CMD_2FIX, // once every 2 fixes
|
|
NMEA_CMD_3FIX, // once every 3 fixes
|
|
NMEA_CMD_4FIX, // once every 4 fixes
|
|
NMEA_CMD_5FIX, // once every 5 fixes
|
|
};
|
|
|
|
char *nmeaCmd = "$PMTK314"; // command
|
|
uint8_t senCmds[N_NMEA_SEN] = {
|
|
NMEA_CMD_DISABLED, // 0:GLL disabled
|
|
NMEA_CMD_ONCE, // 1: RMC once
|
|
NMEA_CMD_DISABLED, // 2: VTG disabled
|
|
NMEA_CMD_DISABLED, // 3: GGA disabled
|
|
NMEA_CMD_DISABLED, // 4: GSA disabled
|
|
NMEA_CMD_DISABLED, // 5: GSV disabled
|
|
NMEA_CMD_DISABLED, // 6 not used
|
|
NMEA_CMD_DISABLED, // 7
|
|
NMEA_CMD_DISABLED, // 13
|
|
NMEA_CMD_DISABLED, // 14
|
|
NMEA_CMD_DISABLED, // 15
|
|
NMEA_CMD_DISABLED, // 16
|
|
NMEA_CMD_DISABLED, // 17
|
|
NMEA_CMD_DISABLED // 18
|
|
};
|
|
#endif
|
|
|
|
// hemispheres
|
|
enum {
|
|
N_HEMI=0, // North
|
|
S_HEMI, // South
|
|
E_HEMI, // East
|
|
W_HEMI, // West
|
|
N_HEMIS
|
|
};
|
|
|
|
uint8_t hemispheres[N_HEMIS] = {
|
|
'N', 'S', 'E', 'W'
|
|
};
|
|
|
|
uint32_t timerInitValue; // value to initialize timer
|
|
uint32_t timerCtrValue; // current counter
|
|
BEACON_HEADER beacon_hdr; // beacon header
|
|
uint8_t bcnPayload[MAX_BEACON]; // beacon payload
|
|
BOOL gpsMessageRx = FALSE;
|
|
BOOL GPSBusy=FALSE;
|
|
TIMEOFDAY wallClockTime;
|
|
|
|
#if __ENABLE_GPS
|
|
// data for GPS
|
|
uint8_t GPSMsgBuf[GPS_BFR_SIZE];
|
|
uint8_t GPSEchoBuf[GPS_BFR_SIZE];
|
|
uint8_t GPSProcBuf[GPS_BFR_SIZE];
|
|
uint8_t *GPSBufPtr;
|
|
uint8_t GPSMsgSize;
|
|
uint8_t NMEAState;
|
|
char cmdBuf[MAX_BEACON];
|
|
//
|
|
BOOL haveGPSFix = FALSE;
|
|
BOOL gpsEchoReady=FALSE;
|
|
//
|
|
char GPSLat[GPS_FIX_LEN];
|
|
char GPSLong[GPS_FIX_LEN];
|
|
char GPSFixTime[GPS_FIX_LEN];
|
|
char *gpsFlds[GPS_BFR_SIZE];
|
|
|
|
// fwd Refs in this module in GPS mode
|
|
BOOL processGPSMessage(uint8_t *GPSMsgBuf, uint8_t bufferSize);
|
|
void sendGPSCmd(void);
|
|
#endif
|
|
|
|
//fwd refs w/o GPS
|
|
void GPSFormat(char *buffer, double value, uint8_t hePos, uint8_t heNeg);
|
|
|
|
// initialization: calculate the init value in
|
|
// quanta of MAIN_TASK_SCHED
|
|
void Beacon_Task_init(void)
|
|
{
|
|
// higher speed for testing...
|
|
#if __SPEED_DAEMON
|
|
timerInitValue = 5 *1000/MAIN_TASK_SCHED; // every 5 seconds for testing
|
|
timerCtrValue = 0;
|
|
#else
|
|
uint32_t timerTick = 60 * 1000/MAIN_TASK_SCHED;
|
|
timerInitValue = setup_memory.params.setup_data.beaconInt * timerTick;
|
|
timerCtrValue = 0; // set to timerInitValue to wait
|
|
#endif
|
|
|
|
// GPS Init
|
|
#if __ENABLE_GPS
|
|
gpsMessageRx = FALSE;
|
|
haveGPSFix = FALSE;
|
|
gpsEchoReady = FALSE;
|
|
GPSBufPtr = GPSMsgBuf;
|
|
GPSBusy = FALSE;
|
|
NMEAState=NMEA_STATE_SOM;
|
|
#endif
|
|
|
|
}
|
|
|
|
// this runs every MAIN_TASK_SCHED ms
|
|
void Beacon_Task_exec(void)
|
|
{
|
|
#if __ENABLE_GPS
|
|
if(gpsMessageRx) {
|
|
// process the message
|
|
if(processGPSMessage(GPSProcBuf, (uint8_t)strlen((char *)GPSProcBuf))) {
|
|
haveGPSFix = TRUE;
|
|
}
|
|
gpsMessageRx = FALSE;
|
|
}
|
|
#endif
|
|
|
|
if(timerCtrValue > 0) {
|
|
timerCtrValue--;
|
|
return;
|
|
}
|
|
timerCtrValue = timerInitValue;
|
|
|
|
#if __ENABLE_GPS
|
|
// send a command to the GPS every beacon interval
|
|
sendGPSCmd();
|
|
#endif
|
|
|
|
// start with the header
|
|
beacon_hdr.setup.flags = setup_memory.params.setup_data.flags;
|
|
beacon_hdr.setup.txPower = setup_memory.params.radio_setup.outputPower;
|
|
uint8_t *buf = bcnPayload;
|
|
|
|
// beacon header: flags, txpower and firmware version
|
|
// brute force copy: compiler rounds SETUP_FLAGS to 32 bits
|
|
*buf++ = beacon_hdr.hdrBytes[0];
|
|
*buf++ = beacon_hdr.hdrBytes[4];
|
|
|
|
// firmware version
|
|
*buf++ = def_params.params.FirmwareVerMajor + '0';
|
|
*buf++ = def_params.params.FirmwareVerMinor + '0';
|
|
|
|
char *pPayload = (char *)buf;
|
|
char *p2 = pPayload;
|
|
|
|
#if __ENABLE_GPS
|
|
//GPS generated payload
|
|
if(haveGPSFix) {
|
|
strcpy(pPayload, "GPS,");
|
|
strcat(pPayload, GPSLat);
|
|
strcat(pPayload, ",");
|
|
strcat(pPayload, GPSLong);
|
|
strcat(pPayload, ",");
|
|
strcat(pPayload, GPSFixTime);
|
|
strcat(pPayload, ",");
|
|
} else {
|
|
#endif
|
|
// setup struct generated payload
|
|
strcpy(pPayload, "FXD,");
|
|
pPayload += strlen(pPayload);
|
|
double dlat = ascii2double(setup_memory.params.setup_data.latitude);
|
|
GPSFormat(pPayload, dlat, N_HEMI, S_HEMI);
|
|
strcat(pPayload, ",");
|
|
pPayload += strlen(pPayload);
|
|
double dlong = ascii2double(setup_memory.params.setup_data.longitude);
|
|
GPSFormat(pPayload, dlong, E_HEMI, W_HEMI);
|
|
strcat(pPayload, ",,");
|
|
#if __ENABLE_GPS
|
|
}
|
|
#endif
|
|
pPayload += strlen(pPayload);
|
|
|
|
// Use RTC for time
|
|
getTOD(&wallClockTime);
|
|
sprintf(pPayload, "%02d%02d%02d", wallClockTime.Hours, wallClockTime.Minutes, wallClockTime.Seconds);
|
|
strcat(pPayload, ",");
|
|
|
|
// home grid square
|
|
strcat(pPayload, setup_memory.params.setup_data.gridSq);
|
|
|
|
int pos = strlen((char *)p2);
|
|
buf[pos++] = '\0'; // null terminated
|
|
|
|
pos += 2*sizeof(uint8_t); // account for firmware field
|
|
|
|
// time to send a beacon frame..
|
|
SendBeaconFrame(setup_memory.params.setup_data.stnCall, bcnPayload, pos+1);
|
|
}
|
|
|
|
/*
|
|
* Format the +/-ddd.dddd lat/long format into DDMM.MMMMM format
|
|
*/
|
|
void GPSFormat(char *buffer, double value, uint8_t hePos, uint8_t heNeg)
|
|
{
|
|
// Set hemi, get abs value
|
|
uint8_t hemi = value > 0.00 ? hePos : heNeg;
|
|
value = fabs(value);
|
|
|
|
// separate whole and fractional
|
|
int whole = (int)value;
|
|
double fract = value - (double)whole;
|
|
|
|
// calculate minutes and fraction
|
|
double dmin = 60.0 * fract;
|
|
dmin = round(dmin * 100.0)/100.0;
|
|
|
|
int min = floor(dmin);
|
|
int ifract = (int)ceil((dmin-min) * 100000);
|
|
|
|
sprintf(buffer, "%d%02d.%05d%c", whole, min, ifract, hemispheres[hemi]);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Process GPS data from LPUART: runs at a higher priority
|
|
*/
|
|
void GPS_Task_exec(void)
|
|
{
|
|
#if __ENABLE_GPS
|
|
char c;
|
|
int nBytesinBuff;
|
|
|
|
if((nBytesinBuff=gpsbuffer_bytesInBuffer()) == 0)
|
|
return;
|
|
|
|
for(int i=0;i<nBytesinBuff;i++) {
|
|
c = (char)gpsbuffer_get(0);
|
|
|
|
switch(NMEAState) {
|
|
|
|
// waiting for a start of message
|
|
case NMEA_STATE_SOM:
|
|
if(c != '$')
|
|
break;
|
|
GPSBufPtr = GPSMsgBuf;
|
|
NMEAState=NMEA_STATE_MSG;
|
|
break;
|
|
|
|
// collecting chars in a message
|
|
case NMEA_STATE_MSG:
|
|
*GPSBufPtr++ = c;
|
|
GPSMsgSize = GPSBufPtr - GPSMsgBuf;
|
|
if((c == '*') || (GPSMsgSize >= GPS_BFR_SIZE)) {
|
|
*GPSBufPtr = '\0';
|
|
GPSMsgSize++;
|
|
memcpy(GPSEchoBuf, GPSMsgBuf, GPSMsgSize);
|
|
gpsMessageRx = TRUE;
|
|
memcpy(GPSProcBuf, GPSMsgBuf, GPSMsgSize);
|
|
memcpy(GPSEchoBuf, GPSMsgBuf, GPSMsgSize);
|
|
gpsEchoReady = TRUE;
|
|
NMEAState=NMEA_STATE_SOM;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
return; // unused code
|
|
#endif
|
|
}
|
|
|
|
#if __ENABLE_GPS
|
|
/*
|
|
* Send a command to the GPS device to limit traffic
|
|
*/
|
|
void sendGPSCmd(void)
|
|
{
|
|
uint8_t cksum = 0;
|
|
char *buf = cmdBuf;
|
|
strcpy(buf, nmeaCmd);
|
|
buf += strlen(nmeaCmd);
|
|
|
|
for(int j=1;j<strlen(nmeaCmd);j++)
|
|
cksum ^= nmeaCmd[j];
|
|
|
|
for(int i=0;i<N_NMEA_SEN;i++) {
|
|
*buf = ',';
|
|
cksum ^= *buf++;
|
|
*buf = senCmds[i] + '0';
|
|
cksum ^= *buf++;
|
|
}
|
|
|
|
*buf++ = '*';
|
|
hex2ascii(cksum, buf);
|
|
buf += 2;
|
|
|
|
*buf++ = '\r';
|
|
*buf++ = '\n';
|
|
*buf = '\0';
|
|
uint16_t buflen = buf - cmdBuf;
|
|
|
|
LPUART_Send_String(cmdBuf, buflen);
|
|
}
|
|
/*
|
|
* Process an inbound GPS message
|
|
*/
|
|
BOOL processGPSMessage(uint8_t *GPSdata, uint8_t bufferSize)
|
|
{
|
|
char *msg = (char *)GPSdata;
|
|
uint8_t nParams = explode_string(msg, gpsFlds, bufferSize, ',', '"');
|
|
if ((nParams == 0) || (nParams < NMEA_MIN_FLDS))
|
|
return FALSE;
|
|
|
|
// brute force position fix
|
|
// check for message with GGA at the end
|
|
char *gpsTag = gpsFlds[NMEA_TAG];
|
|
gpsTag += strlen(gpsTag)-strlen(nmeaMsgTag);
|
|
if(strcmp(gpsTag, nmeaMsgTag))
|
|
return FALSE;
|
|
|
|
strcpy(GPSFixTime, gpsFlds[NMEA_TIMESTAMP]);
|
|
|
|
strcpy(GPSLat, gpsFlds[NMEA_LATITUDE]);
|
|
strcat(GPSLat, gpsFlds[NMEA_NS_HEMI]);
|
|
|
|
strcpy(GPSLong, gpsFlds[NMEA_LONGITUDE]);
|
|
strcat(GPSLong, gpsFlds[NMEA_EW_HEMI]);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* echo the last GPS message on the console
|
|
*/
|
|
void GPSEcho(void)
|
|
{
|
|
if(!gpsEchoReady)
|
|
return;
|
|
|
|
USART_Print_string("%s\r\n", (char *)GPSEchoBuf);
|
|
gpsEchoReady=FALSE;
|
|
}
|
|
#endif
|