Compare commits
20 Commits
DropPeaks
...
SecondValu
Author | SHA1 | Date | |
---|---|---|---|
59e3350aaf | |||
6c21983917 | |||
80103312ce | |||
9213cfac11 | |||
07c80eb21c | |||
eb83c754bf | |||
4f81343a89 | |||
e8102e74a9 | |||
784346b833 | |||
e3ee3a08e8 | |||
5ef114b634 | |||
2dd586d7e4 | |||
5d1f7dde89 | |||
8d56c5aff4 | |||
5230139544 | |||
08c76f13de | |||
6a13da024d
|
|||
8c0c864905 | |||
61b1498d7b | |||
e21e114313 |
42
src/Makefile
42
src/Makefile
@ -3,15 +3,49 @@ CC=gcc
|
|||||||
CFLAGS=-Wall
|
CFLAGS=-Wall
|
||||||
LDFLAGS=-lwiringPi -lcurl -lconfig
|
LDFLAGS=-lwiringPi -lcurl -lconfig
|
||||||
|
|
||||||
counter: counter.o LS7366R.o influx.o ringbuffer.o led.o
|
INST_DIR=/opt/sbin
|
||||||
$(CC) -o $@ $(LDFLAGS) $^
|
|
||||||
|
|
||||||
.c.o:
|
REFCNT:=$(shell git rev-list --all --count)
|
||||||
$(CC) $(CFLAGS) -c $<
|
VERSION:=$(shell cat VERSION)
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: counter
|
all: counter
|
||||||
|
|
||||||
|
counter: counter.o LS7366R.o influx.o ringbuffer.o led.o logging.o version.o
|
||||||
|
$(CC) -o $@ $(LDFLAGS) $^
|
||||||
|
|
||||||
|
version.o: version.c VERSION
|
||||||
|
$(CC) -DD_REFCNT=$(REFCNT) -DD_VERSION=\"$(VERSION)\" -c $<
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
-rm -f *.o counter
|
-rm -f *.o counter
|
||||||
|
|
||||||
|
.PHONY: update
|
||||||
|
update:
|
||||||
|
sudo systemctl stop counter
|
||||||
|
sudo cp counter $(INST_DIR)
|
||||||
|
sudo systemctl start counter
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
install:
|
||||||
|
sudo mkdir -p $(INST_DIR)
|
||||||
|
sudo cp counter counter.service $(INST_DIR)
|
||||||
|
sudo systemctl enable $(INST_DIR)/counter.service
|
||||||
|
sudo systemctl start counter
|
||||||
|
|
||||||
|
.PHONY: stop
|
||||||
|
stop:
|
||||||
|
sudo systemctl stop counter
|
||||||
|
|
||||||
|
.PHONY: start
|
||||||
|
start:
|
||||||
|
sudo systemctl start counter
|
||||||
|
|
||||||
|
.PHONY: restart
|
||||||
|
restart:
|
||||||
|
sudo systemctl restart counter
|
||||||
|
|
||||||
|
1
src/VERSION
Normal file
1
src/VERSION
Normal file
@ -0,0 +1 @@
|
|||||||
|
0.97
|
@ -5,13 +5,18 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "LS7366R.h"
|
#include "LS7366R.h"
|
||||||
#include "influx.h"
|
#include "influx.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern char VERSION[];
|
||||||
|
extern uint32_t REFCNT;
|
||||||
|
|
||||||
const int CTRL_OUT = 16;
|
const int CTRL_OUT = 16;
|
||||||
const int INTR_IN = 19;
|
const int INTR_IN = 19;
|
||||||
const int SPI_CHAN = 0;
|
const int SPI_CHAN = 0;
|
||||||
@ -51,7 +56,7 @@ void init() {
|
|||||||
void readConfig() {
|
void readConfig() {
|
||||||
config_init(&cfg);
|
config_init(&cfg);
|
||||||
if (! config_read_file(&cfg, "/opt/etc/counter.cfg")) {
|
if (! config_read_file(&cfg, "/opt/etc/counter.cfg")) {
|
||||||
fprintf(stderr, "failed to read config file: %s:%d - %s\n",
|
logmsg(LOG_ERR, "failed to read config file: %s:%d - %s\n",
|
||||||
config_error_file(&cfg), config_error_line(&cfg),
|
config_error_file(&cfg), config_error_line(&cfg),
|
||||||
config_error_text(&cfg));
|
config_error_text(&cfg));
|
||||||
config_destroy(&cfg);
|
config_destroy(&cfg);
|
||||||
@ -64,6 +69,7 @@ void start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main (void) {
|
int main (void) {
|
||||||
|
fprintf(stderr, "VERSION: %s, REFCNT: %u\n", VERSION, REFCNT);
|
||||||
|
|
||||||
readConfig();
|
readConfig();
|
||||||
init();
|
init();
|
||||||
@ -76,31 +82,40 @@ int main (void) {
|
|||||||
if (! config_lookup_float(&cfg, EPSILON_KEY, &epsilon)) {
|
if (! config_lookup_float(&cfg, EPSILON_KEY, &epsilon)) {
|
||||||
epsilon = DEFAULT_EPSILON;
|
epsilon = DEFAULT_EPSILON;
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "CONFIG: epsilon=%f\n", epsilon);
|
||||||
|
|
||||||
|
|
||||||
double lastF = 0;
|
double lastF = 0;
|
||||||
bool settled = false;
|
bool settled = false;
|
||||||
uint8_t ledTick = 0;
|
uint8_t ledTick = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
uint32_t diff = ringbufferGet();
|
uint32_t period = ringbufferGet();
|
||||||
|
|
||||||
double f = 1.0 / (((double) diff) / 1000000.0);
|
double fRaw = 1.0 / (((double) period) / 1000000.0);
|
||||||
|
int valid = settled ? 1 : 0;
|
||||||
|
|
||||||
if (settled && (abs(f - lastF) > epsilon)) {
|
double gradient = fRaw - lastF;
|
||||||
printf("Current f=%f, last f=%f, gradient too large, skipped\n", f, lastF);
|
double fSmoothed = fRaw;
|
||||||
|
if (settled && (fabs(gradient) > epsilon)) {
|
||||||
|
logmsg(LOG_INFO, "Current f=%f, last f=%f, gradient %f too large, invalid\n", fRaw, lastF, gradient);
|
||||||
skipped++;
|
skipped++;
|
||||||
f = lastF;
|
fSmoothed = lastF;
|
||||||
|
valid = 0;
|
||||||
|
} else {
|
||||||
|
lastF = fRaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settled) {
|
||||||
|
influxAddFrequency(period, fRaw, fSmoothed, gradient, valid);
|
||||||
}
|
}
|
||||||
lastF = f;
|
|
||||||
// printf("%f\n", f);
|
|
||||||
influxAddFrequency(f);
|
|
||||||
|
|
||||||
ledTick++;
|
ledTick++;
|
||||||
if (ledTick == 50) {
|
if (ledTick == 50) {
|
||||||
ledTick = 0;
|
ledTick = 0;
|
||||||
led(E_GREEN, false);
|
led(E_GREEN, false);
|
||||||
if (! settled) {
|
if (! settled) {
|
||||||
printf("Now it is settled\n");
|
logmsg(LOG_INFO, "Now it is settled\n");
|
||||||
settled = true;
|
settled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,7 @@ After=network-online.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
GuessMainPID=yes
|
ExecStart=/opt/sbin/counter
|
||||||
ExecStart=/opt/bin/counter
|
|
||||||
ExecStop=kill -SIGINT $mainpid
|
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
WorkingDirectory=/tmp
|
WorkingDirectory=/tmp
|
||||||
|
|
||||||
|
119
src/influx.c
119
src/influx.c
@ -1,5 +1,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -7,6 +8,7 @@
|
|||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
|
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
|
||||||
const char INFLUXURL_KEY[] = "influxUrl";
|
const char INFLUXURL_KEY[] = "influxUrl";
|
||||||
@ -18,6 +20,12 @@ const char INFLUXPASS_KEY[] = "influxPass";
|
|||||||
const char *influxPass;
|
const char *influxPass;
|
||||||
const char INFLUXTAG_KEY[] = "influxTag";
|
const char INFLUXTAG_KEY[] = "influxTag";
|
||||||
const char *influxTag;
|
const char *influxTag;
|
||||||
|
const char DEFAULT_LOCATION[] = "Essen_DE";
|
||||||
|
const char LOCATION_KEY[] = "location";
|
||||||
|
const char *location;
|
||||||
|
|
||||||
|
const uint8_t ONE_SECOND_DIVIDER = 50;
|
||||||
|
|
||||||
|
|
||||||
extern uint32_t skipped;
|
extern uint32_t skipped;
|
||||||
|
|
||||||
@ -25,15 +33,34 @@ extern uint32_t skipped;
|
|||||||
// #define BUFSIZE 131070
|
// #define BUFSIZE 131070
|
||||||
#define BUFSIZE 65535
|
#define BUFSIZE 65535
|
||||||
// #define BUFSIZE 1024
|
// #define BUFSIZE 1024
|
||||||
char influxBuffer[BUFSIZE];
|
// char influxBuffer[BUFSIZE];
|
||||||
char *bufferNextEntry;
|
// char *bufferNextEntry;
|
||||||
|
|
||||||
|
typedef struct influxBuffer {
|
||||||
|
uint32_t entries;
|
||||||
|
uint32_t totalEntries;
|
||||||
|
char *nextEntry;
|
||||||
|
char buffer[BUFSIZE];
|
||||||
|
} tInfluxBuffer;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PERIOD_20MS = 0,
|
||||||
|
PERIOD_1S,
|
||||||
|
PERIOD_END
|
||||||
|
} ePeriod;
|
||||||
|
|
||||||
|
tInfluxBuffer *influxBuffers[PERIOD_END];
|
||||||
|
|
||||||
#define HOSTNAMESIZE 128
|
#define HOSTNAMESIZE 128
|
||||||
char hostname[HOSTNAMESIZE];
|
char hostname[HOSTNAMESIZE];
|
||||||
|
|
||||||
static void influxClearBuffer() {
|
static void influxClearBuffer(tInfluxBuffer *influxBuffer, bool initial) {
|
||||||
memset(influxBuffer, 0, BUFSIZE);
|
memset(influxBuffer->buffer, 0, BUFSIZE);
|
||||||
bufferNextEntry = influxBuffer;
|
influxBuffer->nextEntry = influxBuffer->buffer;
|
||||||
|
influxBuffer->entries = 0;
|
||||||
|
if (initial) {
|
||||||
|
influxBuffer->totalEntries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,22 +68,33 @@ void influxInit(config_t *pCfg) {
|
|||||||
if (! config_lookup_string(pCfg, INFLUXURL_KEY, &influxUrl)) {
|
if (! config_lookup_string(pCfg, INFLUXURL_KEY, &influxUrl)) {
|
||||||
influxUrl = DEFAULT_INFLUXURL;
|
influxUrl = DEFAULT_INFLUXURL;
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "CONFIG: influxUrl=%s\n", influxUrl);
|
||||||
if (! config_lookup_string(pCfg, INFLUXUSER_KEY, &influxUser)) {
|
if (! config_lookup_string(pCfg, INFLUXUSER_KEY, &influxUser)) {
|
||||||
influxUser = NULL;
|
influxUser = NULL;
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "CONFIG: influxUser=%s\n", (influxUser == NULL ? "<null>" : influxUser));
|
||||||
if (! config_lookup_string(pCfg, INFLUXPASS_KEY, &influxPass)) {
|
if (! config_lookup_string(pCfg, INFLUXPASS_KEY, &influxPass)) {
|
||||||
influxPass = NULL;
|
influxPass = NULL;
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "CONFIG: influxPass=%s\n", (influxPass == NULL ? "<null>" : influxPass));
|
||||||
|
if (! config_lookup_string(pCfg, LOCATION_KEY, &location)) {
|
||||||
|
location = DEFAULT_LOCATION;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "CONFIG: location=%s\n", location);
|
||||||
if (! config_lookup_string(pCfg, INFLUXTAG_KEY, &influxTag)) {
|
if (! config_lookup_string(pCfg, INFLUXTAG_KEY, &influxTag)) {
|
||||||
gethostname(hostname, HOSTNAMESIZE);
|
gethostname(hostname, HOSTNAMESIZE);
|
||||||
influxTag = hostname;
|
influxTag = hostname;
|
||||||
}
|
}
|
||||||
influxClearBuffer();
|
fprintf(stderr, "CONFIG: influxTag=%s\n", influxTag);
|
||||||
|
influxBuffers[PERIOD_20MS] = (tInfluxBuffer*) malloc(sizeof(tInfluxBuffer));
|
||||||
|
influxClearBuffer(influxBuffers[PERIOD_20MS], true);
|
||||||
|
influxBuffers[PERIOD_1S] = (tInfluxBuffer*) malloc(sizeof(tInfluxBuffer));
|
||||||
|
influxClearBuffer(influxBuffers[PERIOD_1S], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void influxSendRequest() {
|
static void influxSendRequest(tInfluxBuffer *influxBuffer) {
|
||||||
led(E_RED, false);
|
led(E_RED, false);
|
||||||
led(E_BLUE, true);
|
led(E_BLUE, true);
|
||||||
CURL *curl = curl_easy_init();
|
CURL *curl = curl_easy_init();
|
||||||
@ -67,10 +105,10 @@ static void influxSendRequest() {
|
|||||||
curl_easy_setopt(curl, CURLOPT_USERNAME, influxUser);
|
curl_easy_setopt(curl, CURLOPT_USERNAME, influxUser);
|
||||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, influxPass);
|
curl_easy_setopt(curl, CURLOPT_PASSWORD, influxPass);
|
||||||
}
|
}
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, influxBuffer);
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, influxBuffer->buffer);
|
||||||
CURLcode res = curl_easy_perform(curl);
|
CURLcode res = curl_easy_perform(curl);
|
||||||
if(res != CURLE_OK) {
|
if(res != CURLE_OK) {
|
||||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
logmsg(LOG_ERR, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||||
led(E_RED, true);
|
led(E_RED, true);
|
||||||
}
|
}
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
@ -78,27 +116,64 @@ static void influxSendRequest() {
|
|||||||
led(E_BLUE, false);
|
led(E_BLUE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void influxAddFrequency(double f) {
|
void influxAddFrequency(uint32_t period, double fRaw, double fSmoothed, double gradient,
|
||||||
static uint32_t entries = 0;
|
int valid) {
|
||||||
static uint32_t totalEntries = 0;
|
static uint8_t divider = 0;
|
||||||
|
static uint32_t summedUpTime = 0;
|
||||||
char tmpBuf[256];
|
char tmpBuf[256];
|
||||||
struct timespec t;
|
struct timespec t;
|
||||||
|
|
||||||
clock_gettime(CLOCK_REALTIME, &t);
|
clock_gettime(CLOCK_REALTIME, &t);
|
||||||
uint64_t tt = (((uint64_t)t.tv_sec) * 1000) + (((uint64_t)t.tv_nsec) / 1000000);
|
uint64_t tt = (((uint64_t)t.tv_sec) * 1000) + (((uint64_t)t.tv_nsec) / 1000000);
|
||||||
int c = sprintf(tmpBuf, "mainsfrequency,host=%s freq=%f %llu\n", influxTag, f, tt);
|
int c = sprintf(tmpBuf, "mainsfrequency,host=%s,valid=%d,location=%s "
|
||||||
|
"period=%u,freq=%f,freqSmoothed=%f,gradient=%f,freqRaw=%f "
|
||||||
|
"%llu\n",
|
||||||
|
influxTag, valid, location,
|
||||||
|
period, fSmoothed, fSmoothed, gradient, fRaw,
|
||||||
|
tt);
|
||||||
|
|
||||||
if ((bufferNextEntry + c + 10) > (influxBuffer + BUFSIZE)) {
|
if ((influxBuffers[PERIOD_20MS]->nextEntry + c + 10) > (influxBuffers[PERIOD_20MS]->buffer + BUFSIZE)) {
|
||||||
influxSendRequest();
|
influxSendRequest(influxBuffers[PERIOD_20MS]);
|
||||||
influxClearBuffer();
|
influxBuffers[PERIOD_20MS]->totalEntries += influxBuffers[PERIOD_20MS]->entries;
|
||||||
totalEntries += entries;
|
logmsg(LOG_INFO, "%u 20ms-entries sent to database, in total %u, invalid: %u\n",
|
||||||
fprintf(stderr, "%u entries sent to database, in total %u, skipped: %u\n", entries, totalEntries, skipped);
|
influxBuffers[PERIOD_20MS]->entries, influxBuffers[PERIOD_20MS]->totalEntries, skipped);
|
||||||
entries = 0;
|
influxClearBuffer(influxBuffers[PERIOD_20MS], false);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(bufferNextEntry, tmpBuf, c);
|
memcpy(influxBuffers[PERIOD_20MS]->nextEntry, tmpBuf, c);
|
||||||
bufferNextEntry += c;
|
influxBuffers[PERIOD_20MS]->nextEntry += c;
|
||||||
entries++;
|
influxBuffers[PERIOD_20MS]->entries += 1;
|
||||||
|
|
||||||
|
summedUpTime += period;
|
||||||
|
divider += 1;
|
||||||
|
|
||||||
|
if (divider == ONE_SECOND_DIVIDER) {
|
||||||
|
double freq1S = ((double)ONE_SECOND_DIVIDER) / (((double)summedUpTime) / 1000000.0);
|
||||||
|
logmsg(LOG_DEBUG, "%llu: %u %f\n", tt, summedUpTime, freq1S);
|
||||||
|
|
||||||
|
int c = sprintf(tmpBuf, "mainsfrequency1S,host=%s,location=%s "
|
||||||
|
"freq=%f "
|
||||||
|
"%llu\n",
|
||||||
|
influxTag, location,
|
||||||
|
freq1S,
|
||||||
|
tt);
|
||||||
|
|
||||||
|
//if ((influxBuffers[PERIOD_1S]->nextEntry + c + 10) > (influxBuffers[PERIOD_1S]->buffer + BUFSIZE)) {
|
||||||
|
if (influxBuffers[PERIOD_1S]->entries == 30) {
|
||||||
|
influxSendRequest(influxBuffers[PERIOD_1S]);
|
||||||
|
influxBuffers[PERIOD_1S]->totalEntries += influxBuffers[PERIOD_1S]->entries;
|
||||||
|
logmsg(LOG_INFO, "%u 1s-entries sent to database, in total %u\n",
|
||||||
|
influxBuffers[PERIOD_1S]->entries, influxBuffers[PERIOD_1S]->totalEntries);
|
||||||
|
influxClearBuffer(influxBuffers[PERIOD_1S], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(influxBuffers[PERIOD_1S]->nextEntry, tmpBuf, c);
|
||||||
|
influxBuffers[PERIOD_1S]->nextEntry += c;
|
||||||
|
influxBuffers[PERIOD_1S]->entries += 1;
|
||||||
|
|
||||||
|
divider = 0;
|
||||||
|
summedUpTime = 0.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
|
|
||||||
void influxAddFrequency(double f);
|
void influxAddFrequency(uint32_t period, double fRaw, double fSmoothed, double gradient, int valid);
|
||||||
void influxInit(config_t *pCfg);
|
void influxInit(config_t *pCfg);
|
||||||
|
|
||||||
#endif // _INFLUX_H_
|
#endif // _INFLUX_H_
|
13
src/logging.c
Normal file
13
src/logging.c
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include <syslog.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
void logmsg(int prio, const char* format, ...) {
|
||||||
|
va_list vl;
|
||||||
|
|
||||||
|
openlog("counter", 0, LOG_LOCAL0);
|
||||||
|
va_start(vl, format);
|
||||||
|
vsyslog(prio, format, vl);
|
||||||
|
va_end(vl);
|
||||||
|
closelog();
|
||||||
|
}
|
||||||
|
|
8
src/logging.h
Normal file
8
src/logging.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef _LOGGING_H_
|
||||||
|
#define _LOGGING_H_
|
||||||
|
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
void logmsg(int prio, const char* format, ...);
|
||||||
|
|
||||||
|
#endif // _LOGGING_H_
|
6
src/version.c
Normal file
6
src/version.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
const uint32_t REFCNT = D_REFCNT;
|
||||||
|
const char VERSION[] = D_VERSION;
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user