Implemented UART/I2C switch for GPS

Implemented LOWBATT1 and LOWBATT2
Switch off camera at JPEG validation process
Moved JPEG validation section
Added GPS communication error message
Changed Watchdog behavior (1sec delay inserted)
Tidy up
master
Sven Steudte 2017-10-16 23:14:46 +02:00
rodzic f6d69c9afe
commit 8a0b8b8252
14 zmienionych plików z 347 dodań i 299 usunięć

Wyświetl plik

@ -9,7 +9,6 @@
#include "pi2c.h"
#include "board.h"
#include "debug.h"
#include "ssdv.h"
#include "padc.h"
#include <string.h>
@ -713,7 +712,7 @@ void set48MHz(void)
/**
* Reduce AHB clock back to the old speed which has been saved by set48MHz()
*/
void set6MHz(void)
void setSlowFreq(void)
{
uint32_t new = (RCC->CFGR & ~RCC_CFGR_HPRE_Msk) | oldSpeed;
RCC->CFGR = new;
@ -724,59 +723,6 @@ void set6MHz(void)
while(FLASH->ACR != new);
}
/**
* Analyzes the image for JPEG errors. Returns true if the image is error free.
*/
static bool analyze_image(uint8_t *image, uint32_t image_len)
{
#if !OV5640_USE_DMA_DBM
if(image_len >= 65535)
{
TRACE_ERROR("CAM > Camera has %d bytes allocated but DMA DBM not activated", image_len);
TRACE_ERROR("CAM > DMA can only use 65535 bytes only");
image_len = 65535;
}
#endif
ssdv_t ssdv;
uint8_t pkt[SSDV_PKT_SIZE];
uint8_t *b;
uint32_t bi = 0;
uint16_t i = 0;
uint8_t c = SSDV_OK;
ssdv_enc_init(&ssdv, SSDV_TYPE_NORMAL, "", 0, 7);
ssdv_enc_set_buffer(&ssdv, pkt);
while(true) // FIXME: I get caught in these loops occasionally and never return
{
while((c = ssdv_enc_get_packet(&ssdv)) == SSDV_FEED_ME)
{
b = &image[bi];
uint8_t r = bi < image_len-128 ? 128 : image_len - bi;
bi += r;
if(r <= 0)
{
TRACE_ERROR("CAM > Error in image (Premature end of file %d)", i);
return false;
}
ssdv_enc_feed(&ssdv, b, r);
}
if(c == SSDV_EOI) // End of image
return true;
if(c != SSDV_OK) // Error in JPEG image
{
TRACE_ERROR("CAM > Error in image (ssdv_enc_get_packet failed: %d %d)", c, i);
return false;
}
i++;
chThdSleepMilliseconds(5);
}
}
/**
* Captures an image from the camera.
* @buffer Buffer in which the image can be sampled
@ -787,16 +733,14 @@ static bool analyze_image(uint8_t *image, uint32_t image_len)
* that could lead to different resolutions on different method calls.
* The method returns the size of the image.
*/
uint32_t OV5640_Snapshot2RAM(uint8_t* buffer, uint32_t size, resolution_t res, bool enableJpegValidation)
uint32_t OV5640_Snapshot2RAM(uint8_t* buffer, uint32_t size, resolution_t res)
{
uint8_t cntr = 10;
uint8_t cntr = 5;
bool status;
bool jpegValid;
uint32_t size_sampled;
// Set resoultion
if(res == RES_MAX)
{
if(res == RES_MAX) {
OV5640_SetResolution(RES_UXGA); // FIXME: We actually have to choose the resolution which fits in the memory
} else {
OV5640_SetResolution(res);
@ -818,18 +762,7 @@ uint32_t OV5640_Snapshot2RAM(uint8_t* buffer, uint32_t size, resolution_t res, b
size_sampled--;
TRACE_INFO("CAM > Image size: %d bytes", size_sampled);
// Validate JPEG image
if(enableJpegValidation)
{
TRACE_INFO("CAM > Validate integrity of JPEG");
jpegValid = analyze_image(buffer, size);
TRACE_INFO("CAM > JPEG image %s", jpegValid ? "valid" : "invalid");
} else {
jpegValid = true;
}
} while((!jpegValid || !status) && cntr--);
} while(!status && cntr--);
return size_sampled;
}
@ -1003,7 +936,7 @@ CH_IRQ_HANDLER(Vector5C) {
vsync = true;
} else {
// Reduce AHB clock to 6 MHz
set6MHz();
setSlowFreq();
/* VSYNC leading with vsync true.
* This means end of capture for the frame.

Wyświetl plik

@ -13,7 +13,7 @@
#define OV5640_USE_DMA_DBM TRUE
uint32_t OV5640_Snapshot2RAM(uint8_t* buffer, uint32_t size, resolution_t resolution, bool enableJpegValidation);
uint32_t OV5640_Snapshot2RAM(uint8_t* buffer, uint32_t size, resolution_t resolution);
bool OV5640_Capture(uint8_t* buffer, uint32_t size);
void OV5640_InitGPIO(void);
void OV5640_TransmitConfig(void);

Wyświetl plik

@ -359,7 +359,3 @@ int8_t Si4464_getTemperature(void) {
return (899*adc)/4096 - 293;
}
bool isRadioInitialized(void) {
return initialized;
}

Wyświetl plik

@ -40,7 +40,6 @@ void Si4464_writeFIFO(uint8_t *msg, uint8_t size);
uint8_t Si4464_freeFIFO(void);
uint8_t Si4464_getState(void);
int8_t Si4464_getTemperature(void);
bool isRadioInitialized(void);
#endif

Wyświetl plik

@ -10,6 +10,7 @@
#include "debug.h"
#include "config.h"
#if defined(UBLOX_USE_UART)
// Serial driver configuration for GPS
const SerialConfig gps_config =
{
@ -18,39 +19,48 @@ const SerialConfig gps_config =
0, // CR2 register
0 // CR3 register
};
#endif
/*
* gps_transmit_string
*
* transmits a command to the GPS
*/
/**
* Transmits a string of bytes to the GPS
*/
void gps_transmit_string(uint8_t *cmd, uint8_t length)
{
#if defined(UBLOX_USE_I2C)
I2C_writeN(UBLOX_MAX_ADDRESS, cmd, length);
#elif defined(UBLOX_USE_UART)
sdWrite(&SD5, cmd, length);
#endif
}
/**
* Receives a single byte from the GPS. Returns 0x00 is there is no byte available
*/
uint8_t gps_receive_byte(void)
{
uint8_t val;
I2C_read8(UBLOX_MAX_ADDRESS, 0xFF, &val);
uint8_t val = 0x00;
#if defined(UBLOX_USE_I2C)
uint16_t len;
I2C_read16(UBLOX_MAX_ADDRESS, 0xFD, &len);
if(len) {
I2C_read8(UBLOX_MAX_ADDRESS, 0xFF, &val);
#elif defined(UBLOX_USE_UART)
val = sdGetTimeout(&SD5, TIME_IMMEDIATE);
if(val == 0xFF) val = 0x00;
#endif
return val;
}
uint16_t gps_bytes_avail(void)
{
uint16_t val;
I2C_read16(UBLOX_MAX_ADDRESS, 0xFD, &val);
return val;
}
/*
* gps_receive_ack
*
* waits for transmission of an ACK/NAK message from the GPS.
*
* returns 1 if ACK was received, 0 if NAK was received
*
*/
/**
* gps_receive_ack
*
* waits for transmission of an ACK/NAK message from the GPS.
*
* returns 1 if ACK was received, 0 if NAK was received
*
*/
uint8_t gps_receive_ack(uint8_t class_id, uint8_t msg_id, uint16_t timeout) {
int match_count = 0;
int msg_ack = 0;
@ -67,9 +77,8 @@ uint8_t gps_receive_ack(uint8_t class_id, uint8_t msg_id, uint16_t timeout) {
while(sTimeout >= chVTGetSystemTimeX()) {
// Receive one byte
if(gps_bytes_avail()) {
rx_byte = gps_receive_byte();
} else {
rx_byte = gps_receive_byte();
if(!rx_byte) {
chThdSleepMilliseconds(10);
continue;
}
@ -96,15 +105,15 @@ uint8_t gps_receive_ack(uint8_t class_id, uint8_t msg_id, uint16_t timeout) {
return false;
}
/*
* gps_receive_payload
*
* retrieves the payload of a packet with a given class and message-id with the retrieved length.
* the caller has to ensure suitable buffer length!
*
* returns the length of the payload
*
*/
/**
* gps_receive_payload
*
* retrieves the payload of a packet with a given class and message-id with the retrieved length.
* the caller has to ensure suitable buffer length!
*
* returns the length of the payload
*
*/
uint16_t gps_receive_payload(uint8_t class_id, uint8_t msg_id, unsigned char *payload, uint16_t timeout) {
uint8_t rx_byte;
enum {UBX_A, UBX_B, CLASSID, MSGID, LEN_A, LEN_B, PAYLOAD} state = UBX_A;
@ -115,9 +124,8 @@ uint16_t gps_receive_payload(uint8_t class_id, uint8_t msg_id, unsigned char *pa
while(sTimeout >= chVTGetSystemTimeX()) {
// Receive one byte
if(gps_bytes_avail()) {
rx_byte = gps_receive_byte();
} else {
rx_byte = gps_receive_byte();
if(!rx_byte) {
chThdSleepMilliseconds(10);
continue;
}
@ -162,20 +170,20 @@ uint16_t gps_receive_payload(uint8_t class_id, uint8_t msg_id, unsigned char *pa
return 0;
}
/*
* gps_get_fix
*
* retrieves a GPS fix from the module. if validity flag is not set, date/time and position/altitude are
* assumed not to be reliable!
*
* This method divides MAX7/8 and MAX6 modules since the protocol changed at MAX7 series. MAX6 requires
* NAV-POSLLH NAV-TIMEUTC and NAV-SOL to get all information about the GPS. With implementation of the
* NAV-PVT message at the MAX7 series, all information can be aquired by only one message. Although
* MAX7 is backward compatible, MAX7/8 will use NAV-PVT rather than the old protocol.
*
* argument is call by reference to avoid large stack allocations
*
*/
/**
* gps_get_fix
*
* retrieves a GPS fix from the module. if validity flag is not set, date/time and position/altitude are
* assumed not to be reliable!
*
* This method divides MAX7/8 and MAX6 modules since the protocol changed at MAX7 series. MAX6 requires
* NAV-POSLLH NAV-TIMEUTC and NAV-SOL to get all information about the GPS. With implementation of the
* NAV-PVT message at the MAX7 series, all information can be aquired by only one message. Although
* MAX7 is backward compatible, MAX7/8 will use NAV-PVT rather than the old protocol.
*
* argument is call by reference to avoid large stack allocations
*
*/
bool gps_get_fix(gpsFix_t *fix) {
static uint8_t response[92];
@ -184,7 +192,7 @@ bool gps_get_fix(gpsFix_t *fix) {
gps_transmit_string(pvt, sizeof(pvt));
if(!gps_receive_payload(0x01, 0x07, response, 5000)) { // Receive request
TRACE_INFO("GPS > PVT Polling FAILED");
TRACE_ERROR("GPS > PVT Polling FAILED");
return false;
}
@ -224,16 +232,16 @@ bool gps_get_fix(gpsFix_t *fix) {
return true;
}
/*
* gps_disable_nmea_output
*
* disables all NMEA messages to be output from the GPS.
* even though the parser can cope with NMEA messages and ignores them, it
* may save power to disable them completely.
*
* returns if ACKed by GPS
*
*/
/**
* gps_disable_nmea_output
*
* disables all NMEA messages to be output from the GPS.
* even though the parser can cope with NMEA messages and ignores them, it
* may save power to disable them completely.
*
* returns if ACKed by GPS
*
*/
uint8_t gps_disable_nmea_output(void) {
uint8_t nonmea[] = {
0xB5, 0x62, 0x06, 0x00, 20, 0x00, // UBX-CFG-PRT
@ -251,17 +259,17 @@ uint8_t gps_disable_nmea_output(void) {
return gps_receive_ack(0x06, 0x00, 1000);
}
/*
* gps_set_airborne_model
*
* tells the GPS to use the airborne positioning model. Should be used to
* get stable lock up to 50km altitude
*
* working uBlox MAX-M8Q
*
* returns if ACKed by GPS
*
*/
/**
* gps_set_airborne_model
*
* tells the GPS to use the airborne positioning model. Should be used to
* get stable lock up to 50km altitude
*
* working uBlox MAX-M8Q
*
* returns if ACKed by GPS
*
*/
uint8_t gps_set_airborne_model(void) {
uint8_t model6[] = {
0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, // UBX-CFG-NAV5
@ -290,14 +298,14 @@ uint8_t gps_set_airborne_model(void) {
return gps_receive_ack(0x06, 0x24, 1000);
}
/*
* gps_set_power_save
*
* enables cyclic tracking on the uBlox M8Q
*
* returns if ACKed by GPS
*
*/
/**
* gps_set_power_save
*
* enables cyclic tracking on the uBlox M8Q
*
* returns if ACKed by GPS
*
*/
uint8_t gps_set_power_save(void) {
uint8_t powersave[] = {
0xB5, 0x62, 0x06, 0x3B, 44, 0, // UBX-CFG-PM2
@ -320,11 +328,11 @@ uint8_t gps_set_power_save(void) {
return gps_receive_ack(0x06, 0x3B, 1000);
}
/*
* gps_power_save
*
* enables or disables the power save mode (which was configured before)
*/
/**
* gps_power_save
*
* enables or disables the power save mode (which was configured before)
*/
uint8_t gps_power_save(int on) {
uint8_t recvmgmt[] = {
0xB5, 0x62, 0x06, 0x11, 2, 0, // UBX-CFG-RXM
@ -346,12 +354,12 @@ bool GPS_Init(void) {
TRACE_INFO("GPS > Init pins");
palSetLineMode(LINE_GPS_RESET, PAL_MODE_OUTPUT_PUSHPULL); // GPS reset
palSetLineMode(LINE_GPS_EN, PAL_MODE_OUTPUT_PUSHPULL); // GPS off
palSetLineMode(LINE_GPS_RXD, PAL_MODE_ALTERNATE(8)); // UART RXD
palSetLineMode(LINE_GPS_TXD, PAL_MODE_ALTERNATE(8)); // UART TXD
palSetLineMode(LINE_GPS_RXD, PAL_MODE_ALTERNATE(11)); // UART RXD
palSetLineMode(LINE_GPS_TXD, PAL_MODE_ALTERNATE(11)); // UART TXD
// Init UART
//TRACE_INFO("GPS > Init GPS UART");
//sdStart(&SD6, &gps_config);
TRACE_INFO("GPS > Init GPS UART");
sdStart(&SD5, &gps_config);
// Switch MOSFET
TRACE_INFO("GPS > Switch on");
@ -359,39 +367,31 @@ bool GPS_Init(void) {
palSetLine(LINE_GPS_EN); // Switch on GPS
// Wait for GPS startup
chThdSleepMilliseconds(3000);
uint8_t status = 1;
chThdSleepMilliseconds(1000);
// Configure GPS
TRACE_INFO("GPS > Initialize GPS");
if(gps_disable_nmea_output()) {
TRACE_INFO("GPS > Disable NMEA output OK");
TRACE_INFO("GPS > Transmit config to GPS");
uint8_t cntr = 3;
bool status;
while((status = gps_disable_nmea_output()) == false && cntr--);
if(status) {
TRACE_INFO("GPS > ... Disable NMEA output OK");
} else {
TRACE_ERROR("GPS > Disable NMEA output FAILED");
status = 0;
TRACE_ERROR("GPS > Communication Eror");
return false;
}
if(gps_set_airborne_model()) {
TRACE_INFO("GPS > Set airborne model OK");
cntr = 5;
while((status = gps_set_airborne_model()) == false && cntr--);
if(status) {
TRACE_INFO("GPS > ... Set airborne model OK");
} else {
TRACE_ERROR("GPS > Set airborne model FAILED");
status = 0;
}
if(gps_set_power_save()) {
TRACE_INFO("GPS > Configure power save OK");
} else {
TRACE_ERROR("GPS > Configure power save FAILED");
status = 0;
}
if(gps_power_save(0)) {
TRACE_INFO("GPS > Disable power save OK");
} else {
TRACE_ERROR("GPS > Disable power save FAILED");
status = 0;
TRACE_ERROR("GPS > Communication Eror");
return false;
}
return status;
return true;
}
void GPS_Deinit(void)

Wyświetl plik

@ -11,6 +11,10 @@
#define UBLOX_MAX_ADDRESS 0x42
// You can either use I2C or UART
#define UBLOX_USE_UART
//#define UBLOX_USE_I2C
#define isGPSLocked(pos) ((pos)->type == 3 && (pos)->num_svs >= 5)
typedef struct {

Wyświetl plik

@ -34,6 +34,25 @@ int main(void) {
chThdSleepMilliseconds(100);
#endif
/*// Clear Wakeup flag
PWR->CR |= PWR_CR_CWUF;
// Select STANDBY mode
PWR->CR |= PWR_CR_PDDS;
// Set SLEEPDEEP bit of Cortex System Control Register
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
// This option is used to ensure that store operations are completed
#if defined ( __CC_ARM )
__force_stores();
#endif
// Request Wait For Interrupt
__WFI();
while(1);*/
// Init debugging (Serial debug port, LEDs)
DEBUG_INIT();
TRACE_INFO("MAIN > Startup");

Wyświetl plik

@ -195,6 +195,7 @@
#define STM32_SERIAL_USE_USART1 FALSE
#define STM32_SERIAL_USE_USART2 FALSE
#define STM32_SERIAL_USE_USART3 TRUE
#define STM32_SERIAL_USE_UART5 TRUE
#define STM32_SERIAL_USE_USART6 FALSE
#define STM32_SERIAL_USART1_PRIORITY 12
#define STM32_SERIAL_USART2_PRIORITY 12
@ -243,6 +244,7 @@
#define STM32_UART_USE_USART1 FALSE
#define STM32_UART_USE_USART2 FALSE
#define STM32_UART_USE_USART3 FALSE
#define STM32_UART_USE_UART5 TRUE
#define STM32_UART_USE_USART6 FALSE
#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5)
#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
@ -250,6 +252,8 @@
#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
#define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 1)
#define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
#define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
#define STM32_UART_USART1_IRQ_PRIORITY 12

Wyświetl plik

@ -24,7 +24,7 @@
#define METER_TO_FEET(m) (((m)*26876) / 8192)
static uint16_t loss_of_gps_counter = 0;
static uint16_t loss_of_gps_counter;
static uint16_t msg_id;
/**
@ -99,34 +99,44 @@ void aprs_encode_position(ax25_t* packet, const aprs_conf_t *config, trackPoint_
chsnprintf(temp, sizeof(temp), "%d", trackPoint->gps_sats);
ax25_send_string(packet, temp);
if(trackPoint->gps_lock == GPS_LOCKED) // GPS is locked
{
// TTFF (Time to first fix)
ax25_send_string(packet, " TTFF ");
chsnprintf(temp, sizeof(temp), "%d", trackPoint->gps_ttff);
ax25_send_string(packet, temp);
ax25_send_string(packet, "sec");
}
switch(trackPoint->gps_lock) {
case GPS_LOCKED: // GPS is locked
// TTFF (Time to first fix)
ax25_send_string(packet, " TTFF ");
chsnprintf(temp, sizeof(temp), "%d", trackPoint->gps_ttff);
ax25_send_string(packet, temp);
ax25_send_string(packet, "sec");
loss_of_gps_counter = 0;
break;
if(trackPoint->gps_lock == GPS_LOSS) { // No GPS lock
case GPS_LOSS: // No GPS lock
ax25_send_string(packet, " GPS LOSS ");
chsnprintf(temp, sizeof(temp), "%d", ++loss_of_gps_counter);
ax25_send_string(packet, temp);
break;
ax25_send_string(packet, " GPS LOSS ");
chsnprintf(temp, sizeof(temp), "%d", ++loss_of_gps_counter);
ax25_send_string(packet, temp);
case GPS_LOWBATT1: // GPS switched off prematurely
ax25_send_string(packet, " GPS LOWBATT1 ");
chsnprintf(temp, sizeof(temp), "%d", ++loss_of_gps_counter);
ax25_send_string(packet, temp);
break;
} else if(trackPoint->gps_lock == GPS_LOWBATT) { // GPS switched off prematurely
case GPS_LOWBATT2: // GPS switched off prematurely
ax25_send_string(packet, " GPS LOWBATT2 ");
chsnprintf(temp, sizeof(temp), "%d", ++loss_of_gps_counter);
ax25_send_string(packet, temp);
break;
ax25_send_string(packet, " GPS LOWBATT ");
chsnprintf(temp, sizeof(temp), "%d", ++loss_of_gps_counter);
ax25_send_string(packet, temp);
case GPS_ERROR: // GPS error
ax25_send_string(packet, " GPS ERROR ");
chsnprintf(temp, sizeof(temp), "%d", ++loss_of_gps_counter);
ax25_send_string(packet, temp);
break;
} else if(trackPoint->gps_lock == GPS_LOG) { // GPS position from log (because the tracker has been just switched on)
ax25_send_string(packet, " GPS FROM LOG");
loss_of_gps_counter = 0;
} else {
loss_of_gps_counter = 0;
case GPS_LOG: // GPS position from log (because the tracker has been just switched on)
ax25_send_string(packet, " GPS FROM LOG");
loss_of_gps_counter = 0;
break;
}
ax25_send_byte(packet, '|');

Wyświetl plik

@ -175,7 +175,6 @@ THD_FUNCTION(si_fifo_feeder_thd2, arg)
c += more;
chThdSleepMilliseconds(15);
}
// Shutdown radio (and wait for Si4464 to finish transmission)
shutdownRadio();
@ -325,6 +324,7 @@ void shutdownRadio(void)
while(Si4464_getState() == SI4464_STATE_TX)
chThdSleepMilliseconds(10);
TRACE_INFO("RAD > Shutdown radio");
Si4464_shutdown();
active_mod = MOD_NOT_SET;
}

Wyświetl plik

@ -273,8 +273,6 @@ const uint8_t noCameraFound[4071] = {
0xBD, 0xC0, 0x20, 0x00, 0x01, 0xFF, 0xD9
};
#include <string.h>
uint8_t gimage_id; // Global image ID (for all image threads)
mutex_t camera_mtx;
bool camera_mtx_init = false;
@ -404,6 +402,9 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf,
// Initialize new packet buffer
aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod);
if(!conf->packet_spacing)
chThdSleepMilliseconds(8000); // Leave a little break because it will overflow some devices
}
break;
@ -439,6 +440,59 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf,
}
}
/**
* Analyzes the image for JPEG errors. Returns true if the image is error free.
*/
static bool analyze_image(uint8_t *image, uint32_t image_len)
{
#if !OV5640_USE_DMA_DBM
if(image_len >= 65535)
{
TRACE_ERROR("CAM > Camera has %d bytes allocated but DMA DBM not activated", image_len);
TRACE_ERROR("CAM > DMA can only use 65535 bytes only");
image_len = 65535;
}
#endif
ssdv_t ssdv;
uint8_t pkt[SSDV_PKT_SIZE];
uint8_t *b;
uint32_t bi = 0;
uint16_t i = 0;
uint8_t c = SSDV_OK;
ssdv_enc_init(&ssdv, SSDV_TYPE_NORMAL, "", 0, 7);
ssdv_enc_set_buffer(&ssdv, pkt);
while(true) // FIXME: I get caught in these loops occasionally and never return
{
while((c = ssdv_enc_get_packet(&ssdv)) == SSDV_FEED_ME)
{
b = &image[bi];
uint8_t r = bi < image_len-128 ? 128 : image_len - bi;
bi += r;
if(r <= 0)
{
TRACE_ERROR("CAM > Error in image (Premature end of file %d)", i);
return false;
}
ssdv_enc_feed(&ssdv, b, r);
}
if(c == SSDV_EOI) // End of image
return true;
if(c != SSDV_OK) // Error in JPEG image
{
TRACE_ERROR("CAM > Error in image (ssdv_enc_get_packet failed: %d %d)", c, i);
return false;
}
i++;
chThdSleepMilliseconds(5);
}
}
static bool camInitialized = false;
bool takePicture(ssdv_conf_t *conf, bool enableJpegValidation)
@ -463,24 +517,38 @@ bool takePicture(ssdv_conf_t *conf, bool enableJpegValidation)
// Lock Radio (The radio uses the same DMA for SPI as the camera)
lockRadio(); // Lock radio
// Init camera
if(!camInitialized) {
OV5640_init();
camInitialized = true;
}
uint8_t cntr = 5;
bool jpegValid;
do {
// Init camera
if(!camInitialized) {
OV5640_init();
camInitialized = true;
}
// Sample data from pseudo DCMI through DMA into RAM
conf->size_sampled = OV5640_Snapshot2RAM(conf->ram_buffer, conf->ram_size, conf->res, enableJpegValidation);
// Sample data from pseudo DCMI through DMA into RAM
conf->size_sampled = OV5640_Snapshot2RAM(conf->ram_buffer, conf->ram_size, conf->res);
// Switch off camera
if(!keep_cam_switched_on) {
OV5640_deinit();
camInitialized = false;
}
// Validate JPEG image
if(enableJpegValidation)
{
TRACE_INFO("CAM > Validate integrity of JPEG");
jpegValid = analyze_image(conf->ram_buffer, conf->ram_size);
TRACE_INFO("CAM > JPEG image %s", jpegValid ? "valid" : "invalid");
} else {
jpegValid = true;
}
} while(!jpegValid && cntr--);
// Unlock radio
unlockRadio();
// Switch off camera
if(!keep_cam_switched_on) {
OV5640_deinit();
camInitialized = false;
}
} else { // Camera not found
camInitialized = false;

Wyświetl plik

@ -224,62 +224,76 @@ THD_FUNCTION(trackingThread, arg) {
// Switch on GPS is enough power is available and GPS is needed by any position thread
uint16_t batt = getBatteryVoltageMV();
if(batt >= gps_on_vbat && tracking_useGPS)
{
if(!tracking_useGPS) { // No position thread running
tp->gps_lock = GPS_OFF;
} else if(batt < gps_on_vbat) {
tp->gps_lock = GPS_LOWBATT1;
} else {
// Switch on GPS
GPS_Init();
bool status = GPS_Init();
// Search for lock as long enough power is available
do {
batt = getBatteryVoltageMV();
gps_get_fix(&gpsFix);
} while(!isGPSLocked(&gpsFix) && batt >= gps_off_vbat && chVTGetSystemTimeX() <= time + track_cycle_time - S2ST(3)); // Do as long no GPS lock and within timeout, timeout=cycle-1sec (-3sec in order to keep synchronization)
if(status) {
// Search for lock as long enough power is available
do {
batt = getBatteryVoltageMV();
gps_get_fix(&gpsFix);
} while(!isGPSLocked(&gpsFix) && batt >= gps_off_vbat && chVTGetSystemTimeX() <= time + track_cycle_time - S2ST(3)); // Do as long no GPS lock and within timeout, timeout=cycle-1sec (-3sec in order to keep synchronization)
if(batt < gps_off_vbat) { // GPS was switched on but prematurely switched off because the battery is low on power, switch off GPS
GPS_Deinit();
TRACE_WARN("TRAC > GPS sampling finished GPS LOW BATT");
tp->gps_lock = GPS_LOWBATT2;
} else if(!isGPSLocked(&gpsFix)) { // GPS was switched on but it failed to get a lock, keep GPS switched on
TRACE_WARN("TRAC > GPS sampling finished GPS LOSS");
tp->gps_lock = GPS_LOSS;
} 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)
if(track_cycle_time >= S2ST(60)) {
TRACE_INFO("TRAC > Switch off GPS");
GPS_Deinit();
} else {
TRACE_INFO("TRAC > Keep GPS switched of because cycle < 60sec");
}
// Debug
TRACE_INFO("TRAC > GPS sampling finished GPS LOCK");
// Calibrate RTC
setTime(gpsFix.time);
// Take time from GPS
tp->time.year = gpsFix.time.year;
tp->time.month = gpsFix.time.month;
tp->time.day = gpsFix.time.day;
tp->time.hour = gpsFix.time.hour;
tp->time.minute = gpsFix.time.minute;
tp->time.second = gpsFix.time.second;
// Set new GPS fix
tp->gps_lat = gpsFix.lat;
tp->gps_lon = gpsFix.lon;
tp->gps_alt = gpsFix.alt;
tp->gps_lock = GPS_LOCKED;
tp->gps_sats = gpsFix.num_svs;
}
} else { // GPS communication error
if(batt < gps_off_vbat) // Switch off GPS at low batt
GPS_Deinit();
tp->gps_lock = GPS_ERROR;
}
}
if(isGPSLocked(&gpsFix)) { // GPS locked
// Switch off GPS (if cycle time is more than 60 seconds)
if(track_cycle_time >= S2ST(60)) {
TRACE_INFO("TRAC > Switch off GPS");
GPS_Deinit();
} else {
TRACE_INFO("TRAC > Keep GPS switched of because cycle < 60sec");
}
// Debug
TRACE_INFO("TRAC > GPS sampling finished GPS LOCK");
// Calibrate RTC
setTime(gpsFix.time);
// Take time from GPS
tp->time.year = gpsFix.time.year;
tp->time.month = gpsFix.time.month;
tp->time.day = gpsFix.time.day;
tp->time.hour = gpsFix.time.hour;
tp->time.minute = gpsFix.time.minute;
tp->time.second = gpsFix.time.second;
// Set new GPS fix
tp->gps_lat = gpsFix.lat;
tp->gps_lon = gpsFix.lon;
tp->gps_alt = gpsFix.alt;
tp->gps_lock = GPS_LOCKED;
tp->gps_sats = gpsFix.num_svs;
} else { // GPS lost (keep GPS switched on)
// Debug
if(batt < gps_off_vbat) {
TRACE_WARN("TRAC > GPS sampling finished GPS LOW BATT");
} else {
TRACE_WARN("TRAC > GPS sampling finished GPS LOSS");
}
if(tp->gps_lock != GPS_LOCKED) { // We have no valid GPS fix
// Take time from internal RTC
getTime(&rtc);
tp->time.year = rtc.year;
@ -293,14 +307,6 @@ THD_FUNCTION(trackingThread, arg) {
tp->gps_lat = ltp->gps_lat;
tp->gps_lon = ltp->gps_lon;
tp->gps_alt = ltp->gps_alt;
// Mark GPS loss (or low batt, GPS switch off)
if(tracking_useGPS)
tp->gps_lock = batt < gps_off_vbat || batt < gps_on_vbat ? GPS_LOWBATT : GPS_LOSS;
else
tp->gps_lock = GPS_OFF;
tp->gps_sats = 0;
}
tp->id = id; // Serial ID

Wyświetl plik

@ -6,11 +6,13 @@
#include "ptime.h"
typedef enum {
GPS_LOCKED, // GPS is locked and could aquire a fix
GPS_LOSS, // GPS was switched on all time but it couln't aquire a fix
GPS_LOWBATT, // GPS was switched on but had to be switched off prematurely while the battery is almost empty (or is too cold)
GPS_LOCKED, // The GPS is locked and could aquire a fix
GPS_LOSS, // The GPS was switched on all time but it couln't aquire a fix
GPS_LOWBATT1, // The GPS wasnt 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_LOG, // The tracker has been just 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_ERROR // The GPS has a communication error
} gpsLock_t;
typedef struct {

Wyświetl plik

@ -16,12 +16,20 @@ void register_thread_at_wdg(module_conf_t *thread_config)
registered_threads[threads_cnt++] = thread_config;
}
static void flash_led(void) {
palClearLine(LINE_IO_LED2);
chThdSleepMilliseconds(50);
palSetLine(LINE_IO_LED2);
}
THD_FUNCTION(wdgThread, arg) {
(void)arg;
uint8_t counter = 0;
while(true)
{
chThdSleepMilliseconds(1000);
bool healthy = true;
for(uint8_t i=0; i<threads_cnt; i++) {
if(registered_threads[i]->wdg_timeout < chVTGetSystemTimeX())
@ -37,11 +45,8 @@ THD_FUNCTION(wdgThread, arg) {
// Switch LEDs
if(counter++ % (4*healthy) == 0)
{
palClearLine(LINE_IO_LED2);
chThdSleepMilliseconds(50);
palSetLine(LINE_IO_LED2);
flash_led();
}
chThdSleepMilliseconds(1000);
}
}
@ -52,6 +57,8 @@ void init_watchdog(void)
wdgStart(&WDGD1, &wdgcfg);
wdgReset(&WDGD1);
flash_led();
TRACE_INFO("WDG > Startup Watchdog thread");
thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(256), "WDG", NORMALPRIO, wdgThread, NULL);
if(!th) {