Skip to content

Commit

Permalink
Added support to sync time from optional GPS module
Browse files Browse the repository at this point in the history
  • Loading branch information
alexreinert committed Jun 23, 2020
1 parent 729c274 commit 4c082da
Show file tree
Hide file tree
Showing 12 changed files with 328 additions and 43 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,5 @@ Roadmap (ungeordnet und ohne Gewähr für Umsetzung)
* LED Fading
* SNMP
* CheckMK
* GPS Modul Unterstützung
* LGW Mode
* AskSin Analyzer Light
45 changes: 45 additions & 0 deletions include/gps.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* gps.h is part of the HB-RF-ETH firmware - https://github.com/alexreinert/HB-RF-ETH
*
* Copyright 2020 Alexander Reinert
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"
#include "systemclock.h"
#include "settings.h"
#include "linereader.h"

class GPS
{
private:
Settings *_settings;
SystemClock *_clk;
TaskHandle_t _tHandle = NULL;
QueueHandle_t _uart_queue;
LineReader *_lineReader;
uint64_t _nextSync = 0;

public:
GPS(Settings *settings, SystemClock *clk);

void start(void);
void stop(void);

void _gpsSerialQueueHandler();
void _handleLine(unsigned char *buffer, uint16_t len);
};
12 changes: 7 additions & 5 deletions include/linereader.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@
#pragma once

#include <stdint.h>
#include <functional>

class LineReader
{
private:
char _buffer[100];
void (*_processor)(char *buffer, uint8_t len);
unsigned char _buffer[1024];
std::function<void(unsigned char *buffer, uint16_t len)> _processor;
uint16_t _buffer_pos;

public:
LineReader(void (*processor)(char *buffer, uint8_t len));
LineReader(std::function<void(unsigned char *buffer, uint16_t len)> processor);

void AppendChar(char chr);
void Reset();
void Append(unsigned char chr);
void Append(unsigned char *buffer, uint16_t len);
void Flush();
};
19 changes: 16 additions & 3 deletions include/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
#include <stdio.h>
#include <lwip/ip4_addr.h>

typedef enum
{
TIMESOURCE_NTP = 0,
TIMESOURCE_DCF = 1,
TIMESOURCE_GPS = 2
} timesource_t;

class Settings
{
private:
Expand All @@ -34,9 +41,12 @@ class Settings
ip4_addr_t _dns1;
ip4_addr_t _dns2;

bool _enableDcf;
int _timesource;

int _dcfOffset;

int _gpsBaudrate;

char _ntpServer[64] = {0};

public:
Expand All @@ -58,12 +68,15 @@ class Settings

void setNetworkSettings(char *hostname, bool useDHCP, ip4_addr_t localIP, ip4_addr_t netmask, ip4_addr_t gateway, ip4_addr_t dns1, ip4_addr_t dns2);

bool getEnableDcf();
void setEnableDcf(bool enableDcf);
timesource_t getTimesource();
void setTimesource(timesource_t timesource);

int getDcfOffset();
void setDcfOffset(int offset);

int getGpsBaudrate();
void setGpsBaudrate(int baudrate);

char *getNtpServer();
void setNtpServer(char *ntpServer);
};
164 changes: 164 additions & 0 deletions src/gps.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
* gps.cpp is part of the HB-RF-ETH firmware - https://github.com/alexreinert/HB-RF-ETH
*
* Copyright 2020 Alexander Reinert
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "GPS.h"
#include "pins.h"
#include "esp_log.h"
#include "string.h"

void gpsSerialQueueHandlerTask(void *parameter)
{
((GPS *)parameter)->_gpsSerialQueueHandler();
}

GPS::GPS(Settings *settings, SystemClock *clk) : _settings(settings), _clk(clk)
{
uart_config_t uart_config = {
.baud_rate = _settings->getGpsBaudrate(),
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 0,
.use_ref_tick = false};
uart_param_config(UART_NUM_2, &uart_config);
uart_set_pin(UART_NUM_2, GPIO_NUM_0, DCF_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

using namespace std::placeholders;
_lineReader = new LineReader(std::bind(&GPS::_handleLine, this, _1, _2));
}

void GPS::start()
{
uart_driver_install(UART_NUM_2, UART_FIFO_LEN * 2, 0, 20, &_uart_queue, 0);
xTaskCreate(gpsSerialQueueHandlerTask, "GPS_UART_QueueHandler", 4096, this, 15, &_tHandle);
}

void GPS::stop()
{
uart_driver_delete(UART_NUM_2);
vTaskDelete(_tHandle);
}

void GPS::_gpsSerialQueueHandler()
{
uart_event_t event;
uint8_t *buffer = (uint8_t *)malloc(UART_FIFO_LEN);

uart_flush_input(UART_NUM_2);

for (;;)
{
if (xQueueReceive(_uart_queue, (void *)&event, (portTickType)portMAX_DELAY))
{
switch (event.type)
{
case UART_DATA:
uart_read_bytes(UART_NUM_2, buffer, event.size, portMAX_DELAY);
_lineReader->Append(buffer, event.size);
break;
case UART_FIFO_OVF:
case UART_BUFFER_FULL:
uart_flush_input(UART_NUM_2);
xQueueReset(_uart_queue);
_lineReader->Flush();
break;
case UART_BREAK:
case UART_PARITY_ERR:
case UART_FRAME_ERR:
_lineReader->Flush();
break;
default:
break;
}
}
}

free(buffer);
buffer = NULL;
vTaskDelete(NULL);
}

bool parseRMCTime(unsigned char *buffer, uint16_t len, timeval *tv)
{
int fieldIndex = 0;
int fieldStart = 0;

int fieldLength;

struct tm time = {};
time.tm_isdst = 0;

for (int i = 0; i < len; i++)
{
if (buffer[i] == ',')
{
fieldLength = i - fieldStart;

if (fieldIndex == 1)
{
if (fieldLength != 9)
return false;

time.tm_sec = ((buffer[fieldStart + 4] - '0') * 10) + (buffer[fieldStart + 5] - '0');
time.tm_min = ((buffer[fieldStart + 2] - '0') * 10) + (buffer[fieldStart + 3] - '0');
time.tm_hour = ((buffer[fieldStart + 0] - '0') * 10) + (buffer[fieldStart + 1] - '0');

tv->tv_usec = ((buffer[fieldStart + 4] - '7') * 100000) + ((buffer[fieldStart + 8] - '0') * 10000);
}
else if (fieldIndex == 9)
{
if (fieldLength != 6)
return false;

time.tm_year = ((buffer[fieldStart + 4] - '0') * 10) + (buffer[fieldStart + 5] - '0') + 100;
time.tm_mon = ((buffer[fieldStart + 2] - '0') * 10) + (buffer[fieldStart + 3] - '0') - 1;
time.tm_mday = ((buffer[fieldStart + 0] - '0') * 10) + (buffer[fieldStart + 1] - '0');
}

fieldIndex++;
fieldStart = i + 1;
}
}

if (fieldIndex != 12)
return false;

tv->tv_sec = mktime(&time);

return true;
}

void GPS::_handleLine(unsigned char *buffer, uint16_t len)
{
uint64_t startTime = esp_timer_get_time();
if ((len > 6) && (strncmp((char *)buffer, "$GPRMC", 6) == 0))
{
timeval tv;
if (parseRMCTime(buffer, len, &tv))
{
if (_nextSync < startTime)
{
_nextSync = startTime + 300 * 1000 * 1000; // every 5 minutes

tv.tv_usec += esp_timer_get_time() - startTime;
_clk->setTime(&tv);
}
}
}
}
15 changes: 12 additions & 3 deletions src/linereader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
#include "linereader.h"
#include <stdint.h>

LineReader::LineReader(void (*processor)(char *buffer, uint8_t len)) : _processor(processor), _buffer_pos(0)
LineReader::LineReader(std::function<void(unsigned char *buffer, uint16_t len)> processor) : _processor(processor), _buffer_pos(0)
{
}

void LineReader::AppendChar(char chr)
void LineReader::Append(unsigned char chr)
{
switch (chr)
{
Expand All @@ -42,7 +42,16 @@ void LineReader::AppendChar(char chr)
}
}

void LineReader::Reset()
void LineReader::Append(unsigned char *buffer, uint16_t len)
{
int i;
for (i = 0; i < len; i++)
{
Append(buffer[i]);
}
}

void LineReader::Flush()
{
_buffer_pos = 0;
}
17 changes: 12 additions & 5 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "systemclock.h"
#include "dcf.h"
#include "ntpclient.h"
#include "gps.h"
#include "ethernet.h"
#include "pushbuttonhandler.h"
#include "radiomoduleconnector.h"
Expand Down Expand Up @@ -92,13 +93,19 @@ void app_main()

DCF dcf(&settings, &clk);
NtpClient ntpClient(&settings, &clk);
if (settings.getEnableDcf())
{
dcf.start();
}
else
GPS gps(&settings, &clk);

switch (settings.getTimesource())
{
case TIMESOURCE_NTP:
ntpClient.start();
break;
case TIMESOURCE_GPS:
gps.start();
break;
case TIMESOURCE_DCF:
dcf.start();
break;
}

MDns mdns;
Expand Down
Loading

0 comments on commit 4c082da

Please sign in to comment.