#include "main.h"
#include "libNMEA/nmea.h"
#include <cstring>
#include "libOLED/stm32_halDisplay.H"
#include "libOLED/fontclass.H"
#include "libOLED/displayDial.H"
#include "libLSM9DS1/LSM9DS1.h"
#include "libBMP280/bmp280.h"
#include "libSmallPrintf/small_printf.h"
#if defined USB_DEVICE
#include "usbd_cdc_if.h"
#endif
LSM9DS1Class IMU (&hi2c2);
namespace
{
int const WIDTH = 128;
int const HEIGHT = 64;
int const DISPLAY_RAMWIDTH = 132;
}
float speedMPH = 0.0;
float speedAvg = 0.0;
double speedAvgTime = 0; // sum of all deltaTime;
double speedAvgSum = 0.0; // sum of deltaTime * speed for each second
double lastLocTime = 0.0; // last time there was a location
uint32_t nextPosTime = 0;
// convert knots to MPH
double const KNOTS_TO_MPH = 1.128;
int heading = 0;
Location loc;
uint32_t lastTick = 0;
int32_t temp32 = 0;
uint32_t pres32 = 0;
int32_t rslt;
int32_t rslt2; // result from read of second sensor
// second sensor
int32_t temp32_out = 0;
uint8_t displayBuffer[dataSize (WIDTH, HEIGHT)];
stm32_halDisplay_t display1 (WIDTH, HEIGHT, DISPLAY_RAMWIDTH, displayBuffer,
&hspi1,
SPI_CD_GPIO_Port,
SPI_CD_Pin,
SPI_RESET_GPIO_Port,
SPI_RESET_Pin,
SPI_NSS1_GPIO_Port,
SPI_NSS1_Pin);
displayDial_t dial (display1, 96, 32, 32, 180);
// debouncer for the button
char buttonState;
char buttonCount;
char rmc_flag = 0;
extern "C" uint8_t
rmc_callback (uint8_t *data, uint16_t length)
{
rmc_flag = 1;
HAL_GPIO_TogglePin (Green_LED_GPIO_Port, Green_LED_Pin);
return CDC_Transmit_FS (data, length);
}
extern "C" void
cc_init ()
{
display1.reset ();
display1.init ();
display1.clearDisplay ();
dial.draw_scale (0, 360, 8, 1, 45);
display1.display ();
memset (loc.time, '-', 6);
// every time we receive GPRMC, forward the text line to the USB driver
setRmcCallback (&rmc_callback);
// initialise IMU operations
IMU.begin ();
}
char fontBuf[] = "01234567";
extern "C" void
cc_run (struct bmp280_dev *bmp, struct bmp280_dev *bmp2)
{
bool stat = updateLocation (&loc, &uc1);
// process button press : done by polling loop
uint8_t const buttonLimit = 3;
uint8_t newPush = HAL_GPIO_ReadPin ( encoder_push_GPIO_Port,
encoder_push_Pin);
if (newPush == buttonState)
buttonCount = 0;
else if (buttonCount < buttonLimit)
buttonCount++;
if (buttonCount == buttonLimit)
{
buttonState = newPush;
buttonCount = 0;
// if the button is held down , we set the average speed
if (buttonState == GPIO_PIN_RESET)
{
speedAvgSum = 0.0;
speedAvgTime = 0.0;
}
}
if (rmc_flag)
{
// get the time from the RTC
RTC_TimeTypeDef sTime;
rmc_flag = 0;
display1.clearDisplay ();
dial.draw_scale (0, 360, 8, 1, 45);
if (loc.good)
{
heading = loc.heading;
// add in time * speed to give "distance"
if (loc.valid == 'A')
{
sTime.Seconds = loc.tv.tm_sec;
sTime.Minutes = loc.tv.tm_min;
sTime.Hours = loc.tv.tm_hour;
HAL_RTC_SetTime (&hrtc, &sTime, RTC_FORMAT_BIN);
if (lastLocTime != 0)
{
double delta = difftime (loc.utc, lastLocTime);
// believe the speed .
if (delta > 0 && delta < 2)
{
speedAvgSum += loc.speed * delta;
speedAvgTime += delta;
lastLocTime = loc.utc;
}
else
lastLocTime = loc.utc;
}
else
{
lastLocTime = loc.utc;
}
}
}
else
{
HAL_RTC_GetTime (&hrtc, &sTime, RTC_FORMAT_BIN);
}
// slow down the output of ata
if (speedAvgTime > 0)
speedAvg = (speedAvgSum / speedAvgTime) * KNOTS_TO_MPH;
else
speedAvg = 0.0;
// update the display once per second
loc.time[0] = (sTime.Hours / 10) + '0';
loc.time[1] = (sTime.Hours % 10) + '0';
loc.time[2] = (sTime.Minutes / 10) + '0';
loc.time[3] = (sTime.Minutes % 10) + '0';
loc.time[4] = (sTime.Seconds / 10) + '0';
loc.time[5] = (sTime.Seconds % 10) + '0';
// print out the GMT time at the top of the screen
display1.gotoxy (0, 0);
display1.printString (small_font, &loc.time[0], 2, WHITE);
display1.printString (small_font, ":", 1, WHITE);
display1.printString (small_font, &loc.time[2], 2, WHITE);
display1.printString (small_font, ":", 1, WHITE);
display1.printString (small_font, &loc.time[4], 2, WHITE);
int dial_ang = heading + 180;
dial.draw_needle (dial_ang);
display1.gotoxy (70, 25);
if (loc.valid == 'A')
{
if (heading < 100)
display1.moveby (2, 0);
if (heading < 10)
display1.moveby (2, 0);
display1.fontDigits (large_font, 3, -1, heading);
}
else
display1.printString (large_font, "GPS?", 4, WHITE);
if (loc.valid == 'A')
speedMPH = loc.speed * KNOTS_TO_MPH;
else
speedMPH = 0.0;
display1.gotoxy (0, 8);
display1.fontDigits (large_font, 4, 1, speedMPH * 10);
display1.printString (small_font, "c", 2, WHITE);
display1.gotoxy (0, 24);
display1.fontDigits (large_font, 4, 1, speedAvg * 10);
display1.printString (small_font, "av", 2, WHITE);
float x, y, z;
if (IMU.magneticFieldAvailable ())
{
IMU.readMagneticField (x, y, z);
}
if (IMU.accelerationAvailable ())
{
IMU.readAcceleration (x, y, z);
}
struct bmp280_uncomp_data ucomp_data, ucomp_data2;
if (HAL_GetTick () - lastTick > 200)
{
lastTick = HAL_GetTick ();
/* Reading the raw data from sensor */
rslt = bmp280_get_uncomp_data (&ucomp_data, bmp);
/* reading the raw data from the second sensor */
rslt2 = bmp280_get_uncomp_data (&ucomp_data2, bmp2);
if (rslt2 == BMP280_OK)
{
rslt2 = bmp280_get_comp_temp_32bit (&temp32_out,
ucomp_data2.uncomp_temp,
bmp2);
}
// if it returns 128,0,0 for both temperature and pressure at the same time, then this ends up as the value 524288 which is broken ..
if (rslt2 != BMP280_OK
|| (ucomp_data2.uncomp_temp == 524288
&& ucomp_data2.uncomp_press == 524288))
{
/// try to reset the device, its playing up
resetBmp2 ();
}
if (rslt == BMP280_OK)
{
/* Getting the 32 bit compensated temperature */
rslt = bmp280_get_comp_temp_32bit (&temp32,
ucomp_data.uncomp_temp, bmp);
rslt = bmp280_get_comp_pres_32bit (&pres32,
ucomp_data.uncomp_press, bmp);
#if defined USB_DEVICE
/*
* $--XDR,a,x.x,a,c--c, ..... *hh<CR><LF> \\
Field Number:
1) Transducer Type
2) Measurement Data
3) Units of measurement
4) Name of transducer
x) More of the same
n) Checksum
Example:
$IIXDR,C,19.52,C,TempAir*19
$IIXDR,P,1.02481,B,Barometer*29
Currently, OpenCPN recognizes the following transducers:
Measured Value | Transducer Type | Measured Data | Unit of measure | Transducer Name
------------------------------------------------------------------------------------------------------
barometric | "P" pressure | 0.8..1.1 or 800..1100 | "B" bar | "Barometer"
air temperature| "C" temperature | 2 decimals | "C" celsius | "TempAir" or "ENV_OUTAIR_T"
pitch | "A" angle |-180..0 nose down 0..180 nose up | "D" degrees | "PTCH" or "PITCH"
rolling | "A" angle |-180..0 L 0..180 R | "D" degrees | "ROLL"
water temp | "C" temperature | 2 decimals | "C" celsius | "ENV_WATER_T"
*/
// compile a logger message over USB
char buffer[200];
int cnt = small_sprintf(buffer,"$MJXDR,C,%ld.%02ld,C,AirTemp,P,%01ld.%05ld,B,AirPres",temp32/100,temp32%100,pres32/100000,pres32%100000);
uint8_t sum=0;
for(int i=1; i<cnt; i++)
sum += buffer[i];
cnt+= small_sprintf(buffer+cnt,"*%02X\n",sum);
CDC_Transmit_FS(reinterpret_cast<uint8_t*>(&buffer[0]),cnt);
#endif
}
}
display1.gotoxy (0, 40);
display1.fontDigits (large_font, 4, 1, temp32_out / 10, WHITE);
display1.printString (small_font, "°", 1, WHITE);
display1.gotoxy (0, 56);
display1.fontDigits (small_font, 3, 1, temp32 / 10, WHITE);
display1.printString (small_font, "° ", 2, WHITE);
display1.fontDigits (small_font, 4, -1, pres32 / 100, WHITE);
display1.printString (small_font, "mb", 2, WHITE);
display1.display ();
}
HAL_Delay (10);
}