#include #include #include #include #include #include #include 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; WINDOW *lwin; } StInt; typedef struct{ float data; float ldata; float hdata; int digits; WINDOW *lwin; } StFlt; typedef struct{ WINDOW *lwin; } StStr; typedef struct { StInt speed; StInt rpm; StFlt tq; StInt power; StFlt eff; StInt bat; StFlt bat_temp; StFlt var_temp; StFlt mot_temp; StStr message; } Tel; void get_fake_data(Tel *t) { t->speed.data = t->speed.ldata + rand() % (t->speed.hdata - t->speed.ldata + 1); t->power.data = t->power.ldata + rand() % (t->power.hdata - t->power.ldata + 1); t->bat.data = t->bat.ldata + rand() % (t->bat.hdata - t->bat.ldata + 1); t->tq.data = t->tq.ldata + ((float)rand() / (float)RAND_MAX) * (float)(t->tq.hdata - t->tq.ldata); t->rpm.data = t->rpm.ldata + rand() % (t->rpm.hdata - t->rpm.ldata + 1); t->eff.data = t->eff.ldata + ((float)rand() / (float)RAND_MAX) * (float)(t->eff.hdata - t->eff.ldata); t->bat_temp.data = t->bat_temp.ldata + ((float)rand() / (float)RAND_MAX) * (float)(t->bat_temp.hdata - t->bat_temp.ldata); t->var_temp.data = t->var_temp.ldata + ((float)rand() / (float)RAND_MAX) * (float)(t->var_temp.hdata - t->var_temp.ldata); t->mot_temp.data = t->mot_temp.ldata + ((float)rand() / (float)RAND_MAX) * (float)(t->mot_temp.hdata - t->mot_temp.ldata); } 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; } 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); } 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 digits) { 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); } } if (use_color) { wattroff(lwin, COLOR_PAIR(3)); wattroff(lwin, COLOR_PAIR(2)); wattroff(lwin, COLOR_PAIR(1)); } if (use_color) { wattroff(lwin, COLOR_PAIR(0)); } char buf[16]; int len; 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) / 3; int starty = (lwiny - bh * size) / 2; int offset = (bw * size + 1) * (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(lwin, starty + y * size + yy, dx + x * size + xx, ACS_CKBOARD); } } } } wrefresh(lwin); if (use_color) { wattroff(lwin, COLOR_PAIR(0)); } } 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, '|'); } 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; } 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; } int main(int argc, char **argv) { int option; int delay = 1; int fake_data = 0; while ((option = getopt(argc, argv, "d:hf")) !=-1) { switch (option) { case 'd' : delay = atoi(optarg); if (delay < 0) { delay = 0; } break; case 'f' : fake_data = 1; break; case 'h' : printf("Usage: ./dashboard [-d int DELAY by how much to slow down] [-h HELP] [-f generate fake data]\n"); return(0); } } initscr(); noecho(); cbreak(); curs_set(0); nodelay(stdscr, TRUE); refresh(); int y,x; getmaxyx(stdscr, y, x); if (y < 42 || x < 100) { endwin(); perror("terminal window too small"); return 1; } int 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); } WINDOW *win[10]; Tel tel; tel.speed = (StInt){0, 0, 200, 3, NULL}; tel.rpm = (StInt){0, 0, 6000, 4, NULL}; tel.tq = (StFlt){0.0f, 1.8f, 3.5f, 3, NULL}; tel.power = (StInt){0, 0, 1300, 4, NULL}; tel.eff = (StFlt){0.0f, 0.0f, 300.0f, 5, NULL}; tel.bat = (StInt){0, 0, 100, 3, NULL}; tel.bat_temp = (StFlt){0.0f, 0.0f, 150.0f, 5, NULL}; tel.var_temp = (StFlt){0.0f, 0.0f, 150.0f, 5, NULL}; tel.mot_temp = (StFlt){0.0f, 0.0f, 150.0f, 5, NULL}; tel.message = (StStr){NULL}; int x3 = x / 3; int x3r = x - 2 * x3; int y2 = y / 2; int y2r = y - y2; int y4 = y2 / 2; int y4r = y2 - y4; int y6 = y2r / 3; int y6r = y2r - 2 * y6; typedef struct { int height, width, starty, startx; char *title; } WinInfo; 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 }; 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]); } tel.speed.lwin = win[0]; tel.rpm.lwin = win[1]; tel.tq.lwin = win[3]; tel.power.lwin = win[4]; tel.eff.lwin = win[5]; tel.bat.lwin = win[2]; tel.bat_temp.lwin = win[6]; tel.var_temp.lwin = win[7]; tel.mot_temp.lwin = win[8]; tel.message.lwin = win[9]; bar_mark(tel.power.lwin); long t100 = 0, t1000 = 0; int ch = ERR; while(1) { ch = tolower(getch()); switch (ch) { case 'q' : goto end; case ERR : default : if (fake_data) { get_fake_data(&tel); } else { //real_data() } break; } long now = now_ms(); if (now - t100 >= 100 * delay) { win_int(tel.speed.lwin, tel.speed.data, 3, use_color, color_high(tel.speed.data, tel.speed.ldata, tel.speed.hdata)); win_int(tel.rpm.lwin, tel.rpm.data, 4, use_color, color_high(tel.rpm.data, tel.rpm.ldata, tel.rpm.hdata)); win_float(tel.tq.lwin, tel.tq.data, 3, use_color, color_high(tel.tq.data, tel.tq.ldata, tel.tq.hdata)); win_bar(tel.power.lwin, tel.power.data, tel.power.hdata, use_color, tel.power.digits); win_float(tel.eff.lwin, tel.eff.data, 5, use_color, color_high(tel.eff.data, tel.eff.ldata, tel.eff.hdata)); t100 = now; } if (now - t1000 >= 1000 * delay) { win_int(tel.bat.lwin, tel.bat.data, 3, use_color, color_low(tel.bat.data, tel.bat.ldata, tel.bat.hdata)); win_float(tel.bat_temp.lwin, tel.bat_temp.data, 5, use_color, color_high(tel.bat_temp.data, tel.bat_temp.ldata, tel.bat_temp.hdata)); win_float(tel.var_temp.lwin, tel.var_temp.data, 5, use_color, color_high(tel.var_temp.data, tel.var_temp.ldata, tel.var_temp.hdata)); win_float(tel.mot_temp.lwin, tel.mot_temp.data, 5, use_color, color_high(tel.mot_temp.data, tel.mot_temp.ldata, tel.mot_temp.hdata)); t1000 = now; } //win[9]; napms(10); }; end: for (int i = 0; i < 10; i++) { delwin(win[i]); } endwin(); return 0; }