Armchair functions as before (all tasks enabled). Note: probably wrong encoder pin set in encoder.hpp Old button menu works as usual (opimized code). You can switch to new MENU state with 1x long press and exit the menu with 1x long press button.cpp: - use encoder queue instead of evaluated switch - simplify code, rework actions control.cpp: Add MENU state/mode -> control task: turns motors off and idles -> button task idles (button menu disabled) -> display task switches state to handle menu control.cpp: Optimize structure: Add methods to freeze stick and toggle stick mapping display.cpp: show status screen or handle menu depending on mode, simpilfy task main.cpp: re-enable button task, disable buzzer logging menu.cpp: Change events, Add menu exit condition
335 lines
11 KiB
C++
335 lines
11 KiB
C++
#include "display.hpp"
|
|
extern "C"{
|
|
#include <driver/adc.h>
|
|
#include "esp_ota_ops.h"
|
|
}
|
|
|
|
#include "menu.hpp"
|
|
|
|
|
|
|
|
//==== display config ====
|
|
#define I2C_INTERFACE y
|
|
#define SCL_GPIO 22
|
|
#define SDA_GPIO 23
|
|
#define RESET_GPIO 15 // FIXME remove this
|
|
// the following options are set in menuconfig: (see sdkconfig)
|
|
// #define CONFIG_OFFSETX 2 //note: the larger display (actual 130x64) needs 2 pixel offset (prevents bugged column)
|
|
// #define CONFIG_I2C_PORT_0 y
|
|
|
|
//=== content config ===
|
|
#define STARTUP_MSG_TIMEOUT 2000
|
|
#define ADC_BATT_VOLTAGE ADC1_CHANNEL_6
|
|
#define BAT_CELL_COUNT 7
|
|
|
|
|
|
|
|
//--------------------------
|
|
//------- getVoltage -------
|
|
//--------------------------
|
|
//TODO duplicate code: getVoltage also defined in currentsensor.cpp -> outsource this
|
|
//local function to get average voltage from adc
|
|
float getVoltage1(adc1_channel_t adc, uint32_t samples){
|
|
//measure voltage
|
|
int measure = 0;
|
|
for (int j=0; j<samples; j++){
|
|
measure += adc1_get_raw(adc);
|
|
ets_delay_us(50);
|
|
}
|
|
return (float)measure / samples / 4096 * 3.3;
|
|
}
|
|
|
|
|
|
|
|
//======================
|
|
//===== variables ======
|
|
//======================
|
|
//display
|
|
SSD1306_t dev;
|
|
//tag for logging
|
|
static const char * TAG = "display";
|
|
|
|
|
|
|
|
//======================
|
|
//==== display_init ====
|
|
//======================
|
|
//note CONFIG_OFFSETX is used (from menuconfig)
|
|
void display_init(){
|
|
adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11); //max voltage
|
|
ESP_LOGW("display", "INTERFACE is i2c");
|
|
ESP_LOGW("display", "SDA_GPIO=%d",SDA_GPIO);
|
|
ESP_LOGW("display", "SCL_GPIO=%d",SCL_GPIO);
|
|
ESP_LOGW("display", "RESET_GPIO=%d",RESET_GPIO);
|
|
i2c_master_init(&dev, SDA_GPIO, SCL_GPIO, RESET_GPIO);
|
|
#if FLIP
|
|
dev._flip = true;
|
|
ESP_LOGW("display", "Flip upside down");
|
|
#endif
|
|
ESP_LOGI("display", "Panel is 128x64");
|
|
ssd1306_init(&dev, 128, 64);
|
|
|
|
ssd1306_clear_screen(&dev, false);
|
|
ssd1306_contrast(&dev, 0xff);
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------
|
|
//------- getBatteryVoltage --------
|
|
//----------------------------------
|
|
float getBatteryVoltage(){
|
|
#define BAT_VOLTAGE_CONVERSION_FACTOR 11.9
|
|
float voltageRead = getVoltage1(ADC_BATT_VOLTAGE, 1000);
|
|
float battVoltage = voltageRead * 11.9; //note: factor comes from simple test with voltmeter
|
|
ESP_LOGD(TAG, "batteryVoltage - voltageAdc=%f, voltageConv=%f, factor=%.2f", voltageRead, battVoltage, BAT_VOLTAGE_CONVERSION_FACTOR);
|
|
return battVoltage;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------
|
|
//------- getBatteryPercent --------
|
|
//----------------------------------
|
|
//TODO find better/more accurate table?
|
|
//configure discharge curve of one cell with corresponding known voltage->chargePercent values
|
|
const float voltageLevels[] = {3.00, 3.45, 3.68, 3.74, 3.77, 3.79, 3.82, 3.87, 3.92, 3.98, 4.06, 4.20};
|
|
const float percentageLevels[] = {0.0, 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0};
|
|
|
|
float getBatteryPercent(){
|
|
float voltage = getBatteryVoltage();
|
|
float cellVoltage = voltage/BAT_CELL_COUNT;
|
|
int size = sizeof(voltageLevels) / sizeof(voltageLevels[0]);
|
|
int sizePer = sizeof(percentageLevels) / sizeof(percentageLevels[0]);
|
|
//check if configured correctly
|
|
if (size != sizePer) {
|
|
ESP_LOGE(TAG, "getBatteryPercent - count of configured percentages do not match count of voltages");
|
|
return 0;
|
|
}
|
|
if (cellVoltage <= voltageLevels[0]) {
|
|
return 0.0;
|
|
} else if (cellVoltage >= voltageLevels[size - 1]) {
|
|
return 100.0;
|
|
}
|
|
|
|
//scale voltage linear to percent in matched range
|
|
for (int i = 1; i < size; ++i) {
|
|
if (cellVoltage <= voltageLevels[i]) {
|
|
float voltageRange = voltageLevels[i] - voltageLevels[i - 1];
|
|
float voltageOffset = cellVoltage - voltageLevels[i - 1];
|
|
float percentageRange = percentageLevels[i] - percentageLevels[i - 1];
|
|
float percentageOffset = percentageLevels[i - 1];
|
|
float percent = percentageOffset + (voltageOffset / voltageRange) * percentageRange;
|
|
ESP_LOGD(TAG, "getBatPercent - cellVoltage=%.3f => percentage=%.3f", cellVoltage, percent);
|
|
ESP_LOGD(TAG, "getBatPercent - matched range: %.2fV-%.2fV => %.1f%%-%.1f%%", voltageLevels[i-1], voltageLevels[i], percentageLevels[i-1], percentageLevels[i]);
|
|
return percent;
|
|
}
|
|
}
|
|
ESP_LOGE(TAG, "getBatteryPercent - unknown voltage range");
|
|
return 0.0; //unknown range
|
|
}
|
|
|
|
|
|
|
|
//-----------------------
|
|
//----- showScreen1 -----
|
|
//-----------------------
|
|
//shows overview on entire display:
|
|
//percentage, voltage, current, mode, rpm, speed
|
|
void showScreen1()
|
|
{
|
|
char buf[20];
|
|
char buf1[20];
|
|
int len, len1;
|
|
|
|
//-- battery percentage --
|
|
// TODO update when no load (currentsensors = ~0A) only
|
|
len1 = snprintf(buf1, sizeof(buf1), "B:%02.0f%%", getBatteryPercent());
|
|
ssd1306_display_text_x3(&dev, 0, buf1, len1, false);
|
|
|
|
//-- voltage and current --
|
|
len = snprintf(buf, sizeof(buf), "%04.1fV %04.1f:%04.1fA",
|
|
getBatteryVoltage(),
|
|
fabs(motorLeft.getCurrentA()),
|
|
fabs(motorRight.getCurrentA()));
|
|
ssd1306_display_text(&dev, 3, buf, len, false);
|
|
|
|
//-- control state --
|
|
len = snprintf(buf, sizeof(buf), "%s ", control.getCurrentModeStr());
|
|
ssd1306_display_text_x3(&dev, 4, buf, len, false);
|
|
|
|
//-- speed and RPM --
|
|
len = snprintf(buf, sizeof(buf), "%3.1fkm/h %03.0f:%03.0fR",
|
|
fabs((speedLeft.getKmph() + speedRight.getKmph()) / 2),
|
|
speedLeft.getRpm(),
|
|
speedRight.getRpm());
|
|
ssd1306_display_text(&dev, 7, buf, len, false);
|
|
|
|
// debug speed sensors
|
|
ESP_LOGD(TAG, "%s", buf);
|
|
}
|
|
|
|
|
|
|
|
//------------------------
|
|
//---- showStartupMsg ----
|
|
//------------------------
|
|
//shows welcome message and information about current version
|
|
void showStartupMsg(){
|
|
char buf[20];
|
|
int len;
|
|
const esp_app_desc_t * desc = esp_ota_get_app_description();
|
|
|
|
//show message
|
|
len = snprintf(buf, 20, "START");
|
|
ssd1306_display_text_x3(&dev, 0, buf, len, false);
|
|
//show git-tag
|
|
len = snprintf(buf, 20, "%s", desc->version);
|
|
ssd1306_display_text(&dev, 4, buf, len, false);
|
|
//show build-date (note: date,time of last clean build)
|
|
len = snprintf(buf, 20, "%s", desc->date);
|
|
ssd1306_display_text(&dev, 6, buf, len, false);
|
|
//show build-time
|
|
len = snprintf(buf, 20, "%s", desc->time);
|
|
ssd1306_display_text(&dev, 7, buf, len, false);
|
|
}
|
|
|
|
|
|
|
|
|
|
//============================
|
|
//======= display task =======
|
|
//============================
|
|
#define STATUS_SCREEN_UPDATE_INTERVAL 500
|
|
// TODO: separate task for each loop?
|
|
|
|
void display_task(void *pvParameters)
|
|
{
|
|
// initialize display
|
|
display_init();
|
|
// TODO check if successfully initialized
|
|
|
|
// show startup message
|
|
showStartupMsg();
|
|
vTaskDelay(STARTUP_MSG_TIMEOUT / portTICK_PERIOD_MS);
|
|
|
|
// repeatedly update display with content
|
|
while (1)
|
|
{
|
|
if (control.getCurrentMode() == controlMode_t::MENU)
|
|
{
|
|
//uses encoder events to control menu and updates display
|
|
handleMenu(&dev);
|
|
}
|
|
else //show status screen in any other mode
|
|
{
|
|
showScreen1();
|
|
vTaskDelay(STATUS_SCREEN_UPDATE_INTERVAL / portTICK_PERIOD_MS);
|
|
}
|
|
// TODO add pages and menus
|
|
}
|
|
}
|
|
|
|
//-----------------------------------
|
|
//---- text-related example code ----
|
|
//-----------------------------------
|
|
//ssd1306_display_text(&dev, 0, "SSD1306 128x64", 14, false);
|
|
//ssd1306_display_text(&dev, 1, "ABCDEFGHIJKLMNOP", 16, false);
|
|
//ssd1306_display_text(&dev, 2, "abcdefghijklmnop",16, false);
|
|
//ssd1306_display_text(&dev, 3, "Hello World!!", 13, false);
|
|
////ssd1306_clear_line(&dev, 4, true);
|
|
////ssd1306_clear_line(&dev, 5, true);
|
|
////ssd1306_clear_line(&dev, 6, true);
|
|
////ssd1306_clear_line(&dev, 7, true);
|
|
//ssd1306_display_text(&dev, 4, "SSD1306 128x64", 14, true);
|
|
//ssd1306_display_text(&dev, 5, "ABCDEFGHIJKLMNOP", 16, true);
|
|
//ssd1306_display_text(&dev, 6, "abcdefghijklmnop",16, true);
|
|
//ssd1306_display_text(&dev, 7, "Hello World!!", 13, true);
|
|
//
|
|
//// Display Count Down
|
|
//uint8_t image[24];
|
|
//memset(image, 0, sizeof(image));
|
|
//ssd1306_display_image(&dev, top, (6*8-1), image, sizeof(image));
|
|
//ssd1306_display_image(&dev, top+1, (6*8-1), image, sizeof(image));
|
|
//ssd1306_display_image(&dev, top+2, (6*8-1), image, sizeof(image));
|
|
//for(int font=0x39;font>0x30;font--) {
|
|
// memset(image, 0, sizeof(image));
|
|
// ssd1306_display_image(&dev, top+1, (7*8-1), image, 8);
|
|
// memcpy(image, font8x8_basic_tr[font], 8);
|
|
// if (dev._flip) ssd1306_flip(image, 8);
|
|
// ssd1306_display_image(&dev, top+1, (7*8-1), image, 8);
|
|
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
//}
|
|
//
|
|
//// Scroll Up
|
|
//ssd1306_clear_screen(&dev, false);
|
|
//ssd1306_contrast(&dev, 0xff);
|
|
//ssd1306_display_text(&dev, 0, "---Scroll UP---", 16, true);
|
|
////ssd1306_software_scroll(&dev, 7, 1);
|
|
//ssd1306_software_scroll(&dev, (dev._pages - 1), 1);
|
|
//for (int line=0;line<bottom+10;line++) {
|
|
// lineChar[0] = 0x01;
|
|
// sprintf(&lineChar[1], " Line %02d", line);
|
|
// ssd1306_scroll_text(&dev, lineChar, strlen(lineChar), false);
|
|
// vTaskDelay(500 / portTICK_PERIOD_MS);
|
|
//}
|
|
//vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
//
|
|
//// Scroll Down
|
|
//ssd1306_clear_screen(&dev, false);
|
|
//ssd1306_contrast(&dev, 0xff);
|
|
//ssd1306_display_text(&dev, 0, "--Scroll DOWN--", 16, true);
|
|
////ssd1306_software_scroll(&dev, 1, 7);
|
|
//ssd1306_software_scroll(&dev, 1, (dev._pages - 1) );
|
|
//for (int line=0;line<bottom+10;line++) {
|
|
// lineChar[0] = 0x02;
|
|
// sprintf(&lineChar[1], " Line %02d", line);
|
|
// ssd1306_scroll_text(&dev, lineChar, strlen(lineChar), false);
|
|
// vTaskDelay(500 / portTICK_PERIOD_MS);
|
|
//}
|
|
//vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
|
|
//// Page Down
|
|
//ssd1306_clear_screen(&dev, false);
|
|
//ssd1306_contrast(&dev, 0xff);
|
|
//ssd1306_display_text(&dev, 0, "---Page DOWN---", 16, true);
|
|
//ssd1306_software_scroll(&dev, 1, (dev._pages-1) );
|
|
//for (int line=0;line<bottom+10;line++) {
|
|
// //if ( (line % 7) == 0) ssd1306_scroll_clear(&dev);
|
|
// if ( (line % (dev._pages-1)) == 0) ssd1306_scroll_clear(&dev);
|
|
// lineChar[0] = 0x02;
|
|
// sprintf(&lineChar[1], " Line %02d", line);
|
|
// ssd1306_scroll_text(&dev, lineChar, strlen(lineChar), false);
|
|
// vTaskDelay(500 / portTICK_PERIOD_MS);
|
|
//}
|
|
//vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
|
|
//// Horizontal Scroll
|
|
//ssd1306_clear_screen(&dev, false);
|
|
//ssd1306_contrast(&dev, 0xff);
|
|
//ssd1306_display_text(&dev, center, "Horizontal", 10, false);
|
|
//ssd1306_hardware_scroll(&dev, SCROLL_RIGHT);
|
|
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
//ssd1306_hardware_scroll(&dev, SCROLL_LEFT);
|
|
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
//ssd1306_hardware_scroll(&dev, SCROLL_STOP);
|
|
//
|
|
//// Vertical Scroll
|
|
//ssd1306_clear_screen(&dev, false);
|
|
//ssd1306_contrast(&dev, 0xff);
|
|
//ssd1306_display_text(&dev, center, "Vertical", 8, false);
|
|
//ssd1306_hardware_scroll(&dev, SCROLL_DOWN);
|
|
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
//ssd1306_hardware_scroll(&dev, SCROLL_UP);
|
|
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
//ssd1306_hardware_scroll(&dev, SCROLL_STOP);
|
|
//
|
|
//// Invert
|
|
//ssd1306_clear_screen(&dev, true);
|
|
//ssd1306_contrast(&dev, 0xff);
|
|
//ssd1306_display_text(&dev, center, " Good Bye!!", 12, true);
|
|
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
|
|
|
|
//// Fade Out
|
|
//ssd1306_fadeout(&dev);
|