Moved mutex for concurrent access to radio state inside state.h/.c, minimized the time spent with state mutex locked when updating the GPS data fields

This commit is contained in:
Silvano Seva 2022-06-29 09:50:11 +02:00
parent 101b33ce6b
commit 23a1a38a3a
5 changed files with 81 additions and 56 deletions

View File

@ -22,6 +22,7 @@
#define SETTINGS_H #define SETTINGS_H
#include <hwconfig.h> #include <hwconfig.h>
#include <stdbool.h>
typedef enum typedef enum
{ {

View File

@ -21,11 +21,12 @@
#ifndef STATE_H #ifndef STATE_H
#define STATE_H #define STATE_H
#include <datatypes.h>
#include <stdbool.h>
#include <interfaces/rtc.h> #include <interfaces/rtc.h>
#include <cps.h> #include <datatypes.h>
#include <settings.h> #include <settings.h>
#include <pthread.h>
#include <stdbool.h>
#include <cps.h>
#include <gps.h> #include <gps.h>
/** /**
@ -86,15 +87,17 @@ enum RtxStatus
}; };
extern state_t state; extern state_t state;
extern pthread_mutex_t state_mutex;
/** /**
* This function initializes the Radio state, acquiring the information * Initialise radio state mutex and radio state variable, reading the
* needed to populate it from device drivers. * informations from device drivers.
*/ */
void state_init(); void state_init();
/** /**
* This function terminates the radio state saving persistent settings to flash. * Terminate the radio state saving persistent settings to flash and destroy
* the state mutex.
*/ */
void state_terminate(); void state_terminate();

View File

@ -46,11 +46,12 @@ void gps_taskFunc()
} }
// GPS disabled, nothing to do // GPS disabled, nothing to do
if(gpsEnabled == false) return; if(gpsEnabled == false)
return;
// Acquire a new NMEA sentence from GPS
if(readNewSentence) if(readNewSentence)
{ {
// Acquire a new NMEA sentence from GPS
int status = gps_getNmeaSentence(sentence, MINMEA_MAX_LENGTH + 1); int status = gps_getNmeaSentence(sentence, MINMEA_MAX_LENGTH + 1);
if(status != 0) return; if(status != 0) return;
readNewSentence = false; readNewSentence = false;
@ -59,36 +60,34 @@ void gps_taskFunc()
if(gps_nmeaSentenceReady() == false) if(gps_nmeaSentenceReady() == false)
return; return;
// Parse the sentence and request a new one // Parse the sentence. Work on a local state copy to minimize the time
readNewSentence = true; // spent with the state mutex locked
switch(minmea_sentence_id(sentence, false)) gps_t gps_data;
pthread_mutex_lock(&state_mutex);
gps_data = state.gps_data;
pthread_mutex_unlock(&state_mutex);
int32_t sId = minmea_sentence_id(sentence, false);
switch(sId)
{ {
case MINMEA_SENTENCE_RMC: case MINMEA_SENTENCE_RMC:
{ {
struct minmea_sentence_rmc frame; struct minmea_sentence_rmc frame;
if (minmea_parse_rmc(&frame, sentence)) if (minmea_parse_rmc(&frame, sentence))
{ {
state.gps_data.latitude = minmea_tocoord(&frame.latitude); gps_data.latitude = minmea_tocoord(&frame.latitude);
state.gps_data.longitude = minmea_tocoord(&frame.longitude); gps_data.longitude = minmea_tocoord(&frame.longitude);
state.gps_data.timestamp.hour = frame.time.hours; gps_data.timestamp.hour = frame.time.hours;
state.gps_data.timestamp.minute = frame.time.minutes; gps_data.timestamp.minute = frame.time.minutes;
state.gps_data.timestamp.second = frame.time.seconds; gps_data.timestamp.second = frame.time.seconds;
state.gps_data.timestamp.day = 0; gps_data.timestamp.day = 0;
state.gps_data.timestamp.date = frame.date.day; gps_data.timestamp.date = frame.date.day;
state.gps_data.timestamp.month = frame.date.month; gps_data.timestamp.month = frame.date.month;
state.gps_data.timestamp.year = frame.date.year; gps_data.timestamp.year = frame.date.year;
} }
// Synchronize RTC with GPS UTC clock, only when fix is done gps_data.tmg_true = minmea_tofloat(&frame.course);
if((state.gps_set_time) && gps_data.speed = minmea_tofloat(&frame.speed) * KNOTS2KMH;
(state.gps_data.fix_quality > 0) && (!isRtcSyncronised))
{
rtc_setTime(state.gps_data.timestamp);
isRtcSyncronised = true;
}
state.gps_data.tmg_true = minmea_tofloat(&frame.course);
state.gps_data.speed = minmea_tofloat(&frame.speed) * KNOTS2KMH;
} }
break; break;
@ -97,25 +96,25 @@ void gps_taskFunc()
struct minmea_sentence_gga frame; struct minmea_sentence_gga frame;
if (minmea_parse_gga(&frame, sentence)) if (minmea_parse_gga(&frame, sentence))
{ {
state.gps_data.fix_quality = frame.fix_quality; gps_data.fix_quality = frame.fix_quality;
state.gps_data.satellites_tracked = frame.satellites_tracked; gps_data.satellites_tracked = frame.satellites_tracked;
state.gps_data.altitude = minmea_tofloat(&frame.altitude); gps_data.altitude = minmea_tofloat(&frame.altitude);
} }
} }
break; break;
case MINMEA_SENTENCE_GSA: case MINMEA_SENTENCE_GSA:
{ {
state.gps_data.active_sats = 0; gps_data.active_sats = 0;
struct minmea_sentence_gsa frame; struct minmea_sentence_gsa frame;
if (minmea_parse_gsa(&frame, sentence)) if (minmea_parse_gsa(&frame, sentence))
{ {
state.gps_data.fix_type = frame.fix_type; gps_data.fix_type = frame.fix_type;
for (int i = 0; i < 12; i++) for (int i = 0; i < 12; i++)
{ {
if (frame.sats[i] != 0) if (frame.sats[i] != 0)
{ {
state.gps_data.active_sats |= 1 << (frame.sats[i] - 1); gps_data.active_sats |= 1 << (frame.sats[i] - 1);
} }
} }
} }
@ -131,17 +130,17 @@ void gps_taskFunc()
// When the first sentence arrives, clear all the old data // When the first sentence arrives, clear all the old data
if (frame.msg_nr == 1) if (frame.msg_nr == 1)
{ {
bzero(&state.gps_data.satellites[0], 12 * sizeof(sat_t)); bzero(&gps_data.satellites[0], 12 * sizeof(sat_t));
} }
state.gps_data.satellites_in_view = frame.total_sats; gps_data.satellites_in_view = frame.total_sats;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
int index = 4 * (frame.msg_nr - 1) + i; int index = 4 * (frame.msg_nr - 1) + i;
state.gps_data.satellites[index].id = frame.sats[i].nr; gps_data.satellites[index].id = frame.sats[i].nr;
state.gps_data.satellites[index].elevation = frame.sats[i].elevation; gps_data.satellites[index].elevation = frame.sats[i].elevation;
state.gps_data.satellites[index].azimuth = frame.sats[i].azimuth; gps_data.satellites[index].azimuth = frame.sats[i].azimuth;
state.gps_data.satellites[index].snr = frame.sats[i].snr; gps_data.satellites[index].snr = frame.sats[i].snr;
} }
} }
} }
@ -152,9 +151,9 @@ void gps_taskFunc()
struct minmea_sentence_vtg frame; struct minmea_sentence_vtg frame;
if (minmea_parse_vtg(&frame, sentence)) if (minmea_parse_vtg(&frame, sentence))
{ {
state.gps_data.speed = minmea_tofloat(&frame.speed_kph); gps_data.speed = minmea_tofloat(&frame.speed_kph);
state.gps_data.tmg_mag = minmea_tofloat(&frame.magnetic_track_degrees); gps_data.tmg_mag = minmea_tofloat(&frame.magnetic_track_degrees);
state.gps_data.tmg_true = minmea_tofloat(&frame.true_track_degrees); gps_data.tmg_true = minmea_tofloat(&frame.true_track_degrees);
} }
} }
break; break;
@ -170,4 +169,28 @@ void gps_taskFunc()
case MINMEA_INVALID: break; case MINMEA_INVALID: break;
case MINMEA_UNKNOWN: break; case MINMEA_UNKNOWN: break;
} }
// Update GPS data inside radio state
pthread_mutex_lock(&state_mutex);
state.gps_data = gps_data;
pthread_mutex_unlock(&state_mutex);
// Synchronize RTC with GPS UTC clock, only when fix is done
if(state.gps_set_time)
{
if((sId == MINMEA_SENTENCE_RMC) &&
(gps_data.fix_quality > 0) &&
(isRtcSyncronised == false))
{
rtc_setTime(gps_data.timestamp);
isRtcSyncronised = true;
}
}
else
{
isRtcSyncronised = false;
}
// Finally, trigger the acquisition of a new NMEA sentence
readNewSentence = true;
} }

View File

@ -29,9 +29,12 @@
#include <interfaces/cps_io.h> #include <interfaces/cps_io.h>
state_t state; state_t state;
pthread_mutex_t state_mutex;
void state_init() void state_init()
{ {
pthread_mutex_init(&state_mutex, NULL);
/* /*
* Try loading settings from nonvolatile memory and default to sane values * Try loading settings from nonvolatile memory and default to sane values
* in case of failure. * in case of failure.
@ -102,10 +105,13 @@ void state_terminate()
} }
nvm_writeSettingsAndVfo(&state.settings, &state.channel); nvm_writeSettingsAndVfo(&state.settings, &state.channel);
pthread_mutex_destroy(&state_mutex);
} }
void state_update() void state_update()
{ {
pthread_mutex_lock(&state_mutex);
/* /*
* Low-pass filtering with a time constant of 10s when updated at 1Hz * Low-pass filtering with a time constant of 10s when updated at 1Hz
* Original computation: state.v_bat = 0.02*vbat + 0.98*state.v_bat * Original computation: state.v_bat = 0.02*vbat + 0.98*state.v_bat
@ -121,6 +127,8 @@ void state_update()
#ifdef RTC_PRESENT #ifdef RTC_PRESENT
state.time = rtc_getTime(); state.time = rtc_getTime();
#endif #endif
pthread_mutex_unlock(&state_mutex);
} }
void state_resetSettingsAndVfo() void state_resetSettingsAndVfo()

View File

@ -38,9 +38,6 @@
#include <gps.h> #include <gps.h>
#endif #endif
/* Mutex for concurrent access to state variable */
pthread_mutex_t state_mutex;
/* Mutex for concurrent access to RTX state variable */ /* Mutex for concurrent access to RTX state variable */
pthread_mutex_t rtx_mutex; pthread_mutex_t rtx_mutex;
@ -144,17 +141,13 @@ void *dev_task(void *arg)
while(state.shutdown == false) while(state.shutdown == false)
{ {
// Lock mutex and update internal state // Update radio state
pthread_mutex_lock(&state_mutex);
state_update(); state_update();
pthread_mutex_unlock(&state_mutex);
#if defined(GPS_PRESENT) && !defined(MD3x0_ENABLE_DBG) #if defined(GPS_PRESENT) && !defined(MD3x0_ENABLE_DBG)
if(state.gpsDetected) if(state.gpsDetected)
{ {
pthread_mutex_lock(&state_mutex);
gps_taskFunc(); gps_taskFunc();
pthread_mutex_unlock(&state_mutex);
} }
#endif #endif
@ -199,9 +192,6 @@ void *rtx_task(void *arg)
*/ */
void create_threads() void create_threads()
{ {
// Create state mutex
pthread_mutex_init(&state_mutex, NULL);
// Create RTX state mutex // Create RTX state mutex
pthread_mutex_init(&rtx_mutex, NULL); pthread_mutex_init(&rtx_mutex, NULL);