Compare commits
50
Commits
dda471aa34
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6996ef4dc7 | ||
|
|
d65f4a3baa | ||
|
|
85075c1efb | ||
|
|
1b848e77e5 | ||
|
|
21046b2bd3 | ||
|
|
45dffd54ad | ||
|
|
66002a0e1d | ||
|
|
c09f0a81b0 | ||
|
|
ed516cc804 | ||
|
|
aef366e593 | ||
|
|
cd7728c2b7 | ||
|
|
f8957a4cf9 | ||
|
|
52c2deb4ca | ||
|
|
45bad91ba7 | ||
|
|
d44ecffb41 | ||
|
|
4dbf6d4d3d | ||
|
|
fb5b5c00d7 | ||
|
|
57b9a1036c | ||
|
|
b4dfc516fa | ||
|
|
b4b748c042 | ||
|
|
ed41a14d36 | ||
|
|
9047546be0 | ||
|
|
4ca757c738 | ||
|
|
f1193eba72 | ||
|
|
9ad4579879 | ||
|
|
d25cff82ad | ||
|
|
81e2a7a90b | ||
|
|
cf82ec5071 | ||
|
|
5aa878d289 | ||
|
|
836a0b52c4 | ||
|
|
f703745fe5 | ||
|
|
94a65c2889 | ||
|
|
a0dab8fd7f | ||
|
|
1500e35ed1 | ||
|
|
5c4c342455 | ||
|
|
7dad14fa4e | ||
|
|
1993006247 | ||
|
|
25d8136d74 | ||
|
|
acc093b2a2 | ||
|
|
673cdb16a0 | ||
|
|
6cd0fbcf3f | ||
|
|
12e93e0821 | ||
|
|
8f20eb454c | ||
|
|
f4f540e532 | ||
|
|
b562f573b6 | ||
|
|
ac90df80cd | ||
|
|
403b3f6082 | ||
|
|
9b6c7f7540 | ||
|
|
7e24d35a95 | ||
|
|
4227e38ad6 |
@@ -8,9 +8,7 @@
|
||||
- power (W)
|
||||
- rpm (tr/min)
|
||||
- bat (%)
|
||||
- torque (Nm)
|
||||
- tens (V)
|
||||
- amp (A)
|
||||
- eff (Wh/Km)
|
||||
- bat_temp (°C)
|
||||
- var_temp (°C)
|
||||
- mot_temp (°C)
|
||||
- warn (message)
|
||||
|
||||
+621
-221
@@ -1,10 +1,20 @@
|
||||
#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>
|
||||
|
||||
const int digit_bitmaps[10][5][3] = {
|
||||
{{1,1,1},{1,0,1},{1,0,1},{1,0,1},{1,1,1}}, // 0
|
||||
@@ -19,22 +29,239 @@ const int digit_bitmaps[10][5][3] = {
|
||||
{{1,1,1},{1,0,1},{1,1,1},{0,0,1},{1,1,1}} // 9
|
||||
};
|
||||
|
||||
void get_fake_data(int *speed, int lspeed, int hspeed, int *power, int lpower, int hpower, int *bat, int lbat, int hbat, float *tq, float ltq, float htq, int *rpm, int lrpm, int hrpm, float *eff, float leff, float heff, float *bat_temp, float lbat_temp, float hbat_temp, float *var_temp, float lvar_temp, float hvar_temp, float *mot_temp, float lmot_temp, float hmot_temp) {
|
||||
*speed = lspeed + rand() % (hspeed - lspeed + 1);
|
||||
*power = lpower + rand() % (hpower - lpower + 1);
|
||||
*bat = lbat + rand() % (hbat - lbat + 1);
|
||||
*tq = ltq + ((float)rand() / (float)RAND_MAX) * (htq - ltq);
|
||||
*rpm = lrpm + rand() % (hrpm - lrpm + 1);
|
||||
*eff = leff + (float)rand() / (float)RAND_MAX * (heff - leff);
|
||||
*bat_temp = lbat_temp + (float)rand() / (float)RAND_MAX * (hbat_temp - lbat_temp);
|
||||
*var_temp = lvar_temp + (float)rand() / (float)RAND_MAX * (hvar_temp - lvar_temp);
|
||||
*mot_temp = lmot_temp + (float)rand() / (float)RAND_MAX * (hmot_temp - lmot_temp);
|
||||
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;
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
void win_clear(WINDOW *lwin) {
|
||||
@@ -49,146 +276,18 @@ int smaller_of(int a, int b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
void win_int(WINDOW *lwin, int data, int digits, int use_color, int color) {
|
||||
int lwiny, lwinx, len;
|
||||
char buf[16];
|
||||
getmaxyx(lwin, lwiny, lwinx);
|
||||
snprintf(buf , sizeof(buf), "%d", data);
|
||||
len = strlen(buf);
|
||||
|
||||
int bh = 5; // bitmap height
|
||||
int bw = 3; // bitmap width
|
||||
|
||||
int size = smaller_of((lwiny - 2) / bh, (lwinx - 2 - (digits - 1)) / (bw * digits));
|
||||
|
||||
int total_width = digits * (bw * size) + (digits - 1);
|
||||
int startx = (lwinx - total_width) / 2;
|
||||
int starty = (lwiny - bh * size) / 2;
|
||||
int offset = (bw * size + 1) * (digits - len);
|
||||
|
||||
win_clear(lwin);
|
||||
|
||||
if (use_color) wattron(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(lwin,
|
||||
starty + y * size + yy,
|
||||
dx + x * size + xx,
|
||||
ACS_CKBOARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (use_color) wattroff(lwin, COLOR_PAIR(color));
|
||||
|
||||
wrefresh(lwin);
|
||||
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;
|
||||
}
|
||||
|
||||
void win_float(WINDOW *lwin, float data, int digits, int use_color, int color) {
|
||||
int lwiny, lwinx, len;
|
||||
char buf[16];
|
||||
|
||||
getmaxyx(lwin, lwiny, lwinx);
|
||||
|
||||
snprintf(buf , sizeof(buf), "%.1f", data);
|
||||
len = strlen(buf);
|
||||
|
||||
int bh = 5; // bitmap height
|
||||
int bw = 3; // bitmap width
|
||||
|
||||
int size = smaller_of((lwiny - 2) / bh, (lwinx - 2 - (digits - 1)) / (bw * digits));
|
||||
|
||||
int total_width = digits * (bw * size) + (digits - 1);
|
||||
int startx = (lwinx - total_width) / 2;
|
||||
int starty = (lwiny - bh * size) / 2;
|
||||
int offset = (bw * size + 1) * (digits - len);
|
||||
|
||||
win_clear(lwin);
|
||||
|
||||
if (use_color) wattron(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(
|
||||
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(lwin,
|
||||
starty + y * size + yy,
|
||||
dx + x * size + xx,
|
||||
ACS_CKBOARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (use_color) wattroff(lwin, COLOR_PAIR(color));
|
||||
|
||||
wrefresh(lwin);
|
||||
}
|
||||
|
||||
void win_bar(WINDOW *lwin, int data, int data_max, int use_color) {
|
||||
int lwiny, lwinx;
|
||||
getmaxyx(lwin, lwiny, lwinx);
|
||||
|
||||
win_clear(lwin);
|
||||
|
||||
int bar_width = lwinx - 4;
|
||||
int bar_height = lwiny - 2;
|
||||
int filled = (data * bar_width) / data_max;
|
||||
int yellow = (75 * bar_width) / 100;
|
||||
int red = (90 * bar_width) / 100;
|
||||
|
||||
for (int y = 1; y <= bar_height; y++) {
|
||||
for (int x = 0; x < filled; x++) {
|
||||
if (use_color) {
|
||||
if (x < yellow)
|
||||
wattron(lwin, COLOR_PAIR(3));
|
||||
else if (x < red)
|
||||
wattron(lwin, COLOR_PAIR(2));
|
||||
else
|
||||
wattron(lwin, COLOR_PAIR(1));
|
||||
}
|
||||
mvwaddch(lwin, y, 2 + x, ACS_CKBOARD);
|
||||
}
|
||||
}
|
||||
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%d W", data);
|
||||
mvwprintw(lwin, lwiny / 2 - 1, 3, "%s", buf);
|
||||
|
||||
if (use_color) {
|
||||
wattroff(lwin, COLOR_PAIR(3));
|
||||
wattroff(lwin, COLOR_PAIR(2));
|
||||
wattroff(lwin, COLOR_PAIR(1));
|
||||
}
|
||||
|
||||
wrefresh(lwin);
|
||||
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) {
|
||||
@@ -203,26 +302,272 @@ void bar_mark(WINDOW *lwin) {
|
||||
mvwaddch(lwin, lwiny - 1, last_mark + 1, '|');
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
short 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 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;
|
||||
|
||||
while ((option = getopt(argc, argv, "d:hf")) !=-1) {
|
||||
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);
|
||||
@@ -233,12 +578,68 @@ int main(int argc, char **argv) {
|
||||
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: ./dashboard [-d int DELAY by how much to slow down] [-h HELP] [-f generate fake data]\n");
|
||||
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
|
||||
}
|
||||
|
||||
initscr();
|
||||
noecho();
|
||||
cbreak();
|
||||
@@ -249,10 +650,12 @@ int main(int argc, char **argv) {
|
||||
int y,x;
|
||||
getmaxyx(stdscr, y, x);
|
||||
if (y < 42 || x < 100) {
|
||||
endwin();
|
||||
perror("terminal window too small");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int use_color;
|
||||
bool use_color = 0;
|
||||
if (has_colors()) {
|
||||
use_color = 1;
|
||||
start_color();
|
||||
@@ -262,53 +665,46 @@ int main(int argc, char **argv) {
|
||||
init_pair(3, COLOR_GREEN, -1);
|
||||
}
|
||||
|
||||
WINDOW *win[10];
|
||||
|
||||
int x3 = x / 3;
|
||||
int x3r = x - 2 * x3;
|
||||
|
||||
int y2 = y / 2;
|
||||
int y2r = y - y2;
|
||||
int y4 = y2 / 2;
|
||||
int y4 = y / 4;
|
||||
int y4r = y2 - y4;
|
||||
int y6 = y2r / 3;
|
||||
int y6r = y2r - 2 * y6;
|
||||
int y2r4 = y2r / 2;
|
||||
int y2r4r = y2r - y2r4;
|
||||
int y6 = y2r / 3;
|
||||
int y6r = y - (y2 + 2* y6);
|
||||
|
||||
typedef struct {
|
||||
int height, width, starty, startx;
|
||||
char *title;
|
||||
} WinInfo;
|
||||
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}};
|
||||
|
||||
WinInfo win_infos[10] = {
|
||||
{y2, x3, 0, 0, "speed (km/h)"}, // 0
|
||||
{y2, x3, 0, x3, "rpm (tr/min)"}, // 1
|
||||
{y4, x3r, 0, x - x3r, "batteries (%)"}, // 2
|
||||
{y4r, x3r, y4, x - x3r, "torque (N/m)"}, // 3
|
||||
{y6, 2 * x3, y2, 0, "power (W)"}, // 4
|
||||
{y6, x3r, y2, 2 * x3, "efficiency (Wh/Km)"}, // 5
|
||||
{y6, x3, y2 + y6, 0, "batteries temperature (deg C)"}, // 6
|
||||
{y6, x3, y2 + y6, x3, "variator temperature (deg C)"}, // 7
|
||||
{y6, x3r, y2 + y6, x - x3r, "motor temperature (deg C)"}, // 8
|
||||
{y6r, x, y - y6r, 0, "warnings"} // 9
|
||||
};
|
||||
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);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
win[i] = newwin(win_infos[i].height, win_infos[i].width, win_infos[i].starty, win_infos[i].startx);
|
||||
box(win[i], 0, 0);
|
||||
mvwprintw(win[i], 0, 2, "%s", win_infos[i].title);
|
||||
wrefresh(win[i]);
|
||||
}
|
||||
bar_mark(win[4]);
|
||||
bar_mark(tel.power.lwin);
|
||||
|
||||
int speed = 0, power = 0, bat = 0, rpm = 0;
|
||||
float tq = 0.0f, eff = 0.0f, bat_temp = 0.0f, var_temp = 0.0f, mot_temp = 0.0f;
|
||||
int lspeed = 0, hspeed = 200, lpower = 0, hpower = 1250, lbat = 0, hbat = 100, lrpm = 0, hrpm = 6000;
|
||||
float ltq = 1.8f, htq = 3.5f, leff = 0.0f, heff = 300.0f, lbat_temp = 0.0f, hbat_temp = 150.0f, lvar_temp = 0.0f, hvar_temp = 150.0f, lmot_temp = 0.0f, hmot_temp = 150.0f;
|
||||
long t100 = 0, t1000 = 0;
|
||||
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' :
|
||||
@@ -316,40 +712,44 @@ int main(int argc, char **argv) {
|
||||
case ERR :
|
||||
default :
|
||||
if (fake_data) {
|
||||
get_fake_data(&speed, lspeed, hspeed, &power, lpower, hpower, &bat, lbat, hbat, &tq, ltq, htq, &rpm, lrpm, hrpm, &eff, leff, heff, &bat_temp, lbat_temp, hbat_temp, &var_temp, lvar_temp, hvar_temp, &mot_temp, lmot_temp, hmot_temp);
|
||||
get_fake_data(&tel);
|
||||
} else {
|
||||
//real_data()
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
long now = now_ms();
|
||||
if (!is_receiver) calc_data(&tel, &bat_state, now);
|
||||
|
||||
if (now - t100 >= 100 * delay) {
|
||||
win_int(win[0], speed, 3, use_color, color_high(speed, lspeed, hspeed));
|
||||
win_int(win[1], rpm, 4, use_color, color_high(rpm, lrpm, hrpm));
|
||||
win_float(win[3], tq, 3, use_color, color_high(tq, ltq, htq));
|
||||
win_bar(win[4], power, hpower, use_color);
|
||||
win_float(win[5], eff, 5, use_color, color_high(eff, leff, heff));
|
||||
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;
|
||||
}
|
||||
if (now - t1000 >= 1000 * delay) {
|
||||
win_int(win[2], bat, 3, use_color, color_low(bat, lbat, hbat));
|
||||
win_float(win[6], bat_temp, 5, use_color, color_high(bat_temp, lbat_temp, hbat_temp));
|
||||
win_float(win[7], var_temp, 5, use_color, color_high(var_temp, lvar_temp, hvar_temp));
|
||||
win_float(win[8], mot_temp, 5, use_color, color_high(mot_temp, lmot_temp, hmot_temp));
|
||||
t1000 = now;
|
||||
}
|
||||
//win[9];
|
||||
napms(10);
|
||||
};
|
||||
|
||||
end:
|
||||
for (int i = 0; i < 10; i++) {
|
||||
delwin(win[i]);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user