mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-19 22:35:23 +03:00
Add HD OSD support (#11964)
This commit is contained in:
parent
1a45c87281
commit
3e51d15559
14 changed files with 287 additions and 32 deletions
121
docs/API/DisplayPort.md
Normal file
121
docs/API/DisplayPort.md
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
# DisplayPort MSP Extensions
|
||||||
|
|
||||||
|
Betaflight supports what is sometimes referred to as Canvas Mode whereby the OSD can sent arbitrary character strings to be displayed at given screen coordinates.
|
||||||
|
|
||||||
|
## DisplayPort MSP commands
|
||||||
|
|
||||||
|
### MSP\_SET\_OSD\_CANVAS
|
||||||
|
|
||||||
|
The MSP\_SET\_OSD\_CANVAS command is sent by the VTX, or display device, to the FC to indicate the size of the canvas available to the DisplayPort rendering when in HD mode. HD mode, as is indicated by `vcd_video_system = HD` is automatically set on reception of this command.
|
||||||
|
|
||||||
|
| Command | Msg Id | Direction | Notes |
|
||||||
|
|---------|--------|-----------|-------|
|
||||||
|
| MSP\_SET\_OSD\_CANVAS | 188 | to FC | Sets the canvas size|
|
||||||
|
|
||||||
|
| Data | Type | Notes |
|
||||||
|
|------|------|-------|
|
||||||
|
| canvas_cols | uint8 | The number of columns |
|
||||||
|
| canvas_rows | uint8 | The number of rows |
|
||||||
|
|
||||||
|
### MSP\_OSD\_CANVAS
|
||||||
|
|
||||||
|
The MSP\_OSD\_CANVAS command is sent by the configurator to the FC to determine the size of the canvas available to the DisplayPort rendering when in HD mode. This is then used on the OSD tab to show the correct number of rows/columns when editing the OSD element positions.
|
||||||
|
|
||||||
|
| Command | Msg Id | Direction | Notes |
|
||||||
|
|---------|--------|-----------|-------|
|
||||||
|
| MSP\_OSD\_CANVAS | 189 | to FC | Gets the canvas size|
|
||||||
|
|
||||||
|
Response is two bytes.
|
||||||
|
|
||||||
|
| Data | Type | Notes |
|
||||||
|
|------|------|-------|
|
||||||
|
| canvas_cols | uint8 | The number of columns |
|
||||||
|
| canvas_rows | uint8 | The number of rows |
|
||||||
|
|
||||||
|
### MSP\_DISPLAYPORT
|
||||||
|
|
||||||
|
The MSP\_DISPLAYPORT command is sent by the FC to the display device/VTX to perform a DisplayPort operation.
|
||||||
|
|
||||||
|
| Command | Msg Id | Direction | Notes |
|
||||||
|
|---------|--------|-----------|-------|
|
||||||
|
| MSP\_DISPLAYPORT | 182 | from FC | DisplayPort specific commands follow |
|
||||||
|
|
||||||
|
One of the following sub-commands will then follow.
|
||||||
|
|
||||||
|
## DisplayPort sub-commands
|
||||||
|
|
||||||
|
|
||||||
|
#### MSP\_DP\_HEARTBEAT
|
||||||
|
| Command | Msg Id | Notes |
|
||||||
|
|---------|--------|-------|
|
||||||
|
| MSP\_DP\_HEARTBEAT | 0 | Prevent OSD Slave boards from displaying a 'disconnected' status |
|
||||||
|
|
||||||
|
#### MSP\_DP\_RELEASE
|
||||||
|
| Command | Msg Id | Notes |
|
||||||
|
|---------|--------|-------|
|
||||||
|
| MSP\_DP\_RELEASE | 1 | Clears the display and allows local rendering on the display device based on telemetry informtation etc. |
|
||||||
|
|
||||||
|
#### MSP\_DP\_CLEAR\_SCREEN
|
||||||
|
| Command | Msg Id | Notes |
|
||||||
|
|---------|--------|-------|
|
||||||
|
| MSP\_DP\_CLEAR\_SCREEN | 2 | Clear the display |
|
||||||
|
|
||||||
|
#### MSP\_DP\_WRITE\_STRING
|
||||||
|
| Command | Msg Id | Notes |
|
||||||
|
|---------|--------|-------|
|
||||||
|
| MSP\_DP\_WRITE\_STRING | 3 | Write a string |
|
||||||
|
|
||||||
|
| Data | Type | Notes |
|
||||||
|
|------|------|-------|
|
||||||
|
| row | uint8 | Row on which to position the first character of the string |
|
||||||
|
| column | uint8 | Column on which to position the first character of the string |
|
||||||
|
| attribute | uint8 | Byte indicating the font to use and if the text should flash |
|
||||||
|
| string | uint8 x n | NULL terminated string of up to 30 characters in length |
|
||||||
|
|
||||||
|
The `attribute` parameter is encoded thus.
|
||||||
|
|
||||||
|
| Field | Bits | Comment |
|
||||||
|
| ----- | ---- | ------- |
|
||||||
|
| Version | 7 | Must be 0 |
|
||||||
|
| DISPLAYPORT\_MSP\_ATTR\_BLINK | 6 | Set to have the display device automatically blink the string |
|
||||||
|
| Reserved | 2 - 5 | Must be 0 |
|
||||||
|
| Font number | 0 - 1 | Selects one of four fonts, each of 256 8 bit characters |
|
||||||
|
|
||||||
|
#### MSP\_DP\_DRAW\_SCREEN
|
||||||
|
| Command | Msg Id | Notes |
|
||||||
|
|---------|--------|-------|
|
||||||
|
| MSP\_DP\_DRAW\_SCREEN | 4 | Triggers the display of a frame after it has been cleared/rendered |
|
||||||
|
|
||||||
|
#### MSP\_DP\_OPTIONS
|
||||||
|
| Command | Msg Id | Notes |
|
||||||
|
|---------|--------|-------|
|
||||||
|
| MSP\_DP\_OPTIONS | 5 | Not used by Betaflight. Used by INAV and Ardupilot to set display resolution. |
|
||||||
|
|
||||||
|
#### MSP\_DP\_SYS
|
||||||
|
| Command | Msg Id | Notes |
|
||||||
|
|---------|--------|-------|
|
||||||
|
| MSP\_DP\_SYS | 6 | Display system element displayportSystemElement_e at given coordinates |
|
||||||
|
|
||||||
|
| Data | Type | Notes |
|
||||||
|
|------|------|-------|
|
||||||
|
| row | uint8 | Row on which to position the first character of the string |
|
||||||
|
| column | uint8 | Column on which to position the first character of the string |
|
||||||
|
| system_element | uint8 | System element to be rendered by the VTX/goggle/display device |
|
||||||
|
|
||||||
|
`system_element` will be one of the following as defined by `displayPortSystemElement_e `. Once one MSP\_DP\_SYS sub-command has been received by the VTX/goggle/display device then the default system elements should no longer be displayed in their default locations, but only explicitly as directed by this command. In this way, the default behaviour is as before, but as soon as any system element is explicitly positioned these OSD elements behave just like any other and can be called up is specific locations by any given OSD profile.
|
||||||
|
|
||||||
|
```
|
||||||
|
// System elements rendered by VTX or Goggles
|
||||||
|
typedef enum {
|
||||||
|
DISPLAYPORT_SYS_GOGGLE_VOLTAGE = 0,
|
||||||
|
DISPLAYPORT_SYS_VTX_VOLTAGE = 1,
|
||||||
|
DISPLAYPORT_SYS_BITRATE = 2,
|
||||||
|
DISPLAYPORT_SYS_DELAY = 3,
|
||||||
|
DISPLAYPORT_SYS_DISTANCE = 4,
|
||||||
|
DISPLAYPORT_SYS_LQ = 5,
|
||||||
|
DISPLAYPORT_SYS_GOGGLE_DVR = 6,
|
||||||
|
DISPLAYPORT_SYS_VTX_DVR = 7,
|
||||||
|
DISPLAYPORT_SYS_WARNINGS = 8,
|
||||||
|
DISPLAYPORT_SYS_COUNT,
|
||||||
|
} displayPortSystemElement_e;
|
||||||
|
```
|
|
@ -385,7 +385,7 @@ const char * const lookupTableRescueAltitudeMode[] = {
|
||||||
|
|
||||||
#if defined(USE_MAX7456) || defined(USE_FRSKYOSD)
|
#if defined(USE_MAX7456) || defined(USE_FRSKYOSD)
|
||||||
static const char * const lookupTableVideoSystem[] = {
|
static const char * const lookupTableVideoSystem[] = {
|
||||||
"AUTO", "PAL", "NTSC"
|
"AUTO", "PAL", "NTSC", "HD"
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1430,6 +1430,18 @@ const clivalue_t valueTable[] = {
|
||||||
{ "osd_total_flights_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_TOTAL_FLIGHTS]) },
|
{ "osd_total_flights_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_TOTAL_FLIGHTS]) },
|
||||||
{ "osd_aux_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_AUX_VALUE]) },
|
{ "osd_aux_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_AUX_VALUE]) },
|
||||||
|
|
||||||
|
#ifdef USE_MSP_DISPLAYPORT
|
||||||
|
{ "osd_sys_goggle_voltage_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_SYS_GOGGLE_VOLTAGE]) },
|
||||||
|
{ "osd_sys_vtx_voltage_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_SYS_VTX_VOLTAGE]) },
|
||||||
|
{ "osd_sys_bitrate_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_SYS_BITRATE]) },
|
||||||
|
{ "osd_sys_delay_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_SYS_DELAY]) },
|
||||||
|
{ "osd_sys_distance_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_SYS_DISTANCE]) },
|
||||||
|
{ "osd_sys_lq_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_SYS_LQ]) },
|
||||||
|
{ "osd_sys_goggle_dvr_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_SYS_GOGGLE_DVR]) },
|
||||||
|
{ "osd_sys_vtx_dvr_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_SYS_VTX_DVR]) },
|
||||||
|
{ "osd_sys_warnings_pos", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, OSD_POSCFG_MAX }, PG_OSD_ELEMENT_CONFIG, offsetof(osdElementConfig_t, item_pos[OSD_SYS_WARNINGS]) },
|
||||||
|
#endif
|
||||||
|
|
||||||
// OSD stats enabled flags are stored as bitmapped values inside a 32bit parameter
|
// OSD stats enabled flags are stored as bitmapped values inside a 32bit parameter
|
||||||
{ "osd_stat_bitmask", VAR_UINT32 | MASTER_VALUE, .config.u32Max = UINT32_MAX, PG_OSD_CONFIG, offsetof(osdConfig_t, enabled_stats)},
|
{ "osd_stat_bitmask", VAR_UINT32 | MASTER_VALUE, .config.u32Max = UINT32_MAX, PG_OSD_CONFIG, offsetof(osdConfig_t, enabled_stats)},
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,8 @@ bool cmsDisplayPortSelect(displayPort_t *instance)
|
||||||
// 30 cols x 13 rows
|
// 30 cols x 13 rows
|
||||||
// HoTT Telemetry Screen
|
// HoTT Telemetry Screen
|
||||||
// 21 cols x 8 rows
|
// 21 cols x 8 rows
|
||||||
//
|
// HD
|
||||||
|
// 53 cols x 20 rows
|
||||||
// Spektrum SRXL Telemtry Textgenerator
|
// Spektrum SRXL Telemtry Textgenerator
|
||||||
// 13 cols x 9 rows, top row printed as a Bold Heading
|
// 13 cols x 9 rows, top row printed as a Bold Heading
|
||||||
// Needs the "smallScreen" adaptions
|
// Needs the "smallScreen" adaptions
|
||||||
|
|
|
@ -80,6 +80,15 @@ void displaySetXY(displayPort_t *instance, uint8_t x, uint8_t y)
|
||||||
instance->posY = y;
|
instance->posY = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int displaySys(displayPort_t *instance, uint8_t x, uint8_t y, displayPortSystemElement_e systemElement)
|
||||||
|
{
|
||||||
|
if (instance->vTable->writeSys) {
|
||||||
|
return instance->vTable->writeSys(instance, x, y, systemElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int displayWrite(displayPort_t *instance, uint8_t x, uint8_t y, uint8_t attr, const char *text)
|
int displayWrite(displayPort_t *instance, uint8_t x, uint8_t y, uint8_t attr, const char *text)
|
||||||
{
|
{
|
||||||
instance->posX = x + strlen(text);
|
instance->posX = x + strlen(text);
|
||||||
|
|
|
@ -39,6 +39,20 @@ typedef enum {
|
||||||
|
|
||||||
#define DISPLAYPORT_ATTR_BLINK 0x80 // Device local blink bit or'ed into displayPortAttr_e
|
#define DISPLAYPORT_ATTR_BLINK 0x80 // Device local blink bit or'ed into displayPortAttr_e
|
||||||
|
|
||||||
|
// System elements rendered by VTX or Goggles
|
||||||
|
typedef enum {
|
||||||
|
DISPLAYPORT_SYS_GOGGLE_VOLTAGE = 0,
|
||||||
|
DISPLAYPORT_SYS_VTX_VOLTAGE = 1,
|
||||||
|
DISPLAYPORT_SYS_BITRATE = 2,
|
||||||
|
DISPLAYPORT_SYS_DELAY = 3,
|
||||||
|
DISPLAYPORT_SYS_DISTANCE = 4,
|
||||||
|
DISPLAYPORT_SYS_LQ = 5,
|
||||||
|
DISPLAYPORT_SYS_GOGGLE_DVR = 6,
|
||||||
|
DISPLAYPORT_SYS_VTX_DVR = 7,
|
||||||
|
DISPLAYPORT_SYS_WARNINGS = 8,
|
||||||
|
DISPLAYPORT_SYS_COUNT,
|
||||||
|
} displayPortSystemElement_e;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DISPLAYPORT_LAYER_FOREGROUND,
|
DISPLAYPORT_LAYER_FOREGROUND,
|
||||||
DISPLAYPORT_LAYER_BACKGROUND,
|
DISPLAYPORT_LAYER_BACKGROUND,
|
||||||
|
@ -103,6 +117,7 @@ typedef struct displayPortVTable_s {
|
||||||
int (*clearScreen)(displayPort_t *displayPort, displayClearOption_e options);
|
int (*clearScreen)(displayPort_t *displayPort, displayClearOption_e options);
|
||||||
bool (*drawScreen)(displayPort_t *displayPort);
|
bool (*drawScreen)(displayPort_t *displayPort);
|
||||||
int (*screenSize)(const displayPort_t *displayPort);
|
int (*screenSize)(const displayPort_t *displayPort);
|
||||||
|
int (*writeSys)(displayPort_t *displayPort, uint8_t x, uint8_t y, displayPortSystemElement_e systemElement);
|
||||||
int (*writeString)(displayPort_t *displayPort, uint8_t x, uint8_t y, uint8_t attr, const char *text);
|
int (*writeString)(displayPort_t *displayPort, uint8_t x, uint8_t y, uint8_t attr, const char *text);
|
||||||
int (*writeChar)(displayPort_t *displayPort, uint8_t x, uint8_t y, uint8_t attr, uint8_t c);
|
int (*writeChar)(displayPort_t *displayPort, uint8_t x, uint8_t y, uint8_t attr, uint8_t c);
|
||||||
bool (*isTransferInProgress)(const displayPort_t *displayPort);
|
bool (*isTransferInProgress)(const displayPort_t *displayPort);
|
||||||
|
@ -129,6 +144,7 @@ void displayClearScreen(displayPort_t *instance, displayClearOption_e options);
|
||||||
bool displayDrawScreen(displayPort_t *instance);
|
bool displayDrawScreen(displayPort_t *instance);
|
||||||
int displayScreenSize(const displayPort_t *instance);
|
int displayScreenSize(const displayPort_t *instance);
|
||||||
void displaySetXY(displayPort_t *instance, uint8_t x, uint8_t y);
|
void displaySetXY(displayPort_t *instance, uint8_t x, uint8_t y);
|
||||||
|
int displaySys(displayPort_t *instance, uint8_t x, uint8_t y, displayPortSystemElement_e systemElement);
|
||||||
int displayWrite(displayPort_t *instance, uint8_t x, uint8_t y, uint8_t attr, const char *text);
|
int displayWrite(displayPort_t *instance, uint8_t x, uint8_t y, uint8_t attr, const char *text);
|
||||||
int displayWriteChar(displayPort_t *instance, uint8_t x, uint8_t y, uint8_t attr, uint8_t c);
|
int displayWriteChar(displayPort_t *instance, uint8_t x, uint8_t y, uint8_t attr, uint8_t c);
|
||||||
bool displayIsTransferInProgress(const displayPort_t *instance);
|
bool displayIsTransferInProgress(const displayPort_t *instance);
|
||||||
|
|
|
@ -43,7 +43,8 @@
|
||||||
typedef enum {
|
typedef enum {
|
||||||
VIDEO_SYSTEM_AUTO = 0,
|
VIDEO_SYSTEM_AUTO = 0,
|
||||||
VIDEO_SYSTEM_PAL,
|
VIDEO_SYSTEM_PAL,
|
||||||
VIDEO_SYSTEM_NTSC
|
VIDEO_SYSTEM_NTSC,
|
||||||
|
VIDEO_SYSTEM_HD
|
||||||
} videoSystem_e;
|
} videoSystem_e;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -60,7 +60,7 @@ static int output(displayPort_t *displayPort, uint8_t cmd, uint8_t *buf, int len
|
||||||
|
|
||||||
static int heartbeat(displayPort_t *displayPort)
|
static int heartbeat(displayPort_t *displayPort)
|
||||||
{
|
{
|
||||||
uint8_t subcmd[] = { 0 };
|
uint8_t subcmd[] = { MSP_DP_HEARTBEAT };
|
||||||
|
|
||||||
// heartbeat is used to:
|
// heartbeat is used to:
|
||||||
// a) ensure display is not released by MW OSD software
|
// a) ensure display is not released by MW OSD software
|
||||||
|
@ -128,6 +128,18 @@ static int writeString(displayPort_t *displayPort, uint8_t col, uint8_t row, uin
|
||||||
return output(displayPort, MSP_DISPLAYPORT, buf, len + 4);
|
return output(displayPort, MSP_DISPLAYPORT, buf, len + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int writeSys(displayPort_t *displayPort, uint8_t col, uint8_t row, displayPortSystemElement_e systemElement)
|
||||||
|
{
|
||||||
|
uint8_t syscmd[4];
|
||||||
|
|
||||||
|
syscmd[0] = MSP_DP_SYS;
|
||||||
|
syscmd[1] = row;
|
||||||
|
syscmd[2] = col;
|
||||||
|
syscmd[3] = systemElement;
|
||||||
|
|
||||||
|
return output(displayPort, MSP_DISPLAYPORT, syscmd, sizeof(syscmd));
|
||||||
|
}
|
||||||
|
|
||||||
static int writeChar(displayPort_t *displayPort, uint8_t col, uint8_t row, uint8_t attr, uint8_t c)
|
static int writeChar(displayPort_t *displayPort, uint8_t col, uint8_t row, uint8_t attr, uint8_t c)
|
||||||
{
|
{
|
||||||
char buf[2];
|
char buf[2];
|
||||||
|
@ -169,6 +181,7 @@ static const displayPortVTable_t mspDisplayPortVTable = {
|
||||||
.clearScreen = clearScreen,
|
.clearScreen = clearScreen,
|
||||||
.drawScreen = drawScreen,
|
.drawScreen = drawScreen,
|
||||||
.screenSize = screenSize,
|
.screenSize = screenSize,
|
||||||
|
.writeSys = writeSys,
|
||||||
.writeString = writeString,
|
.writeString = writeString,
|
||||||
.writeChar = writeChar,
|
.writeChar = writeChar,
|
||||||
.isTransferInProgress = isTransferInProgress,
|
.isTransferInProgress = isTransferInProgress,
|
||||||
|
|
|
@ -27,15 +27,22 @@
|
||||||
#include "pg/displayport_profiles.h"
|
#include "pg/displayport_profiles.h"
|
||||||
|
|
||||||
// MSP Display Port commands
|
// MSP Display Port commands
|
||||||
#define MSP_DP_RELEASE 1
|
typedef enum {
|
||||||
#define MSP_DP_CLEAR_SCREEN 2
|
MSP_DP_HEARTBEAT = 0, // Release the display after clearing and updating
|
||||||
#define MSP_DP_WRITE_STRING 3
|
MSP_DP_RELEASE = 1, // Release the display after clearing and updating
|
||||||
#define MSP_DP_DRAW_SCREEN 4
|
MSP_DP_CLEAR_SCREEN = 2, // Clear the display
|
||||||
|
MSP_DP_WRITE_STRING = 3, // Write a string at given coordinates
|
||||||
|
MSP_DP_DRAW_SCREEN = 4, // Trigger a screen draw
|
||||||
|
MSP_DP_OPTIONS = 5, // Not used by Betaflight. Reserved by Ardupilot and INAV
|
||||||
|
MSP_DP_SYS = 6, // Display system element displayportSystemElement_e at given coordinates
|
||||||
|
MSP_DP_COUNT,
|
||||||
|
} displayportMspCommand_e;
|
||||||
|
|
||||||
// MSP displayport V2 attribute byte bit functions
|
// MSP displayport V2 attribute byte bit functions
|
||||||
#define DISPLAYPORT_MSP_ATTR_VERSION BIT(7) // Format indicator; must be zero for V2 (and V1)
|
#define DISPLAYPORT_MSP_ATTR_VERSION BIT(7) // Format indicator; must be zero for V2 (and V1)
|
||||||
#define DISPLAYPORT_MSP_ATTR_BLINK BIT(6) // Device local blink
|
#define DISPLAYPORT_MSP_ATTR_BLINK BIT(6) // Device local blink
|
||||||
#define DISPLAYPORT_MSP_ATTR_MASK (~(DISPLAYPORT_MSP_ATTR_VERSION|DISPLAYPORT_MSP_ATTR_BLINK))
|
#define DISPLAYPORT_MSP_ATTR_FONT (BIT(0) | BIT(1)) // Select bank of 256 characters as per displayPortAttr_e
|
||||||
|
#define DISPLAYPORT_MSP_ATTR_MASK (~(DISPLAYPORT_MSP_ATTR_VERSION | DISPLAYPORT_MSP_ATTR_BLINK | DISPLAYPORT_MSP_ATTR_FONT))
|
||||||
|
|
||||||
struct displayPort_s *displayPortMspInit(void);
|
struct displayPort_s *displayPortMspInit(void);
|
||||||
void displayPortMspSetSerial(serialPortIdentifier_e serialPort);
|
void displayPortMspSetSerial(serialPortIdentifier_e serialPort);
|
||||||
|
|
|
@ -983,10 +983,10 @@ static bool mspCommonProcessOutCommand(int16_t cmdMSP, sbuf_t *dst, mspPostProce
|
||||||
sbufWriteU8(dst, osdFlags);
|
sbufWriteU8(dst, osdFlags);
|
||||||
|
|
||||||
#ifdef USE_MAX7456
|
#ifdef USE_MAX7456
|
||||||
// send video system (AUTO/PAL/NTSC)
|
// send video system (AUTO/PAL/NTSC/HD)
|
||||||
sbufWriteU8(dst, vcdProfile()->video_system);
|
sbufWriteU8(dst, vcdProfile()->video_system);
|
||||||
#else
|
#else
|
||||||
sbufWriteU8(dst, 0);
|
sbufWriteU8(dst, VIDEO_SYSTEM_HD);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_OSD
|
#ifdef USE_OSD
|
||||||
|
@ -1056,6 +1056,14 @@ static bool mspCommonProcessOutCommand(int16_t cmdMSP, sbuf_t *dst, mspPostProce
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MSP_OSD_CANVAS: {
|
||||||
|
#ifdef USE_OSD
|
||||||
|
sbufWriteU8(dst, osdConfig()->canvas_cols);
|
||||||
|
sbufWriteU8(dst, osdConfig()->canvas_rows);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1245,7 +1253,7 @@ case MSP_NAME:
|
||||||
|
|
||||||
// Voltage -> 0-63,75V step 0,25V
|
// Voltage -> 0-63,75V step 0,25V
|
||||||
if ((dshotTelemetryState.motorState[i].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_VOLTAGE)) != 0) {
|
if ((dshotTelemetryState.motorState[i].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_VOLTAGE)) != 0) {
|
||||||
escVoltage = dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_VOLTAGE] >> 2;
|
escVoltage = dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_VOLTAGE] >> 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4182,6 +4190,16 @@ static mspResult_e mspCommonProcessInCommand(mspDescriptor_t srcDesc, int16_t cm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MSP_SET_OSD_CANVAS:
|
||||||
|
{
|
||||||
|
osdConfigMutable()->canvas_cols = sbufReadU8(src);
|
||||||
|
osdConfigMutable()->canvas_rows = sbufReadU8(src);
|
||||||
|
|
||||||
|
// An HD VTX has communicated it's canvas size, so we must be in HD mode
|
||||||
|
vcdProfileMutable()->video_system = VIDEO_SYSTEM_HD;
|
||||||
|
}
|
||||||
|
break;
|
||||||
#endif // OSD
|
#endif // OSD
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
#define MSP_PROTOCOL_VERSION 0
|
#define MSP_PROTOCOL_VERSION 0
|
||||||
|
|
||||||
#define API_VERSION_MAJOR 1 // increment when major changes are made
|
#define API_VERSION_MAJOR 1 // increment when major changes are made
|
||||||
#define API_VERSION_MINOR 45 // increment after a release, to set the version for all changes to go into the following release (if no changes to MSP are made between the releases, this can be reverted before the release)
|
#define API_VERSION_MINOR 46 // increment after a release, to set the version for all changes to go into the following release (if no changes to MSP are made between the releases, this can be reverted before the release)
|
||||||
|
|
||||||
#define API_VERSION_LENGTH 2
|
#define API_VERSION_LENGTH 2
|
||||||
|
|
||||||
|
@ -235,6 +235,9 @@
|
||||||
#define MSP_SET_TX_INFO 186 // in message Used to send runtime information from TX lua scripts to the firmware
|
#define MSP_SET_TX_INFO 186 // in message Used to send runtime information from TX lua scripts to the firmware
|
||||||
#define MSP_TX_INFO 187 // out message Used by TX lua scripts to read information from the firmware
|
#define MSP_TX_INFO 187 // out message Used by TX lua scripts to read information from the firmware
|
||||||
|
|
||||||
|
#define MSP_SET_OSD_CANVAS 188 // in message Set osd canvas size COLSxROWS
|
||||||
|
#define MSP_OSD_CANVAS 189 // out message Get osd canvas size COLSxROWS
|
||||||
|
|
||||||
//
|
//
|
||||||
// Multwii original MSP commands
|
// Multwii original MSP commands
|
||||||
//
|
//
|
||||||
|
|
|
@ -147,9 +147,9 @@ static bool backgroundLayerSupported = false;
|
||||||
escSensorData_t *osdEscDataCombined;
|
escSensorData_t *osdEscDataCombined;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
STATIC_ASSERT(OSD_POS_MAX == OSD_POS(31,31), OSD_POS_MAX_incorrect);
|
STATIC_ASSERT(OSD_POS_MAX == OSD_POS(63,31), OSD_POS_MAX_incorrect);
|
||||||
|
|
||||||
PG_REGISTER_WITH_RESET_FN(osdConfig_t, osdConfig, PG_OSD_CONFIG, 11);
|
PG_REGISTER_WITH_RESET_FN(osdConfig_t, osdConfig, PG_OSD_CONFIG, 12);
|
||||||
|
|
||||||
PG_REGISTER_WITH_RESET_FN(osdElementConfig_t, osdElementConfig, PG_OSD_ELEMENT_CONFIG, 1);
|
PG_REGISTER_WITH_RESET_FN(osdElementConfig_t, osdElementConfig, PG_OSD_ELEMENT_CONFIG, 1);
|
||||||
|
|
||||||
|
@ -398,6 +398,9 @@ void pgResetFn_osdConfig(osdConfig_t *osdConfig)
|
||||||
osdConfig->aux_channel = 1;
|
osdConfig->aux_channel = 1;
|
||||||
osdConfig->aux_scale = 200;
|
osdConfig->aux_scale = 200;
|
||||||
osdConfig->aux_symbol = 'A';
|
osdConfig->aux_symbol = 'A';
|
||||||
|
|
||||||
|
osdConfig->canvas_cols = OSD_HD_COLS;
|
||||||
|
osdConfig->canvas_rows = OSD_HD_ROWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pgResetFn_osdElementConfig(osdElementConfig_t *osdElementConfig)
|
void pgResetFn_osdElementConfig(osdElementConfig_t *osdElementConfig)
|
||||||
|
@ -840,13 +843,13 @@ static bool osdDisplayStat(int statistic, uint8_t displayRow)
|
||||||
#ifdef USE_ESC_SENSOR
|
#ifdef USE_ESC_SENSOR
|
||||||
case OSD_STAT_MAX_ESC_TEMP:
|
case OSD_STAT_MAX_ESC_TEMP:
|
||||||
{
|
{
|
||||||
uint16_t ix = 0;
|
uint16_t ix = 0;
|
||||||
if (stats.max_esc_temp_ix > 0) {
|
if (stats.max_esc_temp_ix > 0) {
|
||||||
ix = tfp_sprintf(buff, "%d ", stats.max_esc_temp_ix);
|
ix = tfp_sprintf(buff, "%d ", stats.max_esc_temp_ix);
|
||||||
}
|
}
|
||||||
tfp_sprintf(buff + ix, "%d%c", osdConvertTemperatureToSelectedUnit(stats.max_esc_temp), osdGetTemperatureSymbolForSelectedUnit());
|
tfp_sprintf(buff + ix, "%d%c", osdConvertTemperatureToSelectedUnit(stats.max_esc_temp), osdGetTemperatureSymbolForSelectedUnit());
|
||||||
osdDisplayStatisticLabel(displayRow, "MAX ESC TEMP", buff);
|
osdDisplayStatisticLabel(displayRow, "MAX ESC TEMP", buff);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ extern const char * const osdTimerSourceNames[OSD_NUM_TIMER_TYPES];
|
||||||
|
|
||||||
#define OSD_PROFILE_BITS_POS 11
|
#define OSD_PROFILE_BITS_POS 11
|
||||||
#define OSD_PROFILE_MASK (((1 << OSD_PROFILE_COUNT) - 1) << OSD_PROFILE_BITS_POS)
|
#define OSD_PROFILE_MASK (((1 << OSD_PROFILE_COUNT) - 1) << OSD_PROFILE_BITS_POS)
|
||||||
#define OSD_POS_MAX 0x3FF
|
#define OSD_POS_MAX 0x7FF
|
||||||
#define OSD_POSCFG_MAX UINT16_MAX // element positions now use all 16 bits
|
#define OSD_POSCFG_MAX UINT16_MAX // element positions now use all 16 bits
|
||||||
#define OSD_PROFILE_FLAG(x) (1 << ((x) - 1 + OSD_PROFILE_BITS_POS))
|
#define OSD_PROFILE_FLAG(x) (1 << ((x) - 1 + OSD_PROFILE_BITS_POS))
|
||||||
#define OSD_PROFILE_1_FLAG OSD_PROFILE_FLAG(1)
|
#define OSD_PROFILE_1_FLAG OSD_PROFILE_FLAG(1)
|
||||||
|
@ -71,14 +71,21 @@ extern const char * const osdTimerSourceNames[OSD_NUM_TIMER_TYPES];
|
||||||
|
|
||||||
|
|
||||||
// Character coordinate
|
// Character coordinate
|
||||||
#define OSD_POSITION_BITS 5 // 5 bits gives a range 0-31
|
#define OSD_POSITION_BITS 5 // 5 bits gives a range 0-31
|
||||||
#define OSD_POSITION_XY_MASK ((1 << OSD_POSITION_BITS) - 1)
|
#define OSD_POSITION_BIT_XHD 10 // extra bit used to extend X range in a backward compatible manner for HD displays
|
||||||
#define OSD_TYPE_MASK 0xC000 // bits 14-15
|
#define OSD_POSITIION_XHD_MASK (1 << OSD_POSITION_BIT_XHD)
|
||||||
#define OSD_POS(x,y) ((x & OSD_POSITION_XY_MASK) | ((y & OSD_POSITION_XY_MASK) << OSD_POSITION_BITS))
|
#define OSD_POSITION_XY_MASK ((1 << OSD_POSITION_BITS) - 1)
|
||||||
#define OSD_X(x) (x & OSD_POSITION_XY_MASK)
|
#define OSD_TYPE_MASK 0xC000 // bits 14-15
|
||||||
|
#define OSD_POS(x,y) ((x & OSD_POSITION_XY_MASK) | ((x << (OSD_POSITION_BIT_XHD - OSD_POSITION_BITS)) & OSD_POSITIION_XHD_MASK) | \
|
||||||
|
((y & OSD_POSITION_XY_MASK) << OSD_POSITION_BITS))
|
||||||
|
#define OSD_X(x) ((x & OSD_POSITION_XY_MASK) | ((x & OSD_POSITION_BIT_XHD) >> (OSD_POSITION_BIT_XHD - OSD_POSITION_BITS)))
|
||||||
#define OSD_Y(x) ((x >> OSD_POSITION_BITS) & OSD_POSITION_XY_MASK)
|
#define OSD_Y(x) ((x >> OSD_POSITION_BITS) & OSD_POSITION_XY_MASK)
|
||||||
#define OSD_TYPE(x) ((x & OSD_TYPE_MASK) >> 14)
|
#define OSD_TYPE(x) ((x & OSD_TYPE_MASK) >> 14)
|
||||||
|
|
||||||
|
// Default HD OSD canvas size to be applied unless the goggles announce otherwise
|
||||||
|
#define OSD_HD_COLS 53
|
||||||
|
#define OSD_HD_ROWS 20
|
||||||
|
|
||||||
// Timer configuration
|
// Timer configuration
|
||||||
// Stored as 15[alarm:8][precision:4][source:4]0
|
// Stored as 15[alarm:8][precision:4][source:4]0
|
||||||
#define OSD_TIMER(src, prec, alarm) ((src & 0x0F) | ((prec & 0x0F) << 4) | ((alarm & 0xFF ) << 8))
|
#define OSD_TIMER(src, prec, alarm) ((src & 0x0F) | ((prec & 0x0F) << 4) | ((alarm & 0xFF ) << 8))
|
||||||
|
@ -165,6 +172,15 @@ typedef enum {
|
||||||
OSD_AUX_VALUE,
|
OSD_AUX_VALUE,
|
||||||
OSD_READY_MODE,
|
OSD_READY_MODE,
|
||||||
OSD_RSNR_VALUE,
|
OSD_RSNR_VALUE,
|
||||||
|
OSD_SYS_GOGGLE_VOLTAGE,
|
||||||
|
OSD_SYS_VTX_VOLTAGE,
|
||||||
|
OSD_SYS_BITRATE,
|
||||||
|
OSD_SYS_DELAY,
|
||||||
|
OSD_SYS_DISTANCE,
|
||||||
|
OSD_SYS_LQ,
|
||||||
|
OSD_SYS_GOGGLE_DVR,
|
||||||
|
OSD_SYS_VTX_DVR,
|
||||||
|
OSD_SYS_WARNINGS,
|
||||||
OSD_ITEM_COUNT // MUST BE LAST
|
OSD_ITEM_COUNT // MUST BE LAST
|
||||||
} osd_items_e;
|
} osd_items_e;
|
||||||
|
|
||||||
|
@ -317,6 +333,8 @@ typedef struct osdConfig_s {
|
||||||
uint8_t aux_channel;
|
uint8_t aux_channel;
|
||||||
uint16_t aux_scale;
|
uint16_t aux_scale;
|
||||||
uint8_t aux_symbol;
|
uint8_t aux_symbol;
|
||||||
|
uint8_t canvas_cols; // Canvas dimensions for HD display
|
||||||
|
uint8_t canvas_rows;
|
||||||
} osdConfig_t;
|
} osdConfig_t;
|
||||||
|
|
||||||
PG_DECLARE(osdConfig_t, osdConfig);
|
PG_DECLARE(osdConfig_t, osdConfig);
|
||||||
|
|
|
@ -1539,6 +1539,15 @@ static void osdElementWarnings(osdElementParms_t *element)
|
||||||
#endif // USE_CRAFTNAME_MSGS
|
#endif // USE_CRAFTNAME_MSGS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_MSP_DISPLAYPORT
|
||||||
|
static void osdElementSys(osdElementParms_t *element)
|
||||||
|
{
|
||||||
|
UNUSED(element);
|
||||||
|
|
||||||
|
// Nothing to render for a system element
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Define the order in which the elements are drawn.
|
// Define the order in which the elements are drawn.
|
||||||
// Elements positioned later in the list will overlay the earlier
|
// Elements positioned later in the list will overlay the earlier
|
||||||
// ones if their character positions overlap
|
// ones if their character positions overlap
|
||||||
|
@ -1627,6 +1636,15 @@ static const uint8_t osdElementDisplayOrder[] = {
|
||||||
OSD_TOTAL_FLIGHTS,
|
OSD_TOTAL_FLIGHTS,
|
||||||
#endif
|
#endif
|
||||||
OSD_AUX_VALUE,
|
OSD_AUX_VALUE,
|
||||||
|
OSD_SYS_GOGGLE_VOLTAGE,
|
||||||
|
OSD_SYS_VTX_VOLTAGE,
|
||||||
|
OSD_SYS_BITRATE,
|
||||||
|
OSD_SYS_DELAY,
|
||||||
|
OSD_SYS_DISTANCE,
|
||||||
|
OSD_SYS_LQ,
|
||||||
|
OSD_SYS_GOGGLE_DVR,
|
||||||
|
OSD_SYS_VTX_DVR,
|
||||||
|
OSD_SYS_WARNINGS,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Define the mapping between the OSD element id and the function to draw it
|
// Define the mapping between the OSD element id and the function to draw it
|
||||||
|
@ -1748,6 +1766,17 @@ const osdElementDrawFn osdElementDrawFunction[OSD_ITEM_COUNT] = {
|
||||||
[OSD_TOTAL_FLIGHTS] = osdElementTotalFlights,
|
[OSD_TOTAL_FLIGHTS] = osdElementTotalFlights,
|
||||||
#endif
|
#endif
|
||||||
[OSD_AUX_VALUE] = osdElementAuxValue,
|
[OSD_AUX_VALUE] = osdElementAuxValue,
|
||||||
|
#ifdef USE_MSP_DISPLAYPORT
|
||||||
|
[OSD_SYS_GOGGLE_VOLTAGE] = osdElementSys,
|
||||||
|
[OSD_SYS_VTX_VOLTAGE] = osdElementSys,
|
||||||
|
[OSD_SYS_BITRATE] = osdElementSys,
|
||||||
|
[OSD_SYS_DELAY] = osdElementSys,
|
||||||
|
[OSD_SYS_DISTANCE] = osdElementSys,
|
||||||
|
[OSD_SYS_LQ] = osdElementSys,
|
||||||
|
[OSD_SYS_GOGGLE_DVR] = osdElementSys,
|
||||||
|
[OSD_SYS_VTX_DVR] = osdElementSys,
|
||||||
|
[OSD_SYS_WARNINGS] = osdElementSys,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Define the mapping between the OSD element id and the function to draw its background (static part)
|
// Define the mapping between the OSD element id and the function to draw its background (static part)
|
||||||
|
@ -1841,9 +1870,13 @@ static void osdDrawSingleElement(displayPort_t *osdDisplayPort, uint8_t item)
|
||||||
element.attr = DISPLAYPORT_ATTR_NONE;
|
element.attr = DISPLAYPORT_ATTR_NONE;
|
||||||
|
|
||||||
// Call the element drawing function
|
// Call the element drawing function
|
||||||
osdElementDrawFunction[item](&element);
|
if ((item >= OSD_SYS_GOGGLE_VOLTAGE) && (item < OSD_SYS_WARNINGS)) {
|
||||||
if (element.drawElement) {
|
displaySys(osdDisplayPort, elemPosX, elemPosY, (displayPortSystemElement_e)(item - OSD_SYS_GOGGLE_VOLTAGE + DISPLAYPORT_SYS_GOGGLE_VOLTAGE));
|
||||||
osdDisplayWrite(&element, elemPosX, elemPosY, element.attr, buff);
|
} else {
|
||||||
|
osdElementDrawFunction[item](&element);
|
||||||
|
if (element.drawElement) {
|
||||||
|
osdDisplayWrite(&element, elemPosX, elemPosY, element.attr, buff);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -222,7 +222,7 @@ TEST(RxSpiExpressLrsTelemetryUnitTest, TestFlightMode)
|
||||||
TEST(RxSpiExpressLrsTelemetryUnitTest, TestMspVersionRequest)
|
TEST(RxSpiExpressLrsTelemetryUnitTest, TestMspVersionRequest)
|
||||||
{
|
{
|
||||||
uint8_t request[15] = {238, 12, 122, 200, 234, 48, 0, 1, 1, 0, 0, 0, 0, 128, 0};
|
uint8_t request[15] = {238, 12, 122, 200, 234, 48, 0, 1, 1, 0, 0, 0, 0, 128, 0};
|
||||||
uint8_t response[12] = {200, 10, 123, 234, 200, 48, 3, 1, 0, API_VERSION_MAJOR, API_VERSION_MINOR, 255};
|
uint8_t response[12] = {200, 10, 123, 234, 200, 48, 3, 1, 0, API_VERSION_MAJOR, API_VERSION_MINOR, 85};
|
||||||
uint8_t data1[6] = {1, request[0], request[1], request[2], request[3], request[4]};
|
uint8_t data1[6] = {1, request[0], request[1], request[2], request[3], request[4]};
|
||||||
uint8_t data2[6] = {2, request[5], request[6], request[7], request[8], request[9]};
|
uint8_t data2[6] = {2, request[5], request[6], request[7], request[8], request[9]};
|
||||||
uint8_t data3[6] = {3, request[10], request[11], request[12], request[13], request[14]};
|
uint8_t data3[6] = {3, request[10], request[11], request[12], request[13], request[14]};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue