Compare commits

...
70 Commits
Author SHA1 Message Date
smayzy 6996ef4dc7 change tension limits 2026-05-19 19:00:07 +02:00
smayzy d65f4a3baa set now in main at the top 2026-05-10 19:26:17 +02:00
smayzy 85075c1efb use abs on speed 2026-05-07 12:31:10 +02:00
smayzy 1b848e77e5 set locale 2026-05-06 09:25:14 +02:00
smayzy 21046b2bd3 add receiver option 2026-05-03 18:31:02 +02:00
smayzy 45dffd54ad prevent bat from going negative 2026-05-03 16:04:32 +02:00
smayzy 66002a0e1d add write_uart 2026-05-03 14:40:06 +02:00
smayzy c09f0a81b0 add error message display 2026-05-02 12:30:15 +02:00
smayzy ed516cc804 correct datatype 2026-05-02 10:48:16 +02:00
smayzy aef366e593 better ldata & hdata 2026-04-27 19:56:56 +02:00
smayzy cd7728c2b7 better random 2026-04-27 19:49:37 +02:00
smayzy f8957a4cf9 indentation 2026-04-27 19:41:17 +02:00
smayzy 52c2deb4ca remove useless check as previous one is enough 2026-04-27 14:59:41 +02:00
smayzy 45bad91ba7 clear uart parity 2026-04-27 14:58:12 +02:00
smayzy d44ecffb41 prevent can from parsing partial frames 2026-04-27 14:39:05 +02:00
smayzy 4dbf6d4d3d add safeguard if clock does some undifined shenanigans 2026-04-27 14:35:18 +02:00
smayzy fb5b5c00d7 set VMIN AND VTIME TO 0 on uart 2026-04-27 14:29:45 +02:00
smayzy 57b9a1036c skip uart_read logic if empty 2026-04-27 13:54:29 +02:00
smayzy b4dfc516fa skip can_read logic if empty 2026-04-27 13:51:26 +02:00
smayzy b4b748c042 prevent overflow in win_bar 2026-04-27 13:47:20 +02:00
smayzy ed41a14d36 typo 2026-04-27 13:44:56 +02:00
smayzy 9047546be0 add win_warn and fix uart speed 2026-04-27 13:26:39 +02:00
smayzy 4ca757c738 clean a bit 2026-04-27 02:12:47 +02:00
smayzy f1193eba72 add battery percentage calculations 2026-04-27 02:06:57 +02:00
smayzy 9ad4579879 missed 2026-04-27 01:32:04 +02:00
smayzy d25cff82ad add calc_data 2026-04-27 01:28:46 +02:00
smayzy 81e2a7a90b add tens and amp 2026-04-27 00:55:05 +02:00
smayzy cf82ec5071 add uart support 2026-04-26 20:31:43 +02:00
smayzy 5aa878d289 close soc if ioctl fails 2026-04-11 16:49:46 +02:00
smayzy 836a0b52c4 remove useless wattroff 2026-04-11 16:47:49 +02:00
smayzy f703745fe5 Revert "remove useless wait" do I even have a brain
This reverts commit 1500e35ed1.
2026-04-11 16:42:42 +02:00
smayzy 94a65c2889 avoid copy of struct at each function call 2026-04-11 16:35:36 +02:00
smayzy a0dab8fd7f change help message 2026-04-11 16:20:05 +02:00
smayzy 1500e35ed1 remove useless wait 2026-04-11 16:14:40 +02:00
smayzy 5c4c342455 correct can speed calcs 2026-04-11 15:34:12 +02:00
smayzy 7dad14fa4e add ioctl checks 2026-04-11 15:31:15 +02:00
smayzy 1993006247 change socket to O_NONBLOCK 2026-04-11 15:29:16 +02:00
smayzy 25d8136d74 closes socket 2026-04-11 15:12:54 +02:00
smayzy acc093b2a2 forgot to add c in getopt 2026-04-09 18:00:10 +02:00
smayzy 673cdb16a0 add can support 2026-04-09 17:56:06 +02:00
smayzy 6cd0fbcf3f change help message 2026-04-07 17:37:37 +02:00
smayzy 12e93e0821 switch to the struct for positioning 2026-04-06 15:57:52 +02:00
smayzy 8f20eb454c simplify color logic 2026-04-06 13:49:47 +02:00
smayzy f4f540e532 convert win functions to take st 2026-04-06 13:22:31 +02:00
smayzy b562f573b6 rename Str to St for structs to prevent taking them for strings 2026-04-06 13:09:28 +02:00
smayzy ac90df80cd move win to struct 2026-04-06 13:05:26 +02:00
smayzy 403b3f6082 add telemetry to a struct 2026-04-06 12:38:15 +02:00
smayzy 9b6c7f7540 add error case for too small terminal window 2026-03-31 15:52:20 +02:00
smayzy 7e24d35a95 remove undiffined behaviour 2026-03-31 14:56:43 +02:00
smayzy 4227e38ad6 use bitmap for bar 2026-03-30 13:53:08 +02:00
smayzy dda471aa34 add delimiting marks for bar 2026-01-01 00:55:56 +01:00
smayzy 7d20fca1ab better color for the bar 2026-01-01 00:26:27 +01:00
smayzy 8fa46b3fbc better interuption mechanism 2026-01-01 00:05:04 +01:00
smayzy e474653363 layout and adjustements 2025-12-31 19:29:18 +01:00
smayzy be10b800bf wrong function 2025-12-31 19:15:22 +01:00
smayzy e6b52afc8e add min data 2025-12-31 18:20:09 +01:00
smayzy b168ae2927 add color 2025-12-31 17:43:17 +01:00
smayzy 323666f128 set max dynamically 2025-12-31 12:34:02 +01:00
smayzy e7d3c7697e change layout 2025-12-29 15:44:33 +01:00
smayzy 27b17a39dc add bar for rpm and float for eff 2025-12-29 14:32:18 +01:00
smayzy f5aac64907 correct formating 2025-12-29 13:26:15 +01:00
smayzy c8003fde24 add win_float 2025-12-29 13:21:38 +01:00
smayzy 6b48126f7e add args and better delay logic 2025-12-28 17:09:57 +01:00
smayzy 9abaae1e00 use on both big 2025-12-26 19:28:59 +01:00
smayzy b51450d083 fix indentation 2025-12-26 16:09:12 +01:00
smayzy c2e04f379d add bitmap numbers 2025-12-26 16:07:32 +01:00
smayzy 52e9338ca5 reformat 2025-12-23 19:22:20 +01:00
smayzy e65a407871 add layout and remove update that was trash 2025-12-22 21:43:19 +01:00
smayzy b38ad16d13 add loading bar 2025-12-19 13:11:20 +01:00
smayzy 82f5a40a87 add rand number 2025-12-18 17:59:11 +01:00
2 changed files with 743 additions and 27 deletions
+10
View File
@@ -2,3 +2,13 @@
# Dependencies
- ncurses (libncursesw.so.6)
# Data Shown
- speed (km/h)
- power (W)
- rpm (tr/min)
- bat (%)
- tens (V)
- amp (A)
- eff (Wh/Km)
- warn (message)
+739 -33
View File
@@ -1,49 +1,755 @@
#include <ctype.h>
#include <ncurses.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <linux/can.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <locale.h>
#include <stdlib.h>
void update(WINDOW *win)
{
int win_y, win_x;
char message[] = "test";
getmaxyx(win, win_y, win_x);
mvwprintw(win, win_y/2, win_x/2 - strlen(message)/2, "%s", message);
wrefresh(win);
const int digit_bitmaps[10][5][3] = {
{{1,1,1},{1,0,1},{1,0,1},{1,0,1},{1,1,1}}, // 0
{{0,1,0},{1,1,0},{0,1,0},{0,1,0},{1,1,1}}, // 1
{{1,1,1},{0,0,1},{1,1,1},{1,0,0},{1,1,1}}, // 2
{{1,1,1},{0,0,1},{1,1,1},{0,0,1},{1,1,1}}, // 3
{{1,0,1},{1,0,1},{1,1,1},{0,0,1},{0,0,1}}, // 4
{{1,1,1},{1,0,0},{1,1,1},{0,0,1},{1,1,1}}, // 5
{{1,1,1},{1,0,0},{1,1,1},{1,0,1},{1,1,1}}, // 6
{{1,1,1},{0,0,1},{0,1,0},{0,1,0},{0,1,0}}, // 7
{{1,1,1},{1,0,1},{1,1,1},{1,0,1},{1,1,1}}, // 8
{{1,1,1},{1,0,1},{1,1,1},{0,0,1},{1,1,1}} // 9
};
typedef struct{
int data;
int ldata;
int hdata;
int digits;
bool high;
int height;
int width;
int starty;
int startx;
WINDOW *lwin;
char title[30];
} StInt;
typedef struct{
float data;
float ldata;
float hdata;
int digits;
bool high;
int height;
int width;
int starty;
int startx;
WINDOW *lwin;
char title[30];
} StFlt;
typedef struct {
int err;
long last_err;
} Error;
typedef struct{
long last_error;
int error_level;
int height;
int width;
int starty;
int startx;
WINDOW *lwin;
char title[30];
Error speed;
Error rpm;
Error power;
Error eff;
Error bat;
Error tens;
Error amp;
} StStr;
typedef struct {
char linebuf[128];
int linepos;
} SerialParser;
typedef struct {
StInt speed;
StInt rpm;
StInt power;
StFlt eff;
StInt bat;
StFlt tens;
StFlt amp;
StStr message;
} Tel;
typedef struct {
float wh_used;
float wh_total;
long previous_ms;
} Bat_state;
void win_init_int(StInt *st) {
st->lwin = newwin(st->height, st->width, st->starty, st->startx);
box(st->lwin, 0, 0);
mvwprintw(st->lwin, 0, 2, "%s", st->title);
wrefresh(st->lwin);
};
void win_init_flt(StFlt *st) {
st->lwin = newwin(st->height, st->width, st->starty, st->startx);
box(st->lwin, 0, 0);
mvwprintw(st->lwin, 0, 2, "%s", st->title);
wrefresh(st->lwin);
};
void win_init_str(StStr *st) {
st->lwin = newwin(st->height, st->width, st->starty, st->startx);
box(st->lwin, 0, 0);
mvwprintw(st->lwin, 0, 2, "%s", st->title);
wrefresh(st->lwin);
};
void get_fake_data(Tel *t) {
t->rpm.data = t->rpm.ldata + rand() % (t->rpm.hdata - t->rpm.ldata + 1);
t->tens.data = t->tens.ldata + ((float)rand() / (float)RAND_MAX) * (float)(t->tens.hdata - t->tens.ldata);
t->amp.data = t->amp.ldata + ((float)rand() / (float)RAND_MAX) * (float)(t->amp.hdata - t->amp.ldata);
}
void read_can(Tel *t, int soc) {
struct can_frame frame;
int nbytes = read(soc, &frame, sizeof(struct can_frame));
if (nbytes < 0) return; // -1 EAGAIN means empty
if (nbytes != sizeof(struct can_frame)) return;
switch (frame.can_id) {
case 0x382:
if (frame.can_dlc >= 2) {
t->rpm.data = abs((int16_t)(frame.data[0] | (frame.data[1] << 8)));
}
break;
default:
break;
}
}
void read_uart(Tel *t, int fd, SerialParser *uart_str) {
char buf[128];
int n = read(fd, buf, sizeof(buf));
if (n < 0) return; // -1 EAGAIN means empty
if (n > 0) {
for (int i = 0; i < n; i++) {
char c = buf[i];
if (c == '\n') {
uart_str->linebuf[uart_str->linepos] = '\0';
float tmp_v, tmp_a;
if (sscanf(uart_str->linebuf, "%f,%f", &tmp_v, &tmp_a) == 2) {
t->tens.data = tmp_v;
t->amp.data = tmp_a;
}
uart_str->linepos = 0;
}
if (uart_str->linepos < (int)sizeof(uart_str->linebuf) - 1) {
uart_str->linebuf[uart_str->linepos++] = c;
} else {
uart_str->linepos = 0; // drop line to prevent overflow
}
}
}
}
void read_uart_receiver(Tel *t, int fd, SerialParser *uart_str) {
char buf[128];
int n = read(fd, buf, sizeof(buf));
if (n < 0) return; // -1 EAGAIN means empty
if (n > 0) {
for (int i = 0; i < n; i++) {
char c = buf[i];
if (c == '\n') {
uart_str->linebuf[uart_str->linepos] = '\0';
int tmp_speed, tmp_rpm, tmp_power, tmp_bat, tmp_warn;
float tmp_eff, tmp_tens, tmp_amp;
if (sscanf(uart_str->linebuf, "%d,%d,%d,%f,%d,%f,%f,%d", &tmp_speed, &tmp_rpm, &tmp_power, &tmp_eff, &tmp_bat, &tmp_tens, &tmp_amp, &tmp_warn) == 8) {
t->speed.data = tmp_speed;
t->rpm.data = tmp_rpm;
t->power.data = tmp_power;
t->eff.data = tmp_eff;
t->bat.data = tmp_bat;
t->tens.data = tmp_tens;
t->amp.data = tmp_amp;
t->message.error_level = tmp_warn;
}
uart_str->linepos = 0;
}
if (uart_str->linepos < (int)sizeof(uart_str->linebuf) - 1) {
uart_str->linebuf[uart_str->linepos++] = c;
} else {
uart_str->linepos = 0; // drop line to prevent overflow
}
}
}
}
void write_uart(Tel *t, int fd) {
// speed,rpm,power,eff,bat,tens,amp,warn
char msg[256];
int len = snprintf(msg, sizeof(msg), "%d,%d,%d,%.1f,%d,%.1f,%.1f,%d\n",
t->speed.data,
t->rpm.data,
t->power.data,
t->eff.data,
t->bat.data,
t->tens.data,
t->amp.data,
t->message.error_level );
if (len < 0 || len >= (int)sizeof(msg)) {
return;
}
int total = 0;
while (total < len) {
int n = write(fd, msg + total, len - total);
if (n < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN) continue;
return;
}
total += n;
}
}
void calc_data(Tel *t, Bat_state *b, long now) {
t->power.data = (int)(t->tens.data * t->amp.data);
t->speed.data = (int)(t->rpm.data * 0.017f);
t->bat.data = (int)((b->wh_total - b->wh_used) * 100 / b->wh_total);
if (t->speed.data > 0) {
t->eff.data = (float)t->power.data / (float)t->speed.data;
} else {
t->eff.data = 0.0f;
}
long dt = now - b->previous_ms;
if (dt < 0) dt = 0;
b->previous_ms = now;
b->wh_used += (float)t->power.data * (float)dt / 3600000.0f;
if (b->wh_used > b->wh_total) b->wh_used = b->wh_total;
}
long now_ms(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}
void win_clear(WINDOW *lwin) {
int y, x;
getmaxyx(lwin, y, x);
for (int i = 1; i < y - 1; i++) {
mvwhline(lwin, i, 1, ' ', x - 2);
}
}
int smaller_of(int a, int b) {
return (a < b) ? a : b;
}
int color_high(float data, float ldata, float hdata) {
int percent = (int)((100.0f * (data - ldata)) / (hdata - ldata) + 0.5f);
if (percent >= 90) return 1;
else if (percent >= 75) return 2;
else return 3;
}
int color_low(float data, float ldata, float hdata) {
int percent = 100 - (int)((100.0f * (data - ldata)) / (hdata - ldata) + 0.5f);
if (percent >= 90) return 1;
else if (percent >= 75) return 2;
else return 3;
}
void bar_mark(WINDOW *lwin) {
int lwiny, lwinx;
int first_mark, last_mark;
getmaxyx(lwin, lwiny, lwinx);
first_mark = (75 * (lwinx - 4)) / 100;
last_mark = (90 * (lwinx - 4)) / 100;
mvwaddch(lwin, 0, first_mark + 1, '|');
mvwaddch(lwin, lwiny - 1, first_mark + 1, '|');
mvwaddch(lwin, 0, last_mark + 1, '|');
mvwaddch(lwin, lwiny - 1, last_mark + 1, '|');
}
void win_int(StInt *st, bool use_color) {
int color;
if (st->high) {
color = color_high(st->data, st->ldata, st->hdata);
} else {
color = color_low(st->data, st->ldata, st->hdata);
};
int lwiny, lwinx, len;
char buf[16];
getmaxyx(st->lwin, lwiny, lwinx);
snprintf(buf , sizeof(buf), "%d", st->data);
len = strlen(buf);
int bh = 5; // bitmap height
int bw = 3; // bitmap width
int size = smaller_of((lwiny - 2) / bh, (lwinx - 2 - (st->digits - 1)) / (bw * st->digits));
int total_width = st->digits * (bw * size) + (st->digits - 1);
int startx = (lwinx - total_width) / 2;
int starty = (lwiny - bh * size) / 2;
int offset = (bw * size + 1) * (st->digits - len);
win_clear(st->lwin);
if (use_color) wattron(st->lwin, COLOR_PAIR(color));
for (int d = 0; d < len; d++) {
int digit = buf[d] - '0';
int dx = startx + d * (bw * size + 1) + offset;
for (int y = 0; y < bh; y++) {
for (int x = 0; x < bw; x++) {
if (digit_bitmaps[digit][y][x]) {
for (int yy = 0; yy < size; yy++)
for (int xx = 0; xx < size; xx++)
mvwaddch(st->lwin,
starty + y * size + yy,
dx + x * size + xx,
ACS_CKBOARD);
}
}
}
}
if (use_color) wattroff(st->lwin, COLOR_PAIR(color));
wrefresh(st->lwin);
}
void win_float(StFlt *st, bool use_color) {
int color;
if (st->high) {
color = color_high(st->data, st->ldata, st->hdata);
} else {
color = color_low(st->data, st->ldata, st->hdata);
};
int lwiny, lwinx, len;
char buf[16];
getmaxyx(st->lwin, lwiny, lwinx);
snprintf(buf , sizeof(buf), "%.1f", st->data);
len = strlen(buf);
int bh = 5; // bitmap height
int bw = 3; // bitmap width
int size = smaller_of((lwiny - 2) / bh, (lwinx - 2 - (st->digits - 1)) / (bw * st->digits));
int total_width = st->digits * (bw * size) + (st->digits - 1);
int startx = (lwinx - total_width) / 2;
int starty = (lwiny - bh * size) / 2;
int offset = (bw * size + 1) * (st->digits - len);
win_clear(st->lwin);
if (use_color) wattron(st->lwin, COLOR_PAIR(color));
for (int d = 0; d < len; d++) {
int dx = startx + d * (bw * size + 1) + offset;
if (buf[d] == '.') {
for (int yy = 0; yy < size; yy++)
for (int xx = 0; xx < size; xx++)
mvwaddch(
st->lwin,
starty + (bh - 1) * size + yy,
dx + xx,
ACS_CKBOARD
);
continue;
}
int digit = buf[d] - '0';
for (int y = 0; y < bh; y++) {
for (int x = 0; x < bw; x++) {
if (digit_bitmaps[digit][y][x]) {
for (int yy = 0; yy < size; yy++)
for (int xx = 0; xx < size; xx++)
mvwaddch(st->lwin,
starty + y * size + yy,
dx + x * size + xx,
ACS_CKBOARD);
}
}
}
}
if (use_color) wattroff(st->lwin, COLOR_PAIR(color));
wrefresh(st->lwin);
}
void win_bar(StInt *st, bool use_color) {
int lwiny, lwinx;
getmaxyx(st->lwin, lwiny, lwinx);
win_clear(st->lwin);
int bar_width = lwinx - 4;
int bar_height = lwiny - 2;
int filled = (st->data * bar_width) / st->hdata;
int yellow = (75 * bar_width) / 100;
int red = (90 * bar_width) / 100;
if (filled > bar_width) filled = bar_width;
for (int y = 1; y <= bar_height; y++) {
for (int x = 0; x < filled; x++) {
if (use_color) {
if (x < yellow)
wattron(st->lwin, COLOR_PAIR(3));
else if (x < red)
wattron(st->lwin, COLOR_PAIR(2));
else
wattron(st->lwin, COLOR_PAIR(1));
}
mvwaddch(st->lwin, y, 2 + x, ACS_CKBOARD);
}
}
if (use_color) {
wattroff(st->lwin, COLOR_PAIR(3));
wattroff(st->lwin, COLOR_PAIR(2));
wattroff(st->lwin, COLOR_PAIR(1));
}
char buf[16];
int len;
snprintf(buf , sizeof(buf), "%d", st->data);
len = strlen(buf);
int bh = 5; // bitmap height
int bw = 3; // bitmap width
int size = smaller_of((lwiny - 2) / bh, (lwinx - 2 - (st->digits - 1)) / (bw * st->digits));
int total_width = st->digits * (bw * size) + (st->digits - 1);
int startx = (lwinx - total_width) / 3;
int starty = (lwiny - bh * size) / 2;
int offset = (bw * size + 1) * (st->digits - len);
for (int d = 0; d < len; d++) {
int digit = buf[d] - '0';
int dx = startx + d * (bw * size + 1) + offset;
for (int y = 0; y < bh; y++) {
for (int x = 0; x < bw; x++) {
if (digit_bitmaps[digit][y][x]) {
for (int yy = 0; yy < size; yy++)
for (int xx = 0; xx < size; xx++)
mvwaddch(st->lwin,
starty + y * size + yy,
dx + x * size + xx,
ACS_CKBOARD);
}
}
}
}
wrefresh(st->lwin);
if (use_color) {
wattroff(st->lwin, COLOR_PAIR(0));
}
}
void win_warn(Tel *t, bool use_color, long now) {
int warn_lvl = 0;
int lwiny, lwinx;
getmaxyx(t->message.lwin, lwiny, lwinx);
win_clear(t->message.lwin);
t->message.speed.err = 0;
t->message.rpm.err = 0;
t->message.power.err = 0;
t->message.eff.err = 0;
t->message.bat.err = 0;
t->message.tens.err = 0;
t->message.amp.err = 0;
if ((t->speed.data > t->speed.hdata) || (t->speed.data < t->speed.ldata)) {warn_lvl++; t->message.speed.err = 1; t->message.speed.last_err = now; }
if ((t->rpm.data > t->rpm.hdata) || (t->rpm.data < t->rpm.ldata)) {warn_lvl++; t->message.rpm.err = 1; t->message.rpm.last_err = now; }
if ((t->power.data > t->power.hdata) || (t->power.data < t->power.ldata)) {warn_lvl++; t->message.power.err = 1; t->message.power.last_err = now; }
if ((t->bat.data > t->bat.hdata) || (t->bat.data < t->bat.ldata)) {warn_lvl++; t->message.bat.err = 1; t->message.bat.last_err = now; }
if ((t->eff.data > t->eff.hdata) || (t->eff.data < t->eff.ldata)) {warn_lvl++; t->message.eff.err = 1; t->message.eff.last_err = now; }
if ((t->tens.data > t->tens.hdata) || (t->tens.data < t->tens.ldata)) {warn_lvl++; t->message.tens.err = 1; t->message.tens.last_err = now; }
if ((t->amp.data > t->amp.hdata) || (t->amp.data < t->amp.ldata)) {warn_lvl++; t->message.amp.err = 1; t->message.amp.last_err = now; }
if (warn_lvl > 0) {
t->message.error_level = warn_lvl;
t->message.last_error = now;
} else if ((now - t->message.last_error) > 3000) {
t->message.error_level = 0;
}
if (use_color) wattron(t->message.lwin, COLOR_PAIR(2));
if (warn_lvl > 0 || (now - t->message.last_error) < 3000) {
for (int y = 1; y < lwiny - 1; y++) {
for (int x = 1; x < lwinx - 1; x++) {
mvwaddch(t->message.lwin, y, x, ACS_CKBOARD);
}
}
}
if (use_color) wattroff(t->message.lwin, COLOR_PAIR(2));
if (use_color) wattron(t->message.lwin, COLOR_PAIR(1));
if (t->message.speed.err != 0 || (now - t->message.speed.last_err) < 3000 ) mvwprintw(t->message.lwin, 2 + 0 * ((lwiny - 2) / 4), 2 , "SPEED ERROR");
if (t->message.rpm.err != 0 || (now - t->message.rpm.last_err) < 3000 ) mvwprintw(t->message.lwin, 2 + 1 * ((lwiny - 2) / 4), 2 , "RPM ERROR" );
if (t->message.power.err != 0 || (now - t->message.power.last_err) < 3000 ) mvwprintw(t->message.lwin, 2 + 2 * ((lwiny - 2) / 4), 2 , "POWER ERROR");
if (t->message.eff.err != 0 || (now - t->message.eff.last_err) < 3000 ) mvwprintw(t->message.lwin, 2 + 3 * ((lwiny - 2) / 4), 2 , "EFF ERROR" );
if (t->message.bat.err != 0 || (now - t->message.bat.last_err) < 3000 ) mvwprintw(t->message.lwin, 2 + 0 * ((lwiny - 2) / 4), lwinx / 2, "BAT ERROR" );
if (t->message.tens.err != 0 || (now - t->message.tens.last_err) < 3000 ) mvwprintw(t->message.lwin, 2 + 1 * ((lwiny - 2) / 4), lwinx / 2, "TENS ERROR" );
if (t->message.amp.err != 0 || (now - t->message.amp.last_err) < 3000 ) mvwprintw(t->message.lwin, 2 + 2 * ((lwiny - 2) / 4), lwinx / 2, "AMP ERROR" );
if (use_color) wattroff(t->message.lwin, COLOR_PAIR(1));
wrefresh(t->message.lwin);
}
int main(int argc, char **argv) {
int option;
int delay = 1;
int fake_data = 0;
int use_can = 0;
int soc = 0;
int use_uart = 0;
int uart_fd = 0;
int is_receiver = 0;
struct sockaddr_can addr;
struct ifreq ifr;
struct termios uart_str;
SerialParser uart_parser = {0};
Bat_state bat_state = {0, 1000, 0};
setlocale(LC_NUMERIC, "C");
while ((option = getopt(argc, argv, "d:hfcur")) !=-1) {
switch (option) {
case 'd' :
delay = atoi(optarg);
if (delay < 0) {
delay = 0;
}
break;
case 'f' :
fake_data = 1;
break;
case 'c' :
use_can = 1;
break;
case 'u' :
use_uart = 1;
break;
case 'r' :
is_receiver = 1;
break;
case 'h' :
printf("Usage: ./cocomobile-tui [-d int <ms multiplier>] [-h <help>] [-f <random data generation>] [-c <enable can>] [-u <enable uart connection>] [-r <set for receiver (not for the car)>]\n");
return(0);
}
}
if (use_can) {
soc = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (soc < 0) {
perror("socket error");
return 1;
}
fcntl(soc, F_SETFL, O_NONBLOCK);
strcpy(ifr.ifr_name, "can0");
if (ioctl(soc, SIOCGIFINDEX, &ifr) < 0) {
perror("ioctl error");
close(soc);
return 1;
}
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(soc, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind error");
close(soc);
return 1;
}
}
if (use_uart) {
uart_fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (uart_fd < 0) {
perror("uart open error");
return 1;
}
tcgetattr(uart_fd, &uart_str);
uart_str.c_cflag &= ~CSIZE; // clear bit size
uart_str.c_cflag |= (CLOCAL | CREAD | CS8);
uart_str.c_cflag &= ~PARENB;
cfsetispeed(&uart_str, B115200);
cfsetospeed(&uart_str, B115200);
uart_str.c_lflag = 0; // raw mode
uart_str.c_iflag = 0;
uart_str.c_oflag = 0;
uart_str.c_cc[VMIN] = 0;
uart_str.c_cc[VTIME] = 0;
tcsetattr(uart_fd, TCSAFLUSH, &uart_str); // aplly settings
}
int main()
{
initscr();
noecho();
cbreak();
curs_set(0);
nodelay(stdscr, TRUE);
refresh();
int y,x;
getmaxyx(stdscr, y, x);
WINDOW *top_win;
WINDOW *bottom_win;
top_win = newwin(y/2, x, 0, 0);
bottom_win = newwin(y-y/2, x, y/2, 0);
box(top_win, 0, 0);
box(bottom_win, 0, 0);
refresh();
wrefresh(top_win);
wrefresh(bottom_win);
int ch = ERR;
while(ch == ERR)
{
update(top_win);
update(bottom_win);
ch = getch();
};
delwin(top_win);
delwin(bottom_win);
if (y < 42 || x < 100) {
endwin();
perror("terminal window too small");
return 1;
}
bool use_color = 0;
if (has_colors()) {
use_color = 1;
start_color();
use_default_colors();
init_pair(1, COLOR_RED, -1);
init_pair(2, COLOR_YELLOW, -1);
init_pair(3, COLOR_GREEN, -1);
}
int x3 = x / 3;
int x3r = x - 2 * x3;
int y2 = y / 2;
int y2r = y - y2;
int y4 = y / 4;
int y4r = y2 - y4;
int y2r4 = y2r / 2;
int y2r4r = y2r - y2r4;
int y6 = y2r / 3;
int y6r = y - (y2 + 2* y6);
Tel tel;
tel.speed = (StInt){0 , 0 , 51 , 3, 1, y2 , x3 , 0 , 0 , NULL, "speed (km/h)" };
tel.rpm = (StInt){0 , 0 , 3000 , 4, 1, y2 , x3 , 0 , x3 , NULL, "rpm (tr/min)" };
tel.power = (StInt){0 , 0 , 1300 , 4, 1, 2*y6 , 2*x3, y2 , 0 , NULL, "power (W)" };
tel.bat = (StInt){0 , 0 , 100 , 3, 0, y4 , x3r , 0 , x-x3r , NULL, "batteries (%)" };
tel.eff = (StFlt){0.0f, 0.0f , 100.0f, 5, 1, y4r , x3r , y4 , x-x3r , NULL, "efficiency (Wh/Km)" };
tel.tens = (StFlt){0.0f, 42.0f, 58.0f , 4, 1, y2r4 , x3r , y2 , x-x3r , NULL, "tension (V)" };
tel.amp = (StFlt){0.0f, 0.0f , 30.0f , 4, 1, y2r4r, x3r , y-y2r4r, x-x3r , NULL, "intensity (A)" };
tel.message = (StStr){0 , 0 , y6r , 2*x3, y-y6r , 0 , NULL, "warnings" , {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
win_init_int(&tel.speed);
win_init_int(&tel.rpm);
win_init_int(&tel.power);
win_init_flt(&tel.eff);
win_init_int(&tel.bat);
win_init_flt(&tel.tens);
win_init_flt(&tel.amp);
win_init_str(&tel.message);
bar_mark(tel.power.lwin);
long t100 = 0;
int ch = ERR;
long now = now_ms();
bat_state.previous_ms = now;
while(1) {
now = now_ms();
ch = tolower(getch());
switch (ch) {
case 'q' :
goto end;
case ERR :
default :
if (fake_data) {
get_fake_data(&tel);
} else {
if (use_can && !is_receiver) read_can(&tel, soc);
if (use_uart && !is_receiver) read_uart(&tel, uart_fd, &uart_parser);
if (use_uart && is_receiver) read_uart_receiver(&tel, uart_fd, &uart_parser);
}
break;
}
if (!is_receiver) calc_data(&tel, &bat_state, now);
if (now - t100 >= 100 * delay) {
win_int(&tel.speed, use_color);
win_int(&tel.rpm, use_color);
win_bar(&tel.power, use_color);
win_float(&tel.eff, use_color);
win_float(&tel.tens, use_color);
win_float(&tel.amp, use_color);
win_int(&tel.bat, use_color);
win_warn(&tel, use_color, now);
if (use_uart && !is_receiver) write_uart(&tel, uart_fd);
t100 = now;
}
napms(10);
}
end:
delwin(tel.speed.lwin);
delwin(tel.rpm.lwin);
delwin(tel.power.lwin);
delwin(tel.eff.lwin);
delwin(tel.bat.lwin);
delwin(tel.tens.lwin);
delwin(tel.amp.lwin);
delwin(tel.message.lwin);
endwin();
if (use_can) close(soc);
if (use_uart) close(uart_fd);
return 0;
}