void osdInit(void) { char x, string_buffer[30]; armState = ARMING_FLAG(ARMED); max7456Init(masterConfig.osdProfile.video_system); max7456ClearScreen(); // display logo and help x = 160; for (int i = 1; i < 5; i++) { for (int j = 3; j < 27; j++) { if (x != 255) max7456WriteChar(j, i, x++); } } sprintf(string_buffer, "BF VERSION: %s", FC_VERSION_STRING); max7456Write(5, 6, string_buffer); max7456Write(7, 7, "MENU: THRT MID"); max7456Write(13, 8, "YAW RIGHT"); max7456Write(13, 9, "PITCH UP"); max7456RefreshAll(); refreshTimeout = 4 * REFRESH_1S; }
void osdDrawElementPositioningHelp(void) { max7456Write(OSD_X(OSD_cfg.item_pos[OSD_ARTIFICIAL_HORIZON]), OSD_Y(OSD_cfg.item_pos[OSD_ARTIFICIAL_HORIZON]), "--- HELP --- "); max7456Write(OSD_X(OSD_cfg.item_pos[OSD_ARTIFICIAL_HORIZON]), OSD_Y(OSD_cfg.item_pos[OSD_ARTIFICIAL_HORIZON]) + 1, "USE ROLL/PITCH"); max7456Write(OSD_X(OSD_cfg.item_pos[OSD_ARTIFICIAL_HORIZON]), OSD_Y(OSD_cfg.item_pos[OSD_ARTIFICIAL_HORIZON]) + 2, "TO MOVE ELEM. "); max7456Write(OSD_X(OSD_cfg.item_pos[OSD_ARTIFICIAL_HORIZON]), OSD_Y(OSD_cfg.item_pos[OSD_ARTIFICIAL_HORIZON]) + 3, " "); max7456Write(OSD_X(OSD_cfg.item_pos[OSD_ARTIFICIAL_HORIZON]), OSD_Y(OSD_cfg.item_pos[OSD_ARTIFICIAL_HORIZON]) + 4, "YAW - EXIT "); }
// called when motors armed void osdArmMotors(void) { max7456ClearScreen(); max7456Write(12, 7, "ARMED"); refreshTimeout = REFRESH_1S / 2; osdResetStats(); }
static int writeString(displayPort_t *displayPort, uint8_t x, uint8_t y, const char *s) { UNUSED(displayPort); max7456Write(x, y, s); return 0; }
void osdEraseFlash(void *ptr) { UNUSED(ptr); max7456ClearScreen(); max7456Write(5, 3, "ERASING FLASH..."); max7456RefreshAll(); flashfsEraseCompletely(); while (!flashfsIsReady()) { delay(100); } max7456ClearScreen(); max7456RefreshAll(); }
void osdExitMenu(void *ptr) { max7456ClearScreen(); max7456Write(5, 3, "RESTARTING IMU..."); max7456RefreshAll(); stopMotors(); stopPwmAllMotors(); delay(200); if (ptr) { // save local variables to configuration if (featureBlackbox) featureSet(FEATURE_BLACKBOX); else featureClear(FEATURE_BLACKBOX); if (featureLedstrip) featureSet(FEATURE_LED_STRIP); else featureClear(FEATURE_LED_STRIP); #if defined(VTX) || defined(USE_RTC6705) if (featureVtx) featureSet(FEATURE_VTX); else featureClear(FEATURE_VTX); #endif // VTX || USE_RTC6705 #ifdef VTX masterConfig.vtxBand = vtxBand; masterConfig.vtx_channel = vtxChannel - 1; #endif // VTX #ifdef USE_RTC6705 masterConfig.vtx_channel = vtxBand * 8 + vtxChannel - 1; #endif // USE_RTC6705 saveConfigAndNotify(); } systemReset(); }
void osdDrawMenu(void) { uint8_t i = 0; OSD_Entry *p; char buff[10]; uint8_t top = (osdRows - currentMenuIdx) / 2 - 1; if (!currentMenu) return; if ((currentMenu + currentMenuPos)->type == OME_Label) // skip label currentMenuPos++; for (p = currentMenu; p->type != OME_END; p++) { if (currentMenuPos == i) max7456Write(LEFT_MENU_COLUMN, i + top, " >"); else max7456Write(LEFT_MENU_COLUMN, i + top, " "); max7456Write(LEFT_MENU_COLUMN + 2, i + top, p->text); switch (p->type) { case OME_POS: { uint32_t address = (uint32_t)p->data; uint16_t *val; val = (uint16_t *)address; if (!(*val & VISIBLE_FLAG)) break; } case OME_Submenu: max7456Write(RIGHT_MENU_COLUMN, i + top, ">"); break; case OME_Bool: if (p->data) { if (*((uint8_t *)(p->data))) max7456Write(RIGHT_MENU_COLUMN, i + top, "YES"); else max7456Write(RIGHT_MENU_COLUMN, i + top, "NO "); } break; case OME_TAB: { OSD_TAB_t *ptr = p->data; max7456Write(RIGHT_MENU_COLUMN - 5, i + top, (char *)ptr->names[*ptr->val]); break; } case OME_VISIBLE: if (p->data) { uint32_t address = (uint32_t)p->data; uint16_t *val; val = (uint16_t *)address; if (VISIBLE(*val)) max7456Write(RIGHT_MENU_COLUMN, i + top, "YES"); else max7456Write(RIGHT_MENU_COLUMN, i + top, "NO "); } break; case OME_UINT8: if (p->data) { OSD_UINT8_t *ptr = p->data; itoa(*ptr->val, buff, 10); max7456Write(RIGHT_MENU_COLUMN, i + top, " "); max7456Write(RIGHT_MENU_COLUMN, i + top, buff); } break; case OME_INT8: if (p->data) { OSD_INT8_t *ptr = p->data; itoa(*ptr->val, buff, 10); max7456Write(RIGHT_MENU_COLUMN, i + top, " "); max7456Write(RIGHT_MENU_COLUMN, i + top, buff); } break; case OME_UINT16: if (p->data) { OSD_UINT16_t *ptr = p->data; itoa(*ptr->val, buff, 10); max7456Write(RIGHT_MENU_COLUMN, i + top, " "); max7456Write(RIGHT_MENU_COLUMN, i + top, buff); } break; case OME_INT16: if (p->data) { OSD_UINT16_t *ptr = p->data; itoa(*ptr->val, buff, 10); max7456Write(RIGHT_MENU_COLUMN, i + top, " "); max7456Write(RIGHT_MENU_COLUMN, i + top, buff); } break; case OME_FLOAT: if (p->data) { OSD_FLOAT_t *ptr = p->data; simple_ftoa(*ptr->val * ptr->multipler, buff); max7456Write(RIGHT_MENU_COLUMN - 1, i + top, " "); max7456Write(RIGHT_MENU_COLUMN - 1, i + top, buff); } break; case OME_OSD_Exit: case OME_Label: case OME_END: case OME_Back: break; } i++; if (i == MAX_MENU_ITEMS) // max per page { nextPage = currentMenu + i; if (nextPage->type == OME_END) nextPage = NULL; break; } } }
void osdDrawSingleElement(uint8_t item) { if (!VISIBLE(OSD_cfg.item_pos[item]) || BLINK(OSD_cfg.item_pos[item])) return; uint8_t elemPosX = OSD_X(OSD_cfg.item_pos[item]); uint8_t elemPosY = OSD_Y(OSD_cfg.item_pos[item]); char buff[32]; switch(item) { case OSD_RSSI_VALUE: { uint16_t osdRssi = rssi * 100 / 1024; // change range if (osdRssi >= 100) osdRssi = 99; buff[0] = SYM_RSSI; sprintf(buff + 1, "%d", osdRssi); break; } case OSD_MAIN_BATT_VOLTAGE: { buff[0] = SYM_BATT_5; sprintf(buff + 1, "%d.%1dV", vbat / 10, vbat % 10); break; } case OSD_CURRENT_DRAW: { buff[0] = SYM_AMP; sprintf(buff + 1, "%d.%02d", abs(amperage) / 100, abs(amperage) % 100); break; } case OSD_MAH_DRAWN: { buff[0] = SYM_MAH; sprintf(buff + 1, "%d", mAhDrawn); break; } #ifdef GPS case OSD_GPS_SATS: { buff[0] = 0x1f; sprintf(buff + 1, "%d", GPS_numSat); break; } case OSD_GPS_SPEED: { sprintf(buff, "%d", GPS_speed * 36 / 1000); break; } #endif // GPS case OSD_ALTITUDE: { int32_t alt = osdGetAltitude(BaroAlt); sprintf(buff, "%c%d.%01d%c", alt < 0 ? '-' : ' ', abs(alt / 100), abs((alt % 100) / 10), osdGetAltitudeSymbol()); break; } case OSD_ONTIME: { uint32_t seconds = micros() / 1000000; buff[0] = SYM_ON_M; sprintf(buff + 1, "%02d:%02d", seconds / 60, seconds % 60); break; } case OSD_FLYTIME: { buff[0] = SYM_FLY_M; sprintf(buff + 1, "%02d:%02d", flyTime / 60, flyTime % 60); break; } case OSD_FLYMODE: { char *p = "ACRO"; if (isAirmodeActive()) p = "AIR"; if (FLIGHT_MODE(FAILSAFE_MODE)) p = "!FS"; else if (FLIGHT_MODE(ANGLE_MODE)) p = "STAB"; else if (FLIGHT_MODE(HORIZON_MODE)) p = "HOR"; max7456Write(elemPosX, elemPosY, p); return; } case OSD_CRAFT_NAME: { if (strlen(masterConfig.name) == 0) strcpy(buff, "CRAFT_NAME"); else { for (uint8_t i = 0; i < MAX_NAME_LENGTH; i++) { buff[i] = toupper((unsigned char)masterConfig.name[i]); if (masterConfig.name[i] == 0) break; } } break; } case OSD_THROTTLE_POS: { buff[0] = SYM_THR; buff[1] = SYM_THR1; sprintf(buff + 2, "%d", (constrain(rcData[THROTTLE], PWM_RANGE_MIN, PWM_RANGE_MAX) - PWM_RANGE_MIN) * 100 / (PWM_RANGE_MAX - PWM_RANGE_MIN)); break; } #ifdef VTX case OSD_VTX_CHANNEL: { sprintf(buff, "CH:%d", current_vtx_channel % CHANNELS_PER_BAND + 1); break; } #endif // VTX case OSD_CROSSHAIRS: { uint8_t *screenBuffer = max7456GetScreenBuffer(); uint16_t position = 194; if (maxScreenSize == VIDEO_BUFFER_CHARS_PAL) position += 30; screenBuffer[position - 1] = (SYM_AH_CENTER_LINE); screenBuffer[position + 1] = (SYM_AH_CENTER_LINE_RIGHT); screenBuffer[position] = (SYM_AH_CENTER); return; } case OSD_ARTIFICIAL_HORIZON: { uint8_t *screenBuffer = max7456GetScreenBuffer(); uint16_t position = 194; int rollAngle = attitude.values.roll; int pitchAngle = attitude.values.pitch; if (maxScreenSize == VIDEO_BUFFER_CHARS_PAL) position += 30; if (pitchAngle > AH_MAX_PITCH) pitchAngle = AH_MAX_PITCH; if (pitchAngle < -AH_MAX_PITCH) pitchAngle = -AH_MAX_PITCH; if (rollAngle > AH_MAX_ROLL) rollAngle = AH_MAX_ROLL; if (rollAngle < -AH_MAX_ROLL) rollAngle = -AH_MAX_ROLL; for (uint8_t x = 0; x <= 8; x++) { int y = (rollAngle * (4 - x)) / 64; y -= pitchAngle / 8; y += 41; if (y >= 0 && y <= 81) { uint16_t pos = position - 7 + LINE * (y / 9) + 3 - 4 * LINE + x; screenBuffer[pos] = (SYM_AH_BAR9_0 + (y % 9)); } } osdDrawSingleElement(OSD_HORIZON_SIDEBARS); return; } case OSD_HORIZON_SIDEBARS: { uint8_t *screenBuffer = max7456GetScreenBuffer(); uint16_t position = 194; if (maxScreenSize == VIDEO_BUFFER_CHARS_PAL) position += 30; // Draw AH sides int8_t hudwidth = AH_SIDEBAR_WIDTH_POS; int8_t hudheight = AH_SIDEBAR_HEIGHT_POS; for (int8_t x = -hudheight; x <= hudheight; x++) { screenBuffer[position - hudwidth + (x * LINE)] = (SYM_AH_DECORATION); screenBuffer[position + hudwidth + (x * LINE)] = (SYM_AH_DECORATION); } // AH level indicators screenBuffer[position - hudwidth + 1] = (SYM_AH_LEFT); screenBuffer[position + hudwidth - 1] = (SYM_AH_RIGHT); return; } default: return; } max7456Write(elemPosX, elemPosY, buff); }
void osdShowStats(void) { uint8_t top = 2; char buff[10]; max7456ClearScreen(); max7456Write(2, top++, " --- STATS ---"); if (STATE(GPS_FIX)) { max7456Write(2, top, "MAX SPEED :"); itoa(stats.max_speed, buff, 10); max7456Write(22, top++, buff); } max7456Write(2, top, "MIN BATTERY :"); sprintf(buff, "%d.%1dV", stats.min_voltage / 10, stats.min_voltage % 10); max7456Write(22, top++, buff); max7456Write(2, top, "MIN RSSI :"); itoa(stats.min_rssi, buff, 10); strcat(buff, "%"); max7456Write(22, top++, buff); if (feature(FEATURE_CURRENT_METER)) { max7456Write(2, top, "MAX CURRENT :"); itoa(stats.max_current, buff, 10); strcat(buff, "A"); max7456Write(22, top++, buff); max7456Write(2, top, "USED MAH :"); itoa(mAhDrawn, buff, 10); strcat(buff, "\x07"); max7456Write(22, top++, buff); } max7456Write(2, top, "MAX ALTITUDE :"); int32_t alt = osdGetAltitude(stats.max_altitude); sprintf(buff, "%c%d.%01d%c", alt < 0 ? '-' : ' ', abs(alt / 100), abs((alt % 100) / 10), osdGetAltitudeSymbol()); max7456Write(22, top++, buff); refreshTimeout = 60 * REFRESH_1S; }