From c898ca463466d24f33daa0e96f980c2ccc5ace10 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Sun, 21 Sep 2014 05:09:01 +0100 Subject: [PATCH] OLED Display - Add two pages: RX info and Welcome. The RX info page shows channel letters and bar graphs for the first 8 channels. The Welcome page shows the target and cleanflight git revision. --- Makefile | 1 + src/main/io/display.c | 141 +++++++++++++++++++++++++++++++++------ src/main/io/display.h | 3 + src/main/io/serial_cli.c | 3 +- src/main/main.c | 11 ++- src/main/version.c | 19 ++++++ src/main/version.h | 2 + 7 files changed, 155 insertions(+), 25 deletions(-) create mode 100644 src/main/version.c diff --git a/Makefile b/Makefile index b195a244e..2407a58ef 100644 --- a/Makefile +++ b/Makefile @@ -146,6 +146,7 @@ INCLUDE_DIRS := $(INCLUDE_DIRS) \ VPATH := $(VPATH):$(TARGET_DIR) COMMON_SRC = build_config.c \ + version.c \ $(TARGET_SRC) \ config/config.c \ config/runtime_config.c \ diff --git a/src/main/io/display.c b/src/main/io/display.c index ee7c1fbef..b51a3bd60 100644 --- a/src/main/io/display.c +++ b/src/main/io/display.c @@ -21,11 +21,13 @@ #include #include "platform.h" +#include "version.h" #include "build_config.h" #include "drivers/serial.h" #include "common/printf.h" +#include "common/maths.h" #ifdef DISPLAY @@ -39,6 +41,8 @@ #include "sensors/sensors.h" #include "sensors/compass.h" +#include "rx/rx.h" + #include "config/runtime_config.h" #include "display.h" @@ -48,28 +52,34 @@ #define DISPLAY_UPDATE_FREQUENCY (MILLISECONDS_IN_A_SECOND / 10) #define PAGE_CYCLE_FREQUENCY (MILLISECONDS_IN_A_SECOND * 5) -uint32_t nextDisplayUpdateAt = 0; -uint32_t nextPageAt = 0; +static uint32_t nextDisplayUpdateAt = 0; -char lineBuffer[SCREEN_CHARACTER_COLUMN_COUNT]; +static rxConfig_t *rxConfig; + +static char lineBuffer[SCREEN_CHARACTER_COLUMN_COUNT]; typedef enum { + PAGE_WELCOME, PAGE_ARMED, PAGE_BATTERY, - PAGE_SENSORS + PAGE_SENSORS, + PAGE_RX, } pageId_e; const char* pageTitles[] = { + "CLEANFLIGHT", "ARMED", "BATTERY", - "SENSORS" + "SENSORS", + "RX" }; -#define PAGE_COUNT (PAGE_SENSORS + 1) +#define PAGE_COUNT (PAGE_RX + 1) const uint8_t cyclePageIds[] = { PAGE_BATTERY, - PAGE_SENSORS + PAGE_SENSORS, + PAGE_RX }; #define CYCLE_PAGE_ID_COUNT (sizeof(cyclePageIds) / sizeof(cyclePageIds[0])) @@ -77,10 +87,19 @@ const uint8_t cyclePageIds[] = { static const char* tickerCharacters = "|/-\\"; #define TICKER_CHARACTER_COUNT (sizeof(tickerCharacters) / sizeof(char)) +typedef enum { + PAGE_STATE_FLAG_NONE = 0, + PAGE_STATE_FLAG_CYCLE_ENABLED = (1 << 0), + PAGE_STATE_FLAG_FORCE_PAGE_CHANGE = (1 << 1) +} pageFlags_e; + typedef struct pageState_s { bool pageChanging; pageId_e pageId; + pageId_e pageIdBeforeArming; + uint8_t pageFlags; uint8_t cycleIndex; + uint32_t nextPageAt; } pageState_t; static pageState_t pageState; @@ -89,6 +108,14 @@ void LCDprint(uint8_t i) { i2c_OLED_send_char(i); } +void padLineBuffer(void) +{ + uint8_t length = strlen(lineBuffer); + while (length < sizeof(lineBuffer) - 1) { + lineBuffer[length++] = ' '; + } +} + // LCDbar(n,v) : draw a bar graph - n number of chars for width, v value in % to display void drawHorizonalPercentageBar(uint8_t width,uint8_t percent) { uint8_t i, j; @@ -141,15 +168,55 @@ void handlePageChange(void) showTitle(); } +void drawRxChannel(uint8_t channelIndex, uint8_t width) +{ + uint32_t percentage; + + LCDprint(rcChannelLetters[channelIndex]); + + percentage = (constrain(rcData[channelIndex], PWM_RANGE_MIN, PWM_RANGE_MAX) - PWM_RANGE_MIN) * 100 / (PWM_RANGE_MAX - PWM_RANGE_MIN); + drawHorizonalPercentageBar(width - 1, percentage); +} + +void showRxPage(void) +{ + + for (uint8_t channelIndex = 0; channelIndex < 8; channelIndex += 2) { + i2c_OLED_set_line((channelIndex / 2) + 1); + + uint8_t width = SCREEN_CHARACTER_COLUMN_COUNT / 2; + + drawRxChannel(channelIndex, width); + + if (width * 2 != SCREEN_CHARACTER_COLUMN_COUNT) { + LCDprint(' '); + } + + drawRxChannel(channelIndex + 1, width); + } +} + +void showWelcomePage(void) +{ + tfp_sprintf(lineBuffer, "Rev: %s", shortGitRevision); + i2c_OLED_set_line(1); + i2c_OLED_send_string(lineBuffer); + + tfp_sprintf(lineBuffer, "Target: %s", targetName); + i2c_OLED_set_line(2); + i2c_OLED_send_string(lineBuffer); +} + void showArmedPage(void) { } void showBatteryPage(void) { - tfp_sprintf(lineBuffer, "volts: %d.%d, cells: %d", vbat / 10, vbat % 10, batteryCellCount); + tfp_sprintf(lineBuffer, "Volts: %d.%d, Cells: %d", vbat / 10, vbat % 10, batteryCellCount); i2c_OLED_set_line(1); i2c_OLED_send_string(lineBuffer); + padLineBuffer(); uint32_t batteryPercentage = calculateBatteryPercentage(); i2c_OLED_set_line(2); @@ -161,20 +228,23 @@ void showSensorsPage(void) uint8_t rowIndex = 1; i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string( " X Y Z"); + i2c_OLED_send_string(" X Y Z"); if (sensors(SENSOR_ACC)) { - tfp_sprintf(lineBuffer, "Acc : %4d %4d %4d", accSmooth[X], accSmooth[Y], accSmooth[Z]); + tfp_sprintf(lineBuffer, "A = %5d %5d %5d", accSmooth[X], accSmooth[Y], accSmooth[Z]); + padLineBuffer(); i2c_OLED_set_line(rowIndex++); i2c_OLED_send_string(lineBuffer); } if (sensors(SENSOR_GYRO)) { - tfp_sprintf(lineBuffer, "Gryo: %4d %4d %4d", gyroADC[X], gyroADC[Y], gyroADC[Z]); + tfp_sprintf(lineBuffer, "G = %5d %5d %5d", gyroADC[X], gyroADC[Y], gyroADC[Z]); + padLineBuffer(); i2c_OLED_set_line(rowIndex++); i2c_OLED_send_string(lineBuffer); } #ifdef MAG if (sensors(SENSOR_MAG)) { - tfp_sprintf(lineBuffer, "Comp: %4d %4d %4d", magADC[X], magADC[Y], magADC[Z]); + tfp_sprintf(lineBuffer, "M = %5d %5d %5d", magADC[X], magADC[Y], magADC[Z]); + padLineBuffer(); i2c_OLED_set_line(rowIndex++); i2c_OLED_send_string(lineBuffer); } @@ -201,36 +271,44 @@ void updateDisplay(void) if (!armedStateChanged) { return; } + pageState.pageIdBeforeArming = pageState.pageId; pageState.pageId = PAGE_ARMED; pageState.pageChanging = true; } else { if (armedStateChanged) { - nextPageAt = now; - pageState.cycleIndex = CYCLE_PAGE_ID_COUNT; + pageState.pageFlags |= PAGE_STATE_FLAG_FORCE_PAGE_CHANGE; + pageState.pageId = pageState.pageIdBeforeArming; } - pageState.pageChanging = (int32_t)(now - nextPageAt) >= 0L; - if (pageState.pageChanging) { - nextPageAt = now + PAGE_CYCLE_FREQUENCY; + + pageState.pageChanging = (pageState.pageFlags & PAGE_STATE_FLAG_FORCE_PAGE_CHANGE) || ((int32_t)(now - pageState.nextPageAt) >= 0L); + if (pageState.pageChanging && (pageState.pageFlags & PAGE_STATE_FLAG_CYCLE_ENABLED)) { + pageState.nextPageAt = now + PAGE_CYCLE_FREQUENCY; pageState.cycleIndex++; pageState.cycleIndex = pageState.cycleIndex % CYCLE_PAGE_ID_COUNT; pageState.pageId = cyclePageIds[pageState.cycleIndex]; } } - if (pageState.pageChanging) { handlePageChange(); + pageState.pageFlags &= ~PAGE_STATE_FLAG_FORCE_PAGE_CHANGE; } switch(pageState.pageId) { + case PAGE_WELCOME: + showWelcomePage(); + break; + case PAGE_ARMED: + showArmedPage(); + break; case PAGE_BATTERY: showBatteryPage(); break; case PAGE_SENSORS: showSensorsPage(); break; - case PAGE_ARMED: - showArmedPage(); + case PAGE_RX: + showRxPage(); break; } if (!armedState) { @@ -238,12 +316,31 @@ void updateDisplay(void) } } - -void displayInit(void) +void displayInit(rxConfig_t *rxConfigToUse) { delay(20); ug2864hsweg01InitI2C(); + + rxConfig = rxConfigToUse; + memset(&pageState, 0, sizeof(pageState)); + pageState.pageId = PAGE_WELCOME; + + updateDisplay(); + + displaySetNextPageChangeAt(micros() + (1000 * 1000 * 5)); +} + +void displaySetNextPageChangeAt(uint32_t futureMicros) { + pageState.nextPageAt = futureMicros; +} + +void displayEnablePageCycling(void) { + pageState.pageFlags |= PAGE_STATE_FLAG_CYCLE_ENABLED; +} + +void displayDisablePageCycling(void) { + pageState.pageFlags &= ~PAGE_STATE_FLAG_CYCLE_ENABLED; } #endif diff --git a/src/main/io/display.h b/src/main/io/display.h index 8275bb56d..1100b52a1 100644 --- a/src/main/io/display.h +++ b/src/main/io/display.h @@ -17,3 +17,6 @@ void updateDisplay(void); +void displayEnablePageCycling(void); +void displayDisablePageCycling(void); +void displaySetNextPageChangeAt(uint32_t futureMicros); diff --git a/src/main/io/serial_cli.c b/src/main/io/serial_cli.c index e32f428b1..9efe6d89e 100644 --- a/src/main/io/serial_cli.c +++ b/src/main/io/serial_cli.c @@ -24,6 +24,7 @@ #include #include "platform.h" +#include "version.h" #include "build_config.h" @@ -1167,7 +1168,7 @@ static void cliVersion(char *cmdline) { UNUSED(cmdline); - cliPrint("Cleanflight/" __TARGET__ " " __DATE__ " / " __TIME__ " (" __REVISION__ ")"); + printf("Cleanflight/%s" __DATE__ " / " __TIME__ " (%s)", targetName, shortGitRevision); } void cliProcess(void) diff --git a/src/main/main.c b/src/main/main.c index ef14d77a1..31702a3f1 100755 --- a/src/main/main.c +++ b/src/main/main.c @@ -52,6 +52,7 @@ #include "io/rc_controls.h" #include "io/gimbal.h" #include "io/ledstrip.h" +#include "io/display.h" #include "sensors/sensors.h" #include "sensors/sonar.h" #include "sensors/barometer.h" @@ -93,7 +94,7 @@ void gpsInit(serialConfig_t *serialConfig, gpsConfig_t *initialGpsConfig); void navigationInit(gpsProfile_t *initialGpsProfile, pidProfile_t *pidProfile); bool sensorsAutodetect(sensorAlignmentConfig_t *sensorAlignmentConfig, uint16_t gyroLpf, uint8_t accHardwareToUse, int16_t magDeclinationFromConfig); void imuInit(void); -void displayInit(void); +void displayInit(rxConfig_t *intialRxConfig); void ledStripInit(ledConfig_t *ledConfigsToUse, hsvColor_t *colorsToUse, failsafe_t* failsafeToUse); void loop(void); @@ -144,7 +145,7 @@ void init(void) #ifdef DISPLAY if (feature(FEATURE_DISPLAY)) { - displayInit(); + displayInit(&masterConfig.rxConfig); } #endif @@ -285,6 +286,12 @@ void init(void) // Check battery type/voltage if (feature(FEATURE_VBAT)) batteryInit(&masterConfig.batteryConfig); + +#ifdef DISPLAY + if (feature(FEATURE_DISPLAY)) { + displayEnablePageCycling(); + } +#endif } #ifdef SOFTSERIAL_LOOPBACK diff --git a/src/main/version.c b/src/main/version.c new file mode 100644 index 000000000..3e0849457 --- /dev/null +++ b/src/main/version.c @@ -0,0 +1,19 @@ +/* + * This file is part of Cleanflight. + * + * Cleanflight is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cleanflight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cleanflight. If not, see . + */ + +char *targetName = __TARGET__; +char *shortGitRevision = __REVISION__; diff --git a/src/main/version.h b/src/main/version.h index 6f5ac5fac..ee0dae269 100644 --- a/src/main/version.h +++ b/src/main/version.h @@ -17,3 +17,5 @@ #define MW_VERSION 230 +extern char* targetName; +extern char* shortGitRevision;