Multiple changes.

- Update APRS position packet to include timestamp.
- Add ability to set air pressure level to control GPS airborne mode
- Add capability for time only acquisition from GPS when fixed coord set
- Revise GPIO naming to use IO1 - IO3 (2 & only if not external BME)
pull/4/head
CInsights 2018-04-28 01:05:57 +10:00
rodzic e56eca71e6
commit 061fc953ab
16 zmienionych plików z 616 dodań i 398 usunięć

Wyświetl plik

@ -247,6 +247,9 @@
#define LINE_GPIO_PIN PAL_LINE(GPIOA, 8U) #define LINE_GPIO_PIN PAL_LINE(GPIOA, 8U)
#define LINE_IO_TXD PAL_LINE(GPIOB, 10U) #define LINE_IO_TXD PAL_LINE(GPIOB, 10U)
#define LINE_IO_RXD PAL_LINE(GPIOC, 11U) #define LINE_IO_RXD PAL_LINE(GPIOC, 11U)
#define LINE_IO1 LINE_GPIO_PIN
#define LINE_IO2 LINE_IO_TXD
#define LINE_IO3 LINE_IO_RXD
// LED // LED
#define LINE_IO_BLUE PAL_LINE(GPIOC, 1U) #define LINE_IO_BLUE PAL_LINE(GPIOC, 1U)

Wyświetl plik

@ -131,7 +131,8 @@ const conf_t conf_flash_default = {
.rssi = 0x3F .rssi = 0x3F
}, },
// Node rx identity // Node rx identity
.call = "VK2GJ-4" .call = "VK2GJ-4",
.symbol = SYM_ANTENNA // Use this symbol in message responses
}, },
.tx = { // The transmit identity for digipeat transmit and messages responses .tx = { // The transmit identity for digipeat transmit and messages responses
.radio_conf = { .radio_conf = {
@ -170,6 +171,7 @@ const conf_t conf_flash_default = {
.gps_on_vbat = 1000, .gps_on_vbat = 1000,
.gps_off_vbat = 1000, .gps_off_vbat = 1000,
.gps_onper_vbat = 1000, .gps_onper_vbat = 1000,
.gps_airborne = 90000, // Enable airborne mode below this threshold (Pa)
.magic = CONFIG_MAGIC_DEFAULT // Do not remove. This is the activation bit. .magic = CONFIG_MAGIC_DEFAULT // Do not remove. This is the activation bit.
}; };

Wyświetl plik

@ -395,7 +395,7 @@ uint8_t gps_power_save(int on) {
return gps_receive_ack(0x06, 0x11, 1000); return gps_receive_ack(0x06, 0x11, 1000);
} }
bool GPS_Init(void) { bool GPS_Init(bool airborne) {
// Initialize pins // Initialize pins
TRACE_INFO("GPS > Init pins"); TRACE_INFO("GPS > Init pins");
palSetLineMode(LINE_GPS_RESET, PAL_MODE_OUTPUT_PUSHPULL); // GPS reset palSetLineMode(LINE_GPS_RESET, PAL_MODE_OUTPUT_PUSHPULL); // GPS reset
@ -431,15 +431,16 @@ bool GPS_Init(void) {
return false; return false;
} }
cntr = 3; if(airborne) {
while((status = gps_set_airborne_model()) == false && cntr--); cntr = 3;
if(status) { while((status = gps_set_airborne_model()) == false && cntr--);
TRACE_INFO("GPS > ... Set airborne model OK"); if(status) {
} else { TRACE_INFO("GPS > ... Set airborne model OK");
TRACE_ERROR("GPS > Communication Error [set airborne]"); } else {
return false; TRACE_ERROR("GPS > Communication Error [set airborne]");
} return false;
}
}
return true; return true;
} }

Wyświetl plik

@ -36,7 +36,7 @@ uint8_t gps_power_save(int on);
//uint8_t gps_save_settings(void); //uint8_t gps_save_settings(void);
bool gps_get_fix(gpsFix_t *fix); bool gps_get_fix(gpsFix_t *fix);
bool GPS_Init(void); bool GPS_Init(bool airborne);
void GPS_Deinit(void); void GPS_Deinit(void);
uint32_t GPS_get_mcu_frequency(void); uint32_t GPS_get_mcu_frequency(void);
bool gps_calc_ubx_csum(uint8_t *mbuf, uint16_t mlen); bool gps_calc_ubx_csum(uint8_t *mbuf, uint16_t mlen);

Wyświetl plik

@ -12,45 +12,52 @@ dataPoint_t* flash_getLogBuffer(uint16_t id)
} }
/** /**
* Returns next free log entry address in memory. Returns 0 if all cells are * Returns next free log entry address in memory.
* filled with data * Returns NULL if all entries are used.
*/ */
static dataPoint_t* flash_getNextFreeLogAddress(void) static dataPoint_t* flash_getNextFreeLogAddress(void) {
{ dataPoint_t* tp;
dataPoint_t* tp; for(uint32_t i=0; (tp = flash_getLogBuffer(i)) != NULL; i++) {
for(uint32_t i=0; (tp = flash_getLogBuffer(i)) != NULL; i++) if(LOG_IS_EMPTY(tp))
if(LOG_IS_EMPTY(tp)) return tp;
return tp; }
return NULL;
return NULL;
} }
dataPoint_t* flash_getNewestLogEntry(void) /*
{ *
dataPoint_t* last_tp = NULL; */
uint64_t last_id = 0x0; dataPoint_t* flash_getNewestLogEntry(void) {
dataPoint_t* tp; dataPoint_t* last_tp = NULL;
for(uint32_t i=0; (tp = flash_getLogBuffer(i)) != NULL; i++) { uint64_t last_id = 0x0;
if(!LOG_IS_EMPTY(tp) && last_id <= LOG_RSTandID(tp)) { dataPoint_t* tp;
last_id = LOG_RSTandID(tp); for(uint32_t i=0; (tp = flash_getLogBuffer(i)) != NULL; i++) {
last_tp = tp; if(!LOG_IS_EMPTY(tp) && last_id <= LOG_RSTandID(tp)) {
} last_id = LOG_RSTandID(tp);
} last_tp = tp;
return last_tp; } else {
break;
}
}
return last_tp;
} }
dataPoint_t* flash_getOldestLogEntry(void) /*
{ *
dataPoint_t* first_tp = NULL; */
uint64_t first_id = 0xFFFFFFFFFFFFFFFF; dataPoint_t* flash_getOldestLogEntry(void) {
dataPoint_t* tp; dataPoint_t* first_tp = NULL;
for(uint32_t i=0; (tp = flash_getLogBuffer(i)) != NULL; i++) { uint64_t first_id = 0xFFFFFFFFFFFFFFFF;
if(!LOG_IS_EMPTY(tp) && first_id >= LOG_RSTandID(tp)) { dataPoint_t* tp;
first_id = LOG_RSTandID(tp); for(uint32_t i=0; (tp = flash_getLogBuffer(i)) != NULL; i++) {
first_tp = tp; if(!LOG_IS_EMPTY(tp) && first_id >= LOG_RSTandID(tp)) {
} first_id = LOG_RSTandID(tp);
} first_tp = tp;
return first_tp; } else {
break;
}
}
return first_tp;
} }
/** /**
@ -77,7 +84,7 @@ void flash_writeLogDataPoint(dataPoint_t* tp)
flash_eraseOldestLogData(); flash_eraseOldestLogData();
address = flash_getNextFreeLogAddress(); address = flash_getNextFreeLogAddress();
} }
if(address == NULL) // Something went wront at erasing the memory if(address == NULL) // Something went wrong at erasing the memory
{ {
TRACE_ERROR("LOG > Erasing flash failed"); TRACE_ERROR("LOG > Erasing flash failed");
return; return;

Wyświetl plik

@ -70,7 +70,7 @@ void getTime(ptime_t *date) {
RTCDateTime timespec; RTCDateTime timespec;
rtcGetTime(&RTCD1, &timespec); rtcGetTime(&RTCD1, &timespec);
date->year = timespec.year + 2000; date->year = timespec.year + RTC_BASE_YEAR;
date->month = timespec.month; date->month = timespec.month;
date->day = timespec.day; date->day = timespec.day;
date->hour = timespec.millisecond / 3600000; date->hour = timespec.millisecond / 3600000;
@ -85,7 +85,7 @@ void getTime(ptime_t *date) {
void setTime(ptime_t *date) { void setTime(ptime_t *date) {
TRACE_INFO("GPS > Calibrate RTC"); TRACE_INFO("GPS > Calibrate RTC");
RTCDateTime timespec; RTCDateTime timespec;
timespec.year = date->year - 2000; timespec.year = date->year - RTC_BASE_YEAR;
timespec.month = date->month; timespec.month = date->month;
timespec.day = date->day; timespec.day = date->day;
timespec.millisecond = date->hour * 3600000 + date->minute * 60000 + date->second * 1000; timespec.millisecond = date->hour * 3600000 + date->minute * 60000 + date->second * 1000;

Wyświetl plik

@ -609,7 +609,7 @@ static bool Si446x_transmit(radio_unit_t radio,
chThdSleep(TIME_MS2I(1)); chThdSleep(TIME_MS2I(1));
} }
/* Clear channel timing. */ /* Clear channel timing. */
TRACE_INFO( "SI > CCA completed in %d milliseconds", TRACE_INFO( "SI > CCA attained in %d milliseconds",
chTimeI2MS(chVTTimeElapsedSinceX(t0))); chTimeI2MS(chVTTimeElapsedSinceX(t0)));
} }
@ -1298,7 +1298,7 @@ int16_t Si446x_getLastTemperature(radio_unit_t radio) {
pktAcquireRadio(radio, TIME_INFINITE); pktAcquireRadio(radio, TIME_INFINITE);
// Temperature readout // Temperature readout
lastTemp = Si446x_getTemperature(radio); lastTemp = Si446x_getTemperature(radio);
TRACE_INFO("SI > Transmitter temperature %d degC\r\n", lastTemp/100); TRACE_INFO("SI > Transmitter temperature %d degC", lastTemp/100);
pktReleaseRadio(radio); pktReleaseRadio(radio);
} else { } else {
TRACE_INFO("SI > Transmitter temperature not available"); TRACE_INFO("SI > Transmitter temperature not available");

Wyświetl plik

@ -479,7 +479,7 @@ packet_t ax25_from_text (char *monitor, int strict)
if ( ! ax25_parse_addr (AX25_SOURCE, pa, strict, atemp, &ssid_temp, &heard_temp)) { if ( ! ax25_parse_addr (AX25_SOURCE, pa, strict, atemp, &ssid_temp, &heard_temp)) {
TRACE_ERROR("PKT > Bad source address in packet"); TRACE_ERROR("PKT > Bad source address in packet");
/* Only need single packet release here but linked probably better for consistency. */ /* Only need single packet release here but linked would be fine for consistency. */
pktReleasePacketBuffer(this_p); pktReleasePacketBuffer(this_p);
return (NULL); return (NULL);
} }
@ -2509,10 +2509,12 @@ unsigned short ax25_dedupe_crc (packet_t pp)
* There is a very very small probability that two unrelated * There is a very very small probability that two unrelated
* packets will result in the same checksum, and the * packets will result in the same checksum, and the
* undesired dropping of the packet. * undesired dropping of the packet.
*
* TODO: Deprecate - not used
*
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
unsigned short ax25_m_m_crc (packet_t pp) /*unsigned short ax25_m_m_crc (packet_t pp)
{ {
unsigned short crc; unsigned short crc;
unsigned char fbuf[AX25_MAX_PACKET_LEN]; unsigned char fbuf[AX25_MAX_PACKET_LEN];
@ -2524,7 +2526,7 @@ unsigned short ax25_m_m_crc (packet_t pp)
crc = crc16(fbuf, flen, crc); crc = crc16(fbuf, flen, crc);
return (crc); return (crc);
} }*/
/*------------------------------------------------------------------ /*------------------------------------------------------------------

Wyświetl plik

@ -425,7 +425,7 @@ extern int ax25_get_pid (packet_t this_p);
extern unsigned short ax25_dedupe_crc (packet_t pp); extern unsigned short ax25_dedupe_crc (packet_t pp);
extern unsigned short ax25_m_m_crc (packet_t pp); //extern unsigned short ax25_m_m_crc (packet_t pp);
extern void ax25_safe_print (char *, int, int ascii_only); extern void ax25_safe_print (char *, int, int ascii_only);

Wyświetl plik

@ -173,9 +173,8 @@ const conf_command_t command_list[] = {
const APRSCommand aprs_commands[] = { const APRSCommand aprs_commands[] = {
{"?aprsd", aprs_send_aprsd_message}, {"?aprsd", aprs_send_aprsd_message},
{"?aprsh", aprs_send_aprsh_message}, {"?aprsh", aprs_send_aprsh_message},
{"?aprsp", aprs_send_position_beacon}, {"?aprsp", aprs_send_position_response},
{"?gpio", aprs_execute_gpio_command}, {"?gpio", aprs_execute_gpio_command},
/* {"?gps", aprs_handle_gps_command},*/
{"?reset", aprs_execute_system_reset}, {"?reset", aprs_execute_system_reset},
{"?save", aprs_execute_config_save}, {"?save", aprs_execute_config_save},
{"?img", aprs_execute_img_command}, {"?img", aprs_execute_img_command},
@ -270,6 +269,113 @@ void aprs_debug_getPacket(packet_t pp, char* buf, uint32_t len)
} }
} }
/**
* @brief Transmit APRS position packet.
*
* @param[in] callsign origination call sign
* @param[in] path path to use
* @param[in] symbol symbol for originator
* @param[in] dataPoint position data object
*
* @return encoded packet object pointer
* @retval NULL if encoding failed
*/
packet_t aprs_encode_position(const char *callsign,
const char *path, aprs_sym_t symbol,
dataPoint_t *dataPoint) {
ptime_t time;
unixTimestamp2Date(&time, dataPoint->gps_time);
// Latitude
uint32_t y = 380926 * (90 - dataPoint->gps_lat/10000000.0);
uint32_t y3 = y / 753571;
uint32_t y3r = y % 753571;
uint32_t y2 = y3r / 8281;
uint32_t y2r = y3r % 8281;
uint32_t y1 = y2r / 91;
uint32_t y1r = y2r % 91;
// Longitude
uint32_t x = 190463 * (180 + dataPoint->gps_lon/10000000.0);
uint32_t x3 = x / 753571;
uint32_t x3r = x % 753571;
uint32_t x2 = x3r / 8281;
uint32_t x2r = x3r % 8281;
uint32_t x1 = x2r / 91;
uint32_t x1r = x2r % 91;
// Altitude
uint32_t a = logf(METER_TO_FEET(dataPoint->gps_alt)) / logf(1.002f);
uint32_t a1 = a / 91;
uint32_t a1r = a % 91;
uint8_t gpsFix = dataPoint->gps_state == GPS_LOCKED1
|| dataPoint->gps_state == GPS_LOCKED2
|| dataPoint->gps_state == GPS_FIXED ? GSP_FIX_CURRENT : GSP_FIX_OLD;
uint8_t src = NMEA_SRC_GGA;
uint8_t origin = ORIGIN_PICO;
char xmit[256];
uint32_t len = chsnprintf(xmit, sizeof(xmit), "%s>%s,%s:@%02d%02d%02dz",
callsign,
APRS_DEVICE_CALLSIGN,
path,
time.hour,
time.minute,
time.second);
xmit[len+0] = (symbol >> 8) & 0xFF;
xmit[len+1] = y3+33;
xmit[len+2] = y2+33;
xmit[len+3] = y1+33;
xmit[len+4] = y1r+33;
xmit[len+5] = x3+33;
xmit[len+6] = x2+33;
xmit[len+7] = x1+33;
xmit[len+8] = x1r+33;
xmit[len+9] = symbol & 0xFF;
xmit[len+10] = a1+33;
xmit[len+11] = a1r+33;
xmit[len+12] = ((gpsFix << 5) | (src << 3) | origin) + 33;
// Comments
uint32_t len2 = base91_encode((uint8_t*)dataPoint,
(uint8_t*)&xmit[len+13],
sizeof(dataPoint_t));
xmit[len+len2+13] = '|';
/* APRS base91 encoded telemetry. */
// Sequence ID
uint32_t t = dataPoint->id & 0x1FFF;
xmit[len+len2+14] = t/91 + 33;
xmit[len+len2+15] = t%91 + 33;
// Telemetry analog parameters
for(uint8_t i=0; i<5; i++) {
switch(i) {
case 0: t = dataPoint->adc_vbat; break;
case 1: t = dataPoint->adc_vsol; break;
case 2: t = dataPoint->pac_pbat+4096; break;
case 3: t = dataPoint->sen_i1_temp/10 + 1000; break;
case 4: t = dataPoint->sen_i1_press/125 - 40; break;
}
xmit[len+len2+16+i*2] = t/91 + 33;
xmit[len+len2+16+i*2+1] = t%91 + 33;
}
// Telemetry digital parameter
xmit[len+len2+26] = dataPoint->gpio + 33;
/* Digital bits second byte - set zero. */
xmit[len+len2+27] = 33;
xmit[len+len2+28] = '|';
xmit[len+len2+29] = 0;
return ax25_from_text(xmit, true);
}
/** /**
* @brief Transmit APRS position and telemetry packet. * @brief Transmit APRS position and telemetry packet.
* @notes Base 91 telemetry encoding is used. * @notes Base 91 telemetry encoding is used.
@ -291,8 +397,10 @@ void aprs_debug_getPacket(packet_t pp, char* buf, uint32_t len)
* @retval NULL if encoding failed * @retval NULL if encoding failed
*/ */
packet_t aprs_encode_position_and_telemetry(const char *callsign, packet_t aprs_encode_position_and_telemetry(const char *callsign,
const char *path, uint16_t symbol, const char *path, aprs_sym_t symbol,
dataPoint_t *dataPoint) { dataPoint_t *dataPoint,
bool extended) {
(void)extended;
// Latitude // Latitude
uint32_t y = 380926 * (90 - dataPoint->gps_lat/10000000.0); uint32_t y = 380926 * (90 - dataPoint->gps_lat/10000000.0);
uint32_t y3 = y / 753571; uint32_t y3 = y / 753571;
@ -316,15 +424,24 @@ packet_t aprs_encode_position_and_telemetry(const char *callsign,
uint32_t a1 = a / 91; uint32_t a1 = a / 91;
uint32_t a1r = a % 91; uint32_t a1r = a % 91;
uint8_t gpsFix = dataPoint->gps_state == GPS_LOCKED1 ptime_t time;
|| dataPoint->gps_state == GPS_LOCKED2 unixTimestamp2Date(&time, dataPoint->gps_time);
|| dataPoint->gps_state == GPS_FIXED ? GSP_FIX_CURRENT : GSP_FIX_OLD;
uint8_t src = NMEA_SRC_GGA;
uint8_t origin = ORIGIN_PICO;
char xmit[256]; char xmit[256];
uint32_t len = chsnprintf(xmit, sizeof(xmit), "%s>%s,%s:!", uint32_t len = chsnprintf(xmit, sizeof(xmit), "%s>%s,%s:@%02d%02d%02dz",
callsign, APRS_DEVICE_CALLSIGN, path); callsign,
APRS_DEVICE_CALLSIGN,
path,
time.hour,
time.minute,
time.second);
uint8_t gpsFix = dataPoint->gps_state == GPS_LOCKED1
|| dataPoint->gps_state == GPS_LOCKED2
|| dataPoint->gps_state == GPS_FIXED ? GSP_FIX_CURRENT : GSP_FIX_OLD;
uint8_t src = NMEA_SRC_GGA;
uint8_t origin = ORIGIN_PICO;
xmit[len+0] = (symbol >> 8) & 0xFF; xmit[len+0] = (symbol >> 8) & 0xFF;
xmit[len+1] = y3+33; xmit[len+1] = y3+33;
@ -378,6 +495,9 @@ packet_t aprs_encode_position_and_telemetry(const char *callsign,
return ax25_from_text(xmit, true); return ax25_from_text(xmit, true);
} }
/*
*
*/
packet_t aprs_encode_data_packet(const char *callsign, const char *path, packet_t aprs_encode_data_packet(const char *callsign, const char *path,
char packetType, uint8_t *data) char packetType, uint8_t *data)
{ {
@ -555,101 +675,120 @@ msg_t aprs_execute_gpio_command(aprs_identity_t *id,
if(argc != 1) if(argc != 1)
return MSG_ERROR; return MSG_ERROR;
if(!strcmp(argv[0], "pa8:1")) { char *tok = strtok(argv[0], ":");
TRACE_INFO("RX > Message: GPIO query PA8 HIGH"); if(tok == NULL)
palSetPadMode(GPIOA, 8, PAL_MODE_OUTPUT_PUSHPULL);
palSetPad(GPIOA, 8);
return MSG_OK;
}
if(!strcmp(argv[0], "pa8:0")) {
TRACE_INFO("RX > Message: GPIO query PA8 LOW");
palSetPadMode(GPIOA, 8, PAL_MODE_OUTPUT_PUSHPULL);
palClearPad(GPIOA, 8);
return MSG_OK;
}
if(!strcmp(argv[0], "pa8:?")) {
char buf[AX25_MAX_APRS_MSG_LEN + 1];
/* TODO: Need to read mode and if not output then report as "input" etc. */
chsnprintf(buf, sizeof(buf),
"PA8 is %s ",
(palReadPad(GPIOA, 8) == PAL_HIGH) ? "HIGH" : "LOW");
packet_t pp = aprs_encode_message(id->call, id->path, id->src, buf, false);
if(pp == NULL) {
TRACE_WARN("RX > No free packet objects or badly formed message");
return MSG_ERROR;
}
if(!transmitOnRadio(pp,
id->freq,
0,
0,
id->pwr,
id->mod,
id->cca)) {
TRACE_ERROR("RX > Transmit of GPIO status failed");
return MSG_ERROR;
}
return MSG_OK;
}
return MSG_ERROR;
}
/*
* @brief Handle GPS command
*
* @param[in] id aprs node identity
* @param[in] argc number of parameters
* @param[in] argv array of pointers to parameter strings
*
* @return result of command
* @retval MSG_OK if the command completed.
* @retval MSG_ERROR if there was an error.
*/
/*msg_t aprs_handle_gps_command(aprs_identity_t *id,
int argc, char *argv[]) {
if(argc != 1)
return MSG_ERROR; return MSG_ERROR;
if(!strcmp(argv[0], "fixed")) { /* TODO: WIP to generalize by parsing out the port # and operation. */
TRACE_INFO("RX > Message: GPS set to fixed location"); if(!strcmp(argv[0], "io1:1")) {
test_gps_enabled = true; TRACE_INFO("RX > Message: GPIO set IO1 HIGH");
palSetLineMode(LINE_IO1, PAL_MODE_OUTPUT_PUSHPULL);
palSetLine(LINE_IO1);
return MSG_OK; return MSG_OK;
} }
if(!strcmp(argv[0], "normal")) { if(!strcmp(argv[0], "io1:0")) {
TRACE_INFO("RX > Message: GPS set to normal operation"); TRACE_INFO("RX > Message: GPIO set IO1 LOW");
test_gps_enabled = false; palSetLineMode(LINE_IO1, PAL_MODE_OUTPUT_PUSHPULL);
palClearLine(LINE_IO1);
return MSG_OK; return MSG_OK;
} }
if(!strcmp(argv[0], "status")) { #if ENABLE_EXTERNAL_I2C != TRUE
char buf[AX25_MAX_APRS_MSG_LEN + 1];
chsnprintf(buf, sizeof(buf), if(!strcmp(argv[0], "io2:1")) {
"GPS is %s", TRACE_INFO("RX > Message: GPIO set IO2 HIGH");
test_gps_enabled ? "fixed" : "normal"); palSetLineMode(LINE_IO2, PAL_MODE_OUTPUT_PUSHPULL);
palSetLine(LINE_IO2);
return MSG_OK;
}
packet_t pp = aprs_encode_message(id->call, id->path, id->src, buf, false); if(!strcmp(argv[0], "io2:0")) {
if(pp == NULL) { TRACE_INFO("RX > Message: GPIO set IO2 LOW");
TRACE_WARN("RX > No free packet objects or badly formed message"); palSetLineMode(LINE_IO2, PAL_MODE_OUTPUT_PUSHPULL);
return MSG_ERROR; palClearLine(LINE_IO2);
return MSG_OK;
}
if(!strcmp(argv[0], "io3:1")) {
TRACE_INFO("RX > Message: GPIO set IO3 HIGH");
palSetLineMode(LINE_IO3, PAL_MODE_OUTPUT_PUSHPULL);
palSetLine(LINE_IO3);
return MSG_OK;
}
if(!strcmp(argv[0], "io3:0")) {
TRACE_INFO("RX > Message: GPIO set IO3 LOW");
palSetLineMode(LINE_IO3, PAL_MODE_OUTPUT_PUSHPULL);
palClearLine(LINE_IO3);
return MSG_OK;
}
#endif
/* TODO: Parse out IO number and reduce above and below ugly DRY code. */
packet_t pp;
do {
if(!strcmp(argv[0], "io1:?")) {
char buf[AX25_MAX_APRS_MSG_LEN + 1];
/* TODO: Need to read mode and if not output then report as "input" etc. */
chsnprintf(buf, sizeof(buf),
"IO1 is %s ",
(palReadLine(LINE_IO1) == PAL_HIGH) ? "HIGH" : "LOW");
TRACE_INFO("RX > Message: GPIO query IO1 is %s", (palReadLine(LINE_IO1) == PAL_HIGH) ? "HIGH" : "LOW");
pp = aprs_encode_message(id->call, id->path, id->src, buf, false);
if(pp == NULL) {
TRACE_WARN("RX > No free packet objects or badly formed message");
return MSG_ERROR;
}
break;
} }
if(!transmitOnRadio(pp,
id->freq, #if ENABLE_EXTERNAL_I2C != TRUE
0, if(!strcmp(argv[0], "io2:?")) {
0, char buf[AX25_MAX_APRS_MSG_LEN + 1];
id->pwr, /* TODO: Need to read mode and if not output then report as "input" etc. */
id->mod, chsnprintf(buf, sizeof(buf),
id->rssi)) { "IO2 is %s ",
TRACE_ERROR("RX > Transmit of GPS status failed"); (palReadLine(LINE_IO2) == PAL_HIGH) ? "HIGH" : "LOW");
return MSG_ERROR; TRACE_INFO("RX > Message: GPIO query IO2 is %s", (palReadLine(LINE_IO2) == PAL_HIGH) ? "HIGH" : "LOW");
pp = aprs_encode_message(id->call, id->path, id->src, buf, false);
if(pp == NULL) {
TRACE_WARN("RX > No free packet objects or badly formed message");
return MSG_ERROR;
}
break;
} }
return MSG_OK;
if(!strcmp(argv[0], "io3:?")) {
char buf[AX25_MAX_APRS_MSG_LEN + 1];
/* TODO: Need to read mode and if not output then report as "input" etc. */
chsnprintf(buf, sizeof(buf),
"IO3 is %s ",
(palReadLine(LINE_IO3) == PAL_HIGH) ? "HIGH" : "LOW");
TRACE_INFO("RX > Message: GPIO query IO3 is %s", (palReadLine(LINE_IO3) == PAL_HIGH) ? "HIGH" : "LOW");
pp = aprs_encode_message(id->call, id->path, id->src, buf, false);
if(pp == NULL) {
TRACE_WARN("RX > No free packet objects or badly formed message");
return MSG_ERROR;
}
break;
}
/* No known IO port found. */
return MSG_ERROR;
#endif
} while(true);
if(!transmitOnRadio(pp,
id->freq,
0,
0,
id->pwr,
id->mod,
id->cca)) {
TRACE_ERROR("RX > Transmit of GPIO status failed");
return MSG_ERROR;
} }
return MSG_ERROR; return MSG_OK;
}*/ }
/** /**
* @brief Request for position beacon to be sent * @brief Request for position beacon to be sent
@ -662,16 +801,17 @@ msg_t aprs_execute_gpio_command(aprs_identity_t *id,
* @retval MSG_OK if the command completed. * @retval MSG_OK if the command completed.
* @retval MSG_ERROR if there was an error. * @retval MSG_ERROR if there was an error.
*/ */
msg_t aprs_send_position_beacon(aprs_identity_t *id, msg_t aprs_send_position_response(aprs_identity_t *id,
int argc, char *argv[]) { int argc, char *argv[]) {
(void)argv; (void)argv;
if(argc != 0) if(argc != 0)
return MSG_ERROR; return MSG_ERROR;
/* TODO: Implement a simple (non base 91) position parameter. */
TRACE_INFO("RX > Message: Position query"); TRACE_INFO("RX > Message: Position query");
dataPoint_t* dataPoint = getLastDataPoint(); dataPoint_t* dataPoint = getLastDataPoint();
packet_t pp = aprs_encode_position_and_telemetry(id->call, packet_t pp = aprs_encode_position(id->call,
id->path, id->path,
id->symbol, id->symbol,
dataPoint); dataPoint);
@ -686,7 +826,7 @@ msg_t aprs_send_position_beacon(aprs_identity_t *id,
id->pwr, id->pwr,
id->mod, id->mod,
id->cca)) { id->cca)) {
TRACE_ERROR("RX > Transmit of APRSD failed"); TRACE_ERROR("RX > Transmit of APRSP failed");
return MSG_ERROR; return MSG_ERROR;
} }
return MSG_OK; return MSG_OK;
@ -951,6 +1091,7 @@ static bool aprs_decode_message(packet_t pp) {
&& (conf_sram.aprs.thread_conf.active); && (conf_sram.aprs.thread_conf.active);
if(aprs_rx) { if(aprs_rx) {
strcpy(identity.call, conf_sram.aprs.rx.call); strcpy(identity.call, conf_sram.aprs.rx.call);
identity.symbol = conf_sram.aprs.rx.symbol;
/* Other parameters come from tx identity. */ /* Other parameters come from tx identity. */
} }

Wyświetl plik

@ -87,8 +87,13 @@ extern bool test_gps_enabled;
extern "C" { extern "C" {
#endif #endif
void aprs_debug_getPacket(packet_t pp, char* buf, uint32_t len); void aprs_debug_getPacket(packet_t pp, char* buf, uint32_t len);
packet_t aprs_encode_position_and_telemetry(const char *callsign, const char *path, packet_t aprs_encode_position(const char *callsign,
uint16_t symbol, dataPoint_t *dataPoint); const char *path, aprs_sym_t symbol,
dataPoint_t *dataPoint);
packet_t aprs_encode_position_and_telemetry(const char *callsign,
const char *path,
aprs_sym_t symbol,
dataPoint_t *dataPoint, bool extended);
packet_t aprs_encode_telemetry_configuration(const char *originator, packet_t aprs_encode_telemetry_configuration(const char *originator,
const char *path, const char *path,
const char *destination, const char *destination,
@ -101,7 +106,7 @@ extern "C" {
packet_t aprs_compose_aprsd_message(const char *callsign, const char *path, packet_t aprs_compose_aprsd_message(const char *callsign, const char *path,
const char *receiver); const char *receiver);
void aprs_decode_packet(packet_t pp); void aprs_decode_packet(packet_t pp);
msg_t aprs_send_position_beacon(aprs_identity_t *id, msg_t aprs_send_position_response(aprs_identity_t *id,
int argc, char *argv[]); int argc, char *argv[]);
msg_t aprs_send_aprsd_message(aprs_identity_t *id, msg_t aprs_send_aprsd_message(aprs_identity_t *id,
int argc, char *argv[]); int argc, char *argv[]);

Wyświetl plik

@ -23,7 +23,7 @@
static dataPoint_t dataPoints[2]; static dataPoint_t dataPoints[2];
static dataPoint_t* lastDataPoint; static dataPoint_t* lastDataPoint;
static bool threadStarted = false; static bool threadStarted = false;
static uint8_t attached = 0; static uint8_t useGPS = 0;
/** /**
* Returns most recent data point which is complete. * Returns most recent data point which is complete.
@ -46,94 +46,99 @@ void waitForNewDataPoint(void) {
*/ */
static void aquirePosition(dataPoint_t* tp, dataPoint_t* ltp, static void aquirePosition(dataPoint_t* tp, dataPoint_t* ltp,
sysinterval_t timeout) { sysinterval_t timeout) {
sysinterval_t start = chVTGetSystemTime(); sysinterval_t start = chVTGetSystemTime();
gpsFix_t gpsFix; gpsFix_t gpsFix;
memset(&gpsFix, 0, sizeof(gpsFix_t)); memset(&gpsFix, 0, sizeof(gpsFix_t));
// Switch on GPS if enough power is available and GPS is needed by any position thread // Switch on GPS if enough power is available and GPS is needed by any position thread
uint16_t batt = stm32_get_vbat(); uint16_t batt = stm32_get_vbat();
if(batt < conf_sram.gps_on_vbat) { if(batt < conf_sram.gps_on_vbat) {
tp->gps_state = GPS_LOWBATT1; tp->gps_state = GPS_LOWBATT1;
} else { } else {
// Switch on GPS // Switch on GPS
bool status = GPS_Init(); bool airborne = ltp->sen_i1_press/10 < conf_sram.gps_airborne;
TRACE_INFO("COLL > GPS %s in airborne mode", airborne ? "is" : "is not");
bool status = GPS_Init(airborne);
if(status) { if(status) {
// Search for lock as long as enough power is available // Search for lock as long as enough power is available
do { do {
batt = stm32_get_vbat(); batt = stm32_get_vbat();
gps_get_fix(&gpsFix); gps_get_fix(&gpsFix);
} while(!isGPSLocked(&gpsFix) } while(!isGPSLocked(&gpsFix)
&& batt >= conf_sram.gps_off_vbat && batt >= conf_sram.gps_off_vbat
&& chVTIsSystemTimeWithin(start, start + timeout)); // Do as long no GPS lock and within timeout, timeout=cycle-1sec (-3sec in order to keep synchronization) && chVTIsSystemTimeWithin(start, start + timeout)); // Do as long no GPS lock and within timeout, timeout=cycle-1sec (-3sec in order to keep synchronization)
if(batt < conf_sram.gps_off_vbat) { // GPS was switched on but prematurely switched off because the battery is low on power, switch off GPS if(batt < conf_sram.gps_off_vbat) { // GPS was switched on but prematurely switched off because the battery is low on power, switch off GPS
GPS_Deinit(); GPS_Deinit();
TRACE_WARN("COLL > GPS sampling finished GPS LOW BATT"); TRACE_WARN("COLL > GPS sampling finished GPS LOW BATT");
tp->gps_state = GPS_LOWBATT2; tp->gps_state = GPS_LOWBATT2;
} else if(!isGPSLocked(&gpsFix)) { // GPS was switched on but it failed to get a lock, keep GPS switched on } else if(!isGPSLocked(&gpsFix)) { // GPS was switched on but it failed to get a lock, keep GPS switched on
TRACE_WARN("COLL > GPS sampling finished GPS LOSS"); TRACE_WARN("COLL > GPS sampling finished GPS LOSS");
tp->gps_state = GPS_LOSS; tp->gps_state = GPS_LOSS;
} else { // GPS locked successfully, switch off GPS (unless cycle is less than 60 seconds) } else { // GPS locked successfully, switch off GPS (unless cycle is less than 60 seconds)
// Switch off GPS (if cycle time is more than 60 seconds) // Switch off GPS (if cycle time is more than 60 seconds)
if(timeout < TIME_S2I(60)) { if(timeout < TIME_S2I(60)) {
TRACE_INFO("COLL > Keep GPS switched on because cycle < 60sec"); TRACE_INFO("COLL > Keep GPS switched on because cycle < 60sec");
tp->gps_state = GPS_LOCKED2; tp->gps_state = GPS_LOCKED2;
} else if(conf_sram.gps_onper_vbat != 0 && batt >= conf_sram.gps_onper_vbat) { } else if(conf_sram.gps_onper_vbat != 0 && batt >= conf_sram.gps_onper_vbat) {
TRACE_INFO("COLL > Keep GPS switched on because VBAT >= %dmV", conf_sram.gps_onper_vbat); TRACE_INFO("COLL > Keep GPS switched on because VBAT >= %dmV", conf_sram.gps_onper_vbat);
tp->gps_state = GPS_LOCKED2; tp->gps_state = GPS_LOCKED2;
} else { } else {
TRACE_INFO("COLL > Switch off GPS"); TRACE_INFO("COLL > Switch off GPS");
GPS_Deinit(); GPS_Deinit();
tp->gps_state = GPS_LOCKED1; tp->gps_state = GPS_LOCKED1;
} }
// Debug // Debug
TRACE_INFO("COLL > GPS sampling finished GPS LOCK"); TRACE_INFO("COLL > GPS sampling finished GPS LOCK");
// Calibrate RTC // Calibrate RTC
setTime(&gpsFix.time); setTime(&gpsFix.time);
// Take time from GPS // Take time from GPS
tp->gps_time = date2UnixTimestamp(&gpsFix.time); tp->gps_time = date2UnixTimestamp(&gpsFix.time);
// Set new GPS fix // Set new GPS fix
tp->gps_lat = gpsFix.lat; tp->gps_lat = gpsFix.lat;
tp->gps_lon = gpsFix.lon; tp->gps_lon = gpsFix.lon;
tp->gps_alt = gpsFix.alt; tp->gps_alt = gpsFix.alt;
tp->gps_sats = gpsFix.num_svs; tp->gps_sats = gpsFix.num_svs;
tp->gps_pdop = (gpsFix.pdop+3)/5; tp->gps_pdop = (gpsFix.pdop+3)/5;
} }
} else { // GPS communication error } else { // GPS communication error
GPS_Deinit(); GPS_Deinit();
tp->gps_state = GPS_ERROR; tp->gps_state = GPS_ERROR;
} }
} }
tp->gps_ttff = TIME_I2S(chVTGetSystemTime() - start); // Time to first fix tp->gps_ttff = TIME_I2S(chVTGetSystemTime() - start); // Time to first fix
if(tp->gps_state != GPS_LOCKED1 && tp->gps_state != GPS_LOCKED2) { // We have no valid GPS fix if(tp->gps_state != GPS_LOCKED1 && tp->gps_state != GPS_LOCKED2) { // We have no valid GPS fix
// Take time from internal RTC // Take time from internal RTC
ptime_t time; ptime_t time;
getTime(&time); getTime(&time);
tp->gps_time = date2UnixTimestamp(&time); if(time.year != RTC_BASE_YEAR) {
/* RTC has been set so OK to use data. */
tp->gps_time = date2UnixTimestamp(&time);
// Take GPS fix from old lock // Take GPS fix from old lock
tp->gps_lat = ltp->gps_lat; tp->gps_lat = ltp->gps_lat;
tp->gps_lon = ltp->gps_lon; tp->gps_lon = ltp->gps_lon;
tp->gps_alt = ltp->gps_alt; tp->gps_alt = ltp->gps_alt;
} } /* Else don't set tp data since RTC is not valid. */
}
} }
/* /*
@ -259,132 +264,179 @@ static void setSystemStatus(dataPoint_t* tp) {
* Data Collector (Thread) * Data Collector (Thread)
*/ */
THD_FUNCTION(collectorThread, arg) { THD_FUNCTION(collectorThread, arg) {
uint8_t *attached = arg; uint8_t *useGPS = arg;
uint32_t id = 0; uint32_t id = 0;
lastDataPoint = &dataPoints[0];
// Read time from RTC // Read time from RTC
ptime_t time; ptime_t time;
getTime(&time); getTime(&time);
lastDataPoint->gps_time = date2UnixTimestamp(&time); dataPoints[0].gps_time = date2UnixTimestamp(&time);
dataPoints[1].gps_time = date2UnixTimestamp(&time);
// Get last data point from memory lastDataPoint = &dataPoints[0];
TRACE_INFO("COLL > Read last data point from flash memory");
dataPoint_t* lastLogPoint = flash_getNewestLogEntry();
if(lastLogPoint != NULL) { // If there is stored data point, then get the last know GPS fix // Get last data point from memory
dataPoints[0].reset = lastLogPoint->reset+1; TRACE_INFO("COLL > Read last data point from flash memory");
dataPoints[1].reset = lastLogPoint->reset+1; dataPoint_t* lastLogPoint = flash_getNewestLogEntry();
lastDataPoint->gps_lat = lastLogPoint->gps_lat;
lastDataPoint->gps_lon = lastLogPoint->gps_lon;
lastDataPoint->gps_alt = lastLogPoint->gps_alt;
lastDataPoint->gps_sats = lastLogPoint->gps_sats;
lastDataPoint->gps_ttff = lastLogPoint->gps_ttff;
TRACE_INFO( if(lastLogPoint != NULL) { // If there is stored data point, then get it.
"COLL > Last data point (from memory)\r\n" dataPoints[0].reset = lastLogPoint->reset+1;
"%s Reset %d ID %d\r\n" dataPoints[1].reset = lastLogPoint->reset+1;
"%s Latitude: %d.%07ddeg\r\n" unixTimestamp2Date(&time, lastDataPoint->gps_time);
"%s Longitude: %d.%07ddeg\r\n" lastDataPoint->gps_lat = lastLogPoint->gps_lat;
"%s Altitude: %d Meter", lastDataPoint->gps_lon = lastLogPoint->gps_lon;
TRACE_TAB, lastLogPoint->reset, lastLogPoint->id, lastDataPoint->gps_alt = lastLogPoint->gps_alt;
TRACE_TAB, lastDataPoint->gps_lat/10000000, (lastDataPoint->gps_lat > 0 ? 1:-1)*lastDataPoint->gps_lat%10000000, lastDataPoint->gps_sats = lastLogPoint->gps_sats;
TRACE_TAB, lastDataPoint->gps_lon/10000000, (lastDataPoint->gps_lon > 0 ? 1:-1)*lastDataPoint->gps_lon%10000000, lastDataPoint->gps_ttff = lastLogPoint->gps_ttff;
TRACE_TAB, lastDataPoint->gps_alt
);
} else {
TRACE_INFO("COLL > No data point found in flash memory");
}
lastDataPoint->gps_state = GPS_LOG; // Mark dataPoint as LOG packet TRACE_INFO(
"COLL > Last data point (from memory)\r\n"
"%s Reset %d ID %d\r\n"
"%s Time %04d-%02d-%02d %02d:%02d:%02d\r\n"
"%s Latitude: %d.%07ddeg\r\n"
"%s Longitude: %d.%07ddeg\r\n"
"%s Altitude: %d Meter",
TRACE_TAB, lastLogPoint->reset, lastLogPoint->id,
TRACE_TAB, time.year, time.month, time.day, time.hour,
time.minute, time.day,
TRACE_TAB, lastDataPoint->gps_lat/10000000,
(lastDataPoint->gps_lat > 0
? 1:-1)*lastDataPoint->gps_lat%10000000,
TRACE_TAB, lastDataPoint->gps_lon/10000000,
(lastDataPoint->gps_lon > 0
? 1:-1)*lastDataPoint->gps_lon%10000000,
TRACE_TAB, lastDataPoint->gps_alt
);
lastDataPoint->gps_state = GPS_LOG; // Mark dataPoint as LOG packet
} else {
TRACE_INFO("COLL > No data point found in flash memory");
lastDataPoint->gps_state = GPS_OFF; // Mark dataPoint unset
}
// Measure telemetry // Measure telemetry
measureVoltage(lastDataPoint); measureVoltage(lastDataPoint);
getSensors(lastDataPoint); getSensors(lastDataPoint);
getGPIO(lastDataPoint); getGPIO(lastDataPoint);
setSystemStatus(lastDataPoint); setSystemStatus(lastDataPoint);
// Write data point to Flash memory // Write data point to Flash memory
flash_writeLogDataPoint(lastDataPoint); flash_writeLogDataPoint(lastDataPoint);
// Wait for position threads to start // Wait for position threads to start
chThdSleep(TIME_MS2I(500)); chThdSleep(TIME_MS2I(500));
sysinterval_t cycle_time = chVTGetSystemTime(); sysinterval_t cycle_time = chVTGetSystemTime();
while(true) while(true)
{ {
TRACE_INFO("COLL > Do module DATA COLLECTOR cycle"); TRACE_INFO("COLL > Do module DATA COLLECTOR cycle");
dataPoint_t* tp = &dataPoints[(id+1) % 2]; // Current data point (the one which is processed now) dataPoint_t* tp = &dataPoints[(id+1) % 2]; // Current data point (the one which is processed now)
dataPoint_t* ltp = &dataPoints[ id % 2]; // Last data point dataPoint_t* ltp = &dataPoints[ id % 2]; // Last data point
// Determine cycle time and if GPS should be used. // Determine cycle time and if GPS should be used.
sysinterval_t data_cycle_time = TIME_S2I(600); sysinterval_t data_cycle_time = TIME_S2I(600);
if(conf_sram.pos_pri.thread_conf.active && conf_sram.pos_sec.thread_conf.active) { // Both position threads are active if(conf_sram.pos_pri.thread_conf.active && conf_sram.pos_sec.thread_conf.active) { // Both position threads are active
data_cycle_time = conf_sram.pos_pri.thread_conf.cycle < conf_sram.pos_sec.thread_conf.cycle ? conf_sram.pos_pri.thread_conf.cycle : conf_sram.pos_sec.thread_conf.cycle; // Choose the smallest cycle data_cycle_time = conf_sram.pos_pri.thread_conf.cycle < conf_sram.pos_sec.thread_conf.cycle ? conf_sram.pos_pri.thread_conf.cycle : conf_sram.pos_sec.thread_conf.cycle; // Choose the smallest cycle
(*attached)++; (*useGPS)++;
} else if(conf_sram.pos_pri.thread_conf.active) { // Only primary position thread is active } else if(conf_sram.pos_pri.thread_conf.active) { // Only primary position thread is active
data_cycle_time = conf_sram.pos_pri.thread_conf.cycle; data_cycle_time = conf_sram.pos_pri.thread_conf.cycle;
(*attached)++; (*useGPS)++;
} else if(conf_sram.pos_sec.thread_conf.active) { // Only secondary position thread is active } else if(conf_sram.pos_sec.thread_conf.active) { // Only secondary position thread is active
data_cycle_time = conf_sram.pos_sec.thread_conf.cycle; data_cycle_time = conf_sram.pos_sec.thread_conf.cycle;
(*attached)++; (*useGPS)++;
} else if(conf_sram.aprs.thread_conf.active && conf_sram.aprs.tx.beacon) { // APRS beacon is active } else if(conf_sram.aprs.thread_conf.active && conf_sram.aprs.tx.beacon) { // APRS beacon is active
data_cycle_time = conf_sram.pos_sec.thread_conf.cycle; data_cycle_time = conf_sram.aprs.tx.cycle;
if(conf_sram.aprs.tx.gps) if(conf_sram.aprs.tx.gps) {
(*attached)++; (*useGPS)++;
} else { // There must be an error }
TRACE_ERROR("COLL > Data collector started but no position thread is active"); } else { // There must be an error
} TRACE_ERROR("COLL > Data collector started but no position thread is active");
}
// Get GPS position // Gather telemetry and system status data
if(*attached) aquirePosition(tp, ltp, data_cycle_time - TIME_S2I(3)); measureVoltage(tp);
getSensors(tp);
getGPIO(tp);
setSystemStatus(tp);
tp->id = ++id; // Serial ID /*
* Enable GPS position acquisition if requested.
* a) If the RTC was not set then enable GPS temporarily to set it.
* b) If a thread is using GPS for position.
*/
unixTimestamp2Date(&time, ltp->gps_time);
if(*useGPS == 0 && time.year == RTC_BASE_YEAR) {
TRACE_INFO("COLL > Acquire time using GPS");
aquirePosition(tp, ltp, data_cycle_time - TIME_S2I(3));
/* GPS done. */
if(!(tp->gps_state == GPS_LOCKED1
|| tp->gps_state == GPS_LOCKED2)) {
/* Acquisition failed. Wait and then try again. */
TRACE_INFO("COLL > Time acquisition from GPS failed");
chThdSleep(TIME_S2I(60));
continue;
}
TRACE_INFO("COLL > Time acquired from GPS");
/* Switch GPS off. */
GPS_Deinit();
} else if(*useGPS > 0) {
aquirePosition(tp, ltp, data_cycle_time - TIME_S2I(3));
} else {
/*
* No threads using GPS.
* RTC valid so set tp & ltp from fixed location data.
*/
tp->gps_alt = conf_sram.aprs.tx.alt;
tp->gps_lat = conf_sram.aprs.tx.lat;
tp->gps_lon = conf_sram.aprs.tx.lon;
tp->gps_state = GPS_FIXED;
// Measure telemetry ltp->gps_time = tp->gps_time;
measureVoltage(tp); ltp->gps_alt = tp->gps_alt;
getSensors(tp); ltp->gps_lat = tp->gps_lat;
getGPIO(tp); ltp->gps_lon = tp->gps_lon;
setSystemStatus(tp); ltp->gps_state = GPS_FIXED;
}
// Trace data tp->id = ++id; // Serial ID
unixTimestamp2Date(&time, tp->gps_time);
TRACE_INFO( "COLL > New data point available (ID=%d)\r\n" // Trace data
"%s Time %04d-%02d-%02d %02d:%02d:%02d\r\n" unixTimestamp2Date(&time, tp->gps_time);
"%s Pos %d.%05d %d.%05d Alt %dm\r\n" TRACE_INFO( "COLL > New data point available (ID=%d)\r\n"
"%s Sats %d TTFF %dsec\r\n" "%s Time %04d-%02d-%02d %02d:%02d:%02d\r\n"
"%s ADC Vbat=%d.%03dV Vsol=%d.%03dV Pbat=%dmW\r\n" "%s Pos %d.%05d %d.%05d Alt %dm\r\n"
"%s AIR p=%d.%01dPa T=%d.%02ddegC phi=%d.%01d%%\r\n" "%s Sats %d TTFF %dsec\r\n"
"%s ADC Vbat=%d.%03dV Vsol=%d.%03dV Pbat=%dmW\r\n"
"%s AIR p=%d.%01dPa T=%d.%02ddegC phi=%d.%01d%%\r\n"
#if ENABLE_EXTERNAL_I2C == TRUE #if ENABLE_EXTERNAL_I2C == TRUE
"%s IO IO1=%d", "%s IOP IO1=%d",
#else #else
"%s IO IO1=%d IO2=%d IO3=%d", "%s IOP IO1=%d IO2=%d IO3=%d",
#endif #endif
tp->id, tp->id,
TRACE_TAB, time.year, time.month, time.day, time.hour, time.minute, time.day, TRACE_TAB, time.year, time.month, time.day, time.hour, time.minute, time.day,
TRACE_TAB, tp->gps_lat/10000000, (tp->gps_lat > 0 ? 1:-1)*(tp->gps_lat/100)%100000, tp->gps_lon/10000000, (tp->gps_lon > 0 ? 1:-1)*(tp->gps_lon/100)%100000, tp->gps_alt, TRACE_TAB, tp->gps_lat/10000000, (tp->gps_lat > 0 ? 1:-1)*(tp->gps_lat/100)%100000, tp->gps_lon/10000000, (tp->gps_lon > 0 ? 1:-1)*(tp->gps_lon/100)%100000, tp->gps_alt,
TRACE_TAB, tp->gps_sats, tp->gps_ttff, TRACE_TAB, tp->gps_sats, tp->gps_ttff,
TRACE_TAB, tp->adc_vbat/1000, (tp->adc_vbat%1000), tp->adc_vsol/1000, (tp->adc_vsol%1000), tp->pac_pbat, TRACE_TAB, tp->adc_vbat/1000, (tp->adc_vbat%1000), tp->adc_vsol/1000, (tp->adc_vsol%1000), tp->pac_pbat,
TRACE_TAB, tp->sen_i1_press/10, tp->sen_i1_press%10, tp->sen_i1_temp/100, tp->sen_i1_temp%100, tp->sen_i1_hum/10, tp->sen_i1_hum%10, TRACE_TAB, tp->sen_i1_press/10, tp->sen_i1_press%10, tp->sen_i1_temp/100, tp->sen_i1_temp%100, tp->sen_i1_hum/10, tp->sen_i1_hum%10,
#if ENABLE_EXTERNAL_I2C == TRUE #if ENABLE_EXTERNAL_I2C == TRUE
TRACE_TAB, tp->gpio & 1 TRACE_TAB, tp->gpio & 1
#else #else
TRACE_TAB, tp->gpio & 1, (tp->gpio >> 1) & 1, (tp->gpio >> 2) & 1 TRACE_TAB, tp->gpio & 1, (tp->gpio >> 1) & 1, (tp->gpio >> 2) & 1
#endif #endif
); );
// Write data point to Flash memory // Write data point to Flash memory
flash_writeLogDataPoint(tp); flash_writeLogDataPoint(tp);
// Switch last data point // Switch last data point
lastDataPoint = tp; lastDataPoint = tp;
// Wait until cycle // Wait until cycle
cycle_time = chThdSleepUntilWindowed(cycle_time, cycle_time + data_cycle_time); cycle_time = chThdSleepUntilWindowed(cycle_time, cycle_time + data_cycle_time);
} }
} }
/* /*
@ -399,7 +451,7 @@ void init_data_collector() {
thread_t *th = chThdCreateFromHeap(NULL, thread_t *th = chThdCreateFromHeap(NULL,
THD_WORKING_AREA_SIZE(10*1024), THD_WORKING_AREA_SIZE(10*1024),
"TRA", LOWPRIO, "TRA", LOWPRIO,
collectorThread, &attached); collectorThread, &useGPS);
if(!th) { if(!th) {
// Print startup error, do not start watchdog for this thread // Print startup error, do not start watchdog for this thread
TRACE_ERROR("COLL > Could not start" TRACE_ERROR("COLL > Could not start"

Wyświetl plik

@ -11,8 +11,8 @@ typedef enum {
GPS_LOSS, // The GPS was switched on all time but it couln't acquire a fix GPS_LOSS, // The GPS was switched on all time but it couln't acquire a fix
GPS_LOWBATT1, // The GPS wasn't switched on because the battery has not enough energy GPS_LOWBATT1, // The GPS wasn't switched on because the battery has not enough energy
GPS_LOWBATT2, // The GPS was switched on but has been switched off prematurely while the battery has not enough energy (or is too cold) GPS_LOWBATT2, // The GPS was switched on but has been switched off prematurely while the battery has not enough energy (or is too cold)
GPS_LOG, // The tracker has been just switched on and the position has been taken from the log GPS_LOG, // The tracker has just been switched on and the position has been taken from the log
GPS_OFF, // There is no active position thread so the GPS was never switched on (in oder to save power) GPS_OFF, // There was no prior acquisition by GPS
GPS_ERROR, // The GPS has a communication error GPS_ERROR, // The GPS has a communication error
GPS_FIXED // Fixed location data used from APRS location GPS_FIXED // Fixed location data used from APRS location
} gpsState_t; } gpsState_t;
@ -32,19 +32,20 @@ typedef struct {
gpsState_t gps_state; // GPS state gpsState_t gps_state; // GPS state
uint8_t gps_sats; // Satellites used for solution uint8_t gps_sats; // Satellites used for solution
uint8_t gps_ttff; // Time to first fix in seconds uint8_t gps_ttff; // Time to first fix in seconds
uint8_t gps_pdop; // Position DOP in 0.05 per unit (unitless) uint8_t gps_pdop; // Position DOP in 0.05 per arbitrary unit
uint16_t gps_alt; // Altitude in meter uint16_t gps_alt; // Altitude in meter
int32_t gps_lat; // Latitude in 10^(-7)° per unit int32_t gps_lat; // Latitude in 10^(-7)° per unit
int32_t gps_lon; // Longitude in 10^(-7)° per unit int32_t gps_lon; // Longitude in 10^(-7)° per unit
// BME280 (on board) // BME280 (on board)
uint32_t sen_i1_press; // Airpressure in Pa*10 (in 0.1Pa) uint32_t sen_i1_press; // Airpressure in Pa*10 (in 0.1Pa)
uint32_t sen_e1_press; // Airpressure in Pa*10 (in 0.1Pa) uint32_t sen_e1_press; // Airpressure in Pa*10 (in 0.1Pa)
uint32_t sen_e2_press; // Airpressure in Pa*10 (in 0.1Pa) uint32_t sen_e2_press; // Airpressure in Pa*10 (in 0.1Pa)
int16_t sen_i1_temp; // Temperature in 0.01°C per unit // BME280 (off board)
int16_t sen_e1_temp; // Temperature in 0.01°C per unit int16_t sen_i1_temp; // Temperature in 0.01°C per unit
int16_t sen_e2_temp; // Temperature in 0.01°C per unit int16_t sen_e1_temp; // Temperature in 0.01°C per unit
int16_t sen_e2_temp; // Temperature in 0.01°C per unit
uint8_t sen_i1_hum; // Rel. humidity in % uint8_t sen_i1_hum; // Rel. humidity in %
uint8_t sen_e1_hum; // Rel. humidity in % uint8_t sen_e1_hum; // Rel. humidity in %
@ -72,8 +73,8 @@ typedef struct {
* - 3:4 pac1720 status * - 3:4 pac1720 status
* - 5:7 OV5640 status * - 5:7 OV5640 status
* - 8:9 BMEi1 status (0 = OK, 1 = Fail, 2 = Not fitted) * - 8:9 BMEi1 status (0 = OK, 1 = Fail, 2 = Not fitted)
* - 9:10 BMEe1 status (0 = OK, 1 = Fail, 2 = Not fitted) * - 10:11 BMEe1 status (0 = OK, 1 = Fail, 2 = Not fitted)
* - 10:11 BMEe2 status (0 = OK, 1 = Fail, 2 = Not fitted) * - 12:13 BMEe2 status (0 = OK, 1 = Fail, 2 = Not fitted)
*/ */
} dataPoint_t; } dataPoint_t;
@ -82,5 +83,5 @@ dataPoint_t* getLastDataPoint(void);
void init_data_collector(void); void init_data_collector(void);
#endif #endif /* __COLLECTOR_H__ */

Wyświetl plik

@ -36,16 +36,6 @@ THD_FUNCTION(bcnThread, arg) {
TRACE_INFO("BCN > Do module BEACON cycle"); TRACE_INFO("BCN > Do module BEACON cycle");
dataPoint_t* dataPoint = getLastDataPoint(); dataPoint_t* dataPoint = getLastDataPoint();
if(dataPoint->gps_state != GPS_LOCKED1
|| dataPoint->gps_state != GPS_LOCKED2) {
TRACE_INFO("BCN > Set location from fixed location data");
dataPoint->gps_alt = conf->tx.alt;
dataPoint->gps_lat = conf->tx.lat;
dataPoint->gps_lon = conf->tx.lon;
dataPoint->gps_state = GPS_FIXED;
} else {
TRACE_INFO("BCN > Set location from GPS derived data");
}
if(!p_sleep(&conf->thread_conf.sleep_conf)) { if(!p_sleep(&conf->thread_conf.sleep_conf)) {
// Telemetry encoding parameter transmission // Telemetry encoding parameter transmission
@ -63,7 +53,7 @@ THD_FUNCTION(bcnThread, arg) {
type); type);
if(packet == NULL) { if(packet == NULL) {
TRACE_WARN("BCN > No free packet objects for" TRACE_WARN("BCN > No free packet objects for"
" telemetry config transmission"); " telemetry config transmission");
} else { } else {
if(!transmitOnRadio(packet, if(!transmitOnRadio(packet,
conf->tx.radio_conf.freq, conf->tx.radio_conf.freq,
@ -80,62 +70,73 @@ THD_FUNCTION(bcnThread, arg) {
last_conf_transmission += conf->tx.tel_enc_cycle; last_conf_transmission += conf->tx.tel_enc_cycle;
} }
TRACE_INFO("BCN > Transmit position beacon"); if(dataPoint->gps_state == GPS_FIXED
|| dataPoint->gps_state == GPS_LOCKED1
|| dataPoint->gps_state == GPS_LOCKED2) {
// Encode/Transmit position packet TRACE_INFO("BCN > Transmit position beacon");
packet_t packet = aprs_encode_position_and_telemetry(conf->tx.call, conf->tx.path,
conf->tx.symbol, dataPoint); // Encode/Transmit position packet
if(packet == NULL) { packet_t packet = aprs_encode_position_and_telemetry(conf->tx.call,
TRACE_WARN("BCN > No free packet objects" conf->tx.path,
" for position transmission"); conf->tx.symbol,
} else { dataPoint, true);
if(!transmitOnRadio(packet, if(packet == NULL) {
conf->tx.radio_conf.freq, TRACE_WARN("BCN > No free packet objects"
0, " for position transmission");
0, } else {
conf->tx.radio_conf.pwr, if(!transmitOnRadio(packet,
conf->tx.radio_conf.mod, conf->tx.radio_conf.freq,
conf->tx.radio_conf.cca)) { 0,
TRACE_ERROR("BCN > failed to transmit beacon data"); 0,
conf->tx.radio_conf.pwr,
conf->tx.radio_conf.mod,
conf->tx.radio_conf.cca)) {
TRACE_ERROR("BCN > failed to transmit beacon data");
}
chThdSleep(TIME_S2I(5));
} }
chThdSleep(TIME_S2I(5));
}
/* /*
* Encode/Transmit APRSD packet. * Encode/Transmit APRSD packet.
* This is a tracker originated message (not a reply to a request). * This is a tracker originated message (not a reply to a request).
* The message will be sent to the base station if set. * The message will be sent to the base station if set.
* Else send it to device identity. * Else send it to device identity.
*/ */
char *call = conf_sram.aprs.base.enabled char *call = conf_sram.aprs.base.enabled
? conf_sram.aprs.base.call : APRS_DEVICE_CALLSIGN; ? conf_sram.aprs.base.call : APRS_DEVICE_CALLSIGN;
/* /*
* Send message from this device. * Send message from this device.
* Use call sign and path as specified in base config. * Use call sign and path as specified in base config.
* There is no acknowledgment requested. * There is no acknowledgment requested.
*/ */
packet = aprs_compose_aprsd_message( packet = aprs_compose_aprsd_message(
conf->tx.call, conf->tx.call,
conf->base.path, conf->base.path,
call); call);
if(packet == NULL) { if(packet == NULL) {
TRACE_WARN("BCN > No free packet objects " TRACE_WARN("BCN > No free packet objects "
"or badly formed APRSD message"); "or badly formed APRSD message");
} else { } else {
if(!transmitOnRadio(packet, if(!transmitOnRadio(packet,
conf->tx.radio_conf.freq, conf->tx.radio_conf.freq,
0, 0,
0, 0,
conf->tx.radio_conf.pwr, conf->tx.radio_conf.pwr,
conf->tx.radio_conf.mod, conf->tx.radio_conf.mod,
conf->tx.radio_conf.cca conf->tx.radio_conf.cca
)) { )) {
TRACE_ERROR("BCN > Failed to transmit APRSD data"); TRACE_ERROR("BCN > Failed to transmit APRSD data");
}
chThdSleep(TIME_S2I(5));
} }
chThdSleep(TIME_S2I(5)); } else {
TRACE_INFO("BCN > No GPS data available for position beacon");
chThdSleep(TIME_S2I(60));
continue;
} }
} } /* psleep */
time = waitForTrigger(time, conf->tx.cycle); time = waitForTrigger(time, conf->tx.cycle);
} }
} }

Wyświetl plik

@ -77,7 +77,9 @@ THD_FUNCTION(posThread, arg)
// Encode/Transmit position packet // Encode/Transmit position packet
packet_t packet = aprs_encode_position_and_telemetry(conf->call, packet_t packet = aprs_encode_position_and_telemetry(conf->call,
conf->path, conf->path,
conf->symbol, dataPoint); conf->symbol,
dataPoint,
true);
if(packet == NULL) { if(packet == NULL) {
TRACE_WARN("POS > No free packet objects" TRACE_WARN("POS > No free packet objects"
" for position transmission"); " for position transmission");

Wyświetl plik

@ -115,7 +115,7 @@ typedef struct {
typedef struct { typedef struct {
radio_rx_conf_t radio_conf; radio_rx_conf_t radio_conf;
aprs_sym_t symbol;
// Protocol // Protocol
char call[AX25_MAX_ADDR_LEN]; char call[AX25_MAX_ADDR_LEN];
} thd_rx_conf_t; } thd_rx_conf_t;
@ -165,6 +165,7 @@ typedef struct {
volt_level_t gps_off_vbat; // Battery voltage threshold at which GPS is switched off volt_level_t gps_off_vbat; // Battery voltage threshold at which GPS is switched off
volt_level_t gps_onper_vbat; // Battery voltage threshold at which GPS is kept switched on all time. This value must be larger volt_level_t gps_onper_vbat; // Battery voltage threshold at which GPS is kept switched on all time. This value must be larger
// When gps_on_vbat and gps_off_vbat otherwise this value has no effect. Value 0 disables this feature // When gps_on_vbat and gps_off_vbat otherwise this value has no effect. Value 0 disables this feature
uint32_t gps_airborne; // Air pressure below which GPS is switched to airborne mode
uint32_t magic; // Key that indicates if the flash is loaded or has been updated uint32_t magic; // Key that indicates if the flash is loaded or has been updated
uint16_t crc; // CRC to verify content uint16_t crc; // CRC to verify content
} conf_t; } conf_t;