pax curve plotter (experimental)

This commit is contained in:
Verkehrsrot 2019-10-01 13:02:30 +02:00
parent e38a91162b
commit 66af2b8c54
3 changed files with 163 additions and 60 deletions

View File

@ -150,7 +150,13 @@ Paxcounter generates identifiers for sniffed MAC adresses and collects them temp
# Display # Display
If you're using a device with OLED display, or if you add such one to the I2C bus, the device shows live data on the display. You can flip between pages showing pax, time, GPS and BME sensor data by pressing the button of the device. If you're using a device with OLED display, or if you add such one to the I2C bus, the device shows live data on the display. You can flip display pages showing
- recent count of pax
- histogram
- GPS data
- BME sensor data
- Time of day
by pressing the button of the device.
# Sensors and Peripherals # Sensors and Peripherals

View File

@ -7,10 +7,17 @@
extern uint8_t DisplayIsOn; extern uint8_t DisplayIsOn;
void refreshTheDisplay(bool nextPage = false); void refreshTheDisplay(bool nextPage = false);
void init_display(void); void init_display(uint8_t verbose = 0);
void draw_page(time_t t, uint8_t page); void draw_page(time_t t, uint8_t page);
void dp_printf(int x, int y, int font, int inv, const char *format, ...); void dp_printf(uint16_t x, uint16_t y, uint8_t font, uint8_t inv,
void dp_printqr(int offset_x, int offset_y, const char *Message); const char *format, ...);
void oledfillRect(int x, int y, int width, int height, int bRender); void dp_printqr(uint16_t offset_x, uint16_t offset_y, const char *Message);
void oledfillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height,
uint8_t bRender);
void oledScrollBufferLeft(uint8_t *buf, const uint16_t width,
const uint16_t height);
int oledDrawPixel(uint8_t *buf, const uint16_t x, const uint16_t y,
const uint8_t dot);
void oledPlotCurve(uint16_t count);
#endif #endif

View File

@ -37,23 +37,29 @@ FONT_STRETCHED: 16x32px = 8 chars / line
// local Tag for logging // local Tag for logging
static const char TAG[] = __FILE__; static const char TAG[] = __FILE__;
#define DISPLAY_PAGES (5) // number of paxcounter display pages
// settings for oled display library // settings for oled display library
#define DISPLAY_PAGES (4) // number of display pages #define USE_BACKBUFFER
#define USE_BACKBUFFER // for display library
// settings for qr code generator // settings for qr code generator
#define QR_VERSION 3 // 29 x 29px #define QR_VERSION 3 // 29 x 29px
#define QR_SCALEFACTOR 2 // 29 -> 58x < 64px #define QR_SCALEFACTOR 2 // 29 -> 58x < 64px
// helper arry for converting month values to text // settings for curve plotter
#define PLOT_SCALEFACTOR 1 // downscales pax numbers to display rows
#define DISPLAY_WIDTH 128 // Width in pixels of OLED-display, must be 32X
#define DISPLAY_HEIGHT 64 // Height in pixels of OLED-display, must be 16X
// helper array for converting month values to text
const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun", const char *printmonth[] = {"xxx", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
uint8_t DisplayIsOn = 0; uint8_t DisplayIsOn = 0;
uint8_t displaybuf[DISPLAY_WIDTH * DISPLAY_HEIGHT / 8] = {0};
QRCode qrcode; QRCode qrcode;
void init_display(void) { void init_display(uint8_t verbose) {
// block i2c bus access // block i2c bus access
if (!I2C_MUTEX_LOCK()) if (!I2C_MUTEX_LOCK())
@ -71,6 +77,8 @@ void init_display(void) {
oledSetContrast(DISPLAYCONTRAST); oledSetContrast(DISPLAYCONTRAST);
oledFill(0, 1); oledFill(0, 1);
if (verbose) {
// show startup screen // show startup screen
// to come -> display .bmp file with logo // to come -> display .bmp file with logo
@ -87,7 +95,8 @@ void init_display(void) {
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : ""); (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
dp_printf(0, 6, 0, 0, "%dMB %s Flash", dp_printf(0, 6, 0, 0, "%dMB %s Flash",
spi_flash_get_chip_size() / (1024 * 1024), spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext."); (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int."
: "ext.");
// give user some time to read or take picture // give user some time to read or take picture
oledDumpBuffer(NULL); oledDumpBuffer(NULL);
@ -121,6 +130,8 @@ void init_display(void) {
oledFill(0x00, 1); oledFill(0x00, 1);
#endif // HAS_LORA #endif // HAS_LORA
} // verbose
oledPower(cfg.screenon); // set display off if disabled oledPower(cfg.screenon); // set display off if disabled
I2C_MUTEX_UNLOCK(); // release i2c bus access I2C_MUTEX_UNLOCK(); // release i2c bus access
@ -171,15 +182,20 @@ void draw_page(time_t t, uint8_t page) {
// line 1/2: pax counter // line 1/2: pax counter
dp_printf(0, 0, FONT_STRETCHED, 0, "PAX:%-4d", dp_printf(0, 0, FONT_STRETCHED, 0, "PAX:%-4d",
(int)macs.size()); // display number of unique macs total Wifi + BLE macs.size()); // display number of unique macs total Wifi + BLE
// update histogram if we have a display
oledPlotCurve(macs.size());
switch (page % DISPLAY_PAGES) { switch (page % DISPLAY_PAGES) {
// page 0: parameters overview // page 0: parameters overview
// page 1: time // page 1: pax graph
// page 2: GPS // page 2: GPS
// page 3: BME280/680 // page 3: BME280/680
// page 4: time
// page 0: parameters overview
case 0: case 0:
// line 3: wifi + bluetooth counters // line 3: wifi + bluetooth counters
@ -194,7 +210,9 @@ void draw_page(time_t t, uint8_t page) {
// line 4: Battery + GPS status + Wifi channel // line 4: Battery + GPS status + Wifi channel
#if (defined BAT_MEASURE_ADC || defined HAS_PMU) #if (defined BAT_MEASURE_ADC || defined HAS_PMU)
if (batt_voltage == 0xffff) if (batt_voltage == 0xffff)
dp_printf(0, 4, FONT_SMALL, 0, "%s", "B:USB "); dp_printf(0, 4, FONT_SMALL, 0, "%s", "USB ");
else if (batt_voltage == 0)
dp_printf(0, 4, FONT_SMALL, 0, "%s", "No batt");
else else
dp_printf(0, 4, FONT_SMALL, 0, "B:%.2fV", batt_voltage / 1000.0); dp_printf(0, 4, FONT_SMALL, 0, "B:%.2fV", batt_voltage / 1000.0);
#endif #endif
@ -249,11 +267,12 @@ void draw_page(time_t t, uint8_t page) {
break; // page0 break; // page0
// page 1: pax graph
case 1: case 1:
dp_printf(0, 4, FONT_LARGE, 0, "%02d:%02d:%02d", hour(t), minute(t), oledDumpBuffer(displaybuf);
second(t));
break; // page1 break; // page1
// page 2: GPS
case 2: case 2:
#if (HAS_GPS) #if (HAS_GPS)
if (gps.location.age() < 1500) { if (gps.location.age() < 1500) {
@ -281,6 +300,7 @@ void draw_page(time_t t, uint8_t page) {
break; // page2 break; // page2
// page 3: BME280/680
case 3: case 3:
#if (HAS_BME) #if (HAS_BME)
@ -301,6 +321,13 @@ void draw_page(time_t t, uint8_t page) {
break; // page3 break; // page3
// page 4: time
case 4:
dp_printf(0, 4, FONT_LARGE, 0, "%02d:%02d:%02d", hour(t), minute(t),
second(t));
break;
default: default:
break; // default break; // default
@ -308,8 +335,9 @@ void draw_page(time_t t, uint8_t page) {
} // draw_page } // draw_page
// display print helper functions // display helper functions
void dp_printf(int x, int y, int font, int inv, const char *format, ...) { void dp_printf(uint16_t x, uint16_t y, uint8_t font, uint8_t inv,
const char *format, ...) {
char loc_buf[64]; char loc_buf[64];
char *temp = loc_buf; char *temp = loc_buf;
va_list arg; va_list arg;
@ -337,13 +365,13 @@ void dp_printf(int x, int y, int font, int inv, const char *format, ...) {
} }
} }
void dp_printqr(int offset_x, int offset_y, const char *Message) { void dp_printqr(uint16_t offset_x, uint16_t offset_y, const char *Message) {
uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)]; uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)];
qrcode_initText(&qrcode, qrcodeData, QR_VERSION, ECC_HIGH, Message); qrcode_initText(&qrcode, qrcodeData, QR_VERSION, ECC_HIGH, Message);
// draw QR code // draw QR code
for (int y = 0; y < qrcode.size; y++) for (uint16_t y = 0; y < qrcode.size; y++)
for (int x = 0; x < qrcode.size; x++) for (uint16_t x = 0; x < qrcode.size; x++)
if (!qrcode_getModule(&qrcode, x, y)) // "black" if (!qrcode_getModule(&qrcode, x, y)) // "black"
oledfillRect(x * QR_SCALEFACTOR + offset_x, oledfillRect(x * QR_SCALEFACTOR + offset_x,
y * QR_SCALEFACTOR + offset_y, QR_SCALEFACTOR, y * QR_SCALEFACTOR + offset_y, QR_SCALEFACTOR,
@ -360,9 +388,71 @@ void dp_printqr(int offset_x, int offset_y, const char *Message) {
qrcode.size * QR_SCALEFACTOR + 2 * offset_y, false); qrcode.size * QR_SCALEFACTOR + 2 * offset_y, false);
} }
void oledfillRect(int x, int y, int width, int height, int bRender) { void oledfillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height,
for (int xi = x; xi < x + width; xi++) uint8_t bRender) {
for (uint16_t xi = x; xi < x + width; xi++)
oledDrawLine(xi, y, xi, y + height - 1, bRender); oledDrawLine(xi, y, xi, y + height - 1, bRender);
} }
int oledDrawPixel(uint8_t *buf, const uint16_t x, const uint16_t y,
const uint8_t dot) {
uint8_t page, bit;
if (x > DISPLAY_WIDTH || y > DISPLAY_HEIGHT)
return -1;
page = y / 8;
bit = y % 8;
if (dot)
buf[page * DISPLAY_WIDTH + x] |= (1 << bit); // mark
else
buf[page * DISPLAY_WIDTH + x] &= ~(0 << bit); // clear
return 0;
}
void oledScrollBufferLeft(uint8_t *buf, const uint16_t width,
const uint16_t height) {
uint16_t col, page, idx;
for (page = 0; page < height / 8; page++) {
for (col = 0; col < width - 1; col++) {
idx = page * width + col;
buf[idx] = buf[idx + 1];
}
buf[idx + 1] = 0;
}
}
void oledPlotCurve(uint16_t count) {
uint8_t level;
static uint16_t last_count = 0, col = 0, row = 0;
if (last_count == count)
return;
// next count cycle?
if (count == 0) {
// matrix full? then scroll left 1 dot, else increment column
if (col < DISPLAY_WIDTH - 1)
col++;
else
oledScrollBufferLeft(displaybuf, DISPLAY_WIDTH, DISPLAY_HEIGHT);
} else
oledDrawPixel(displaybuf, col, row, 0); // clear current dot
// scale and set new dot
last_count = count;
level = count / PLOT_SCALEFACTOR;
row =
level <= DISPLAY_HEIGHT ? DISPLAY_HEIGHT - 1 - level % DISPLAY_HEIGHT : 0;
oledDrawPixel(displaybuf, col, row, 1);
}
#endif // HAS_DISPLAY #endif // HAS_DISPLAY