diff --git a/make/source.mk b/make/source.mk index d08c01e594..a7197a93a3 100644 --- a/make/source.mk +++ b/make/source.mk @@ -44,6 +44,7 @@ COMMON_SRC = \ drivers/io.c \ drivers/io_pca9685.c \ drivers/light_led.c \ + drivers/osd.c \ drivers/resource.c \ drivers/rx_nrf24l01.c \ drivers/rx_spi.c \ diff --git a/src/main/drivers/max7456.c b/src/main/drivers/max7456.c index dc6f4ee025..405db287c1 100644 --- a/src/main/drivers/max7456.c +++ b/src/main/drivers/max7456.c @@ -176,10 +176,9 @@ #define CHAR_MODE_EXT (1 << 2) #define CHAR_MODE_IS_EXT(m) ((m) & CHAR_MODE_EXT) -// we write everything in max7456ScreenBuffer and set a dirty bit -// in screenIsDirty to upgrade only changed chars this solution -// is faster than redrawing the whole screen on each frame -uint16_t max7456ScreenBuffer[MAX7456_BUFFER_CHARS_PAL] ALIGNED(4); +// we write everything in osdCharacterGridBuffer and set a dirty bit +// in screenIsDirty to update only changed chars. This solution +// is faster than redrawing the whole screen on each frame. static BITARRAY_DECLARE(screenIsDirty, MAX7456_BUFFER_CHARS_PAL); //max chars to update in one idle @@ -307,7 +306,7 @@ uint8_t max7456GetRowsCount(void) } //because MAX7456 need some time to detect video system etc. we need to wait for a while to initialize it at startup -//and in case of restart we need to reinitialize chip. Note that we can't touch max7456ScreenBuffer here, since +//and in case of restart we need to reinitialize chip. Note that we can't touch osdCharacterGridBuffer here, since //it might already have some data by the first time this function is called. static void max7456ReInit(void) { @@ -382,9 +381,9 @@ void max7456Init(const videoSystem_e videoSystem) state.registers.dmm = 0; state.videoSystem = videoSystem; - // Set max7456ScreenBuffer to all blanks - for (uint_fast16_t ii = 0; ii < ARRAYLEN(max7456ScreenBuffer); ii++) { - max7456ScreenBuffer[ii] = CHAR_BLANK; + // Set screen buffer to all blanks + for (uint_fast16_t ii = 0; ii < ARRAYLEN(osdCharacterGridBuffer); ii++) { + osdCharacterGridBuffer[ii] = CHAR_BLANK; } // Wait for software reset to finish @@ -409,9 +408,9 @@ void max7456Init(const videoSystem_e videoSystem) void max7456ClearScreen(void) { - for (uint_fast16_t ii = 0; ii < ARRAYLEN(max7456ScreenBuffer); ii++) { - if (max7456ScreenBuffer[ii] != CHAR_BLANK) { - max7456ScreenBuffer[ii] = CHAR_BLANK; + for (uint_fast16_t ii = 0; ii < ARRAYLEN(osdCharacterGridBuffer); ii++) { + if (osdCharacterGridBuffer[ii] != CHAR_BLANK) { + osdCharacterGridBuffer[ii] = CHAR_BLANK; bitArraySet(screenIsDirty, ii); } } @@ -421,8 +420,8 @@ void max7456WriteChar(uint8_t x, uint8_t y, uint16_t c, uint8_t mode) { unsigned pos = y * MAX7456_CHARS_PER_LINE + x; uint16_t val = MAKE_CHAR_MODE(c, mode); - if (max7456ScreenBuffer[pos] != val) { - max7456ScreenBuffer[pos] = val; + if (osdCharacterGridBuffer[pos] != val) { + osdCharacterGridBuffer[pos] = val; bitArraySet(screenIsDirty, pos); } } @@ -430,8 +429,8 @@ void max7456WriteChar(uint8_t x, uint8_t y, uint16_t c, uint8_t mode) bool max7456ReadChar(uint8_t x, uint8_t y, uint16_t *c, uint8_t *mode) { unsigned pos = y * MAX7456_CHARS_PER_LINE + x; - if (pos < ARRAYLEN(max7456ScreenBuffer)) { - uint16_t val = max7456ScreenBuffer[pos]; + if (pos < ARRAYLEN(osdCharacterGridBuffer)) { + uint16_t val = osdCharacterGridBuffer[pos]; *c = CHAR_BYTE(val); *mode = MODE_BYTE(val); if (CHAR_MODE_IS_EXT(*mode)) { @@ -454,8 +453,8 @@ void max7456Write(uint8_t x, uint8_t y, const char *buff, uint8_t mode) break; } c = MAKE_CHAR_MODE_U8(*buff, mode); - if (max7456ScreenBuffer[pos] != c) { - max7456ScreenBuffer[pos] = c; + if (osdCharacterGridBuffer[pos] != c) { + osdCharacterGridBuffer[pos] = c; bitArraySet(screenIsDirty, pos); } } @@ -482,8 +481,8 @@ static bool max7456DrawScreenPartial(void) uint8_t ph = pos >> 8; uint8_t pl = pos & 0xff; - charMode = MODE_BYTE(max7456ScreenBuffer[pos]); - uint8_t chr = CHAR_BYTE(max7456ScreenBuffer[pos]); + charMode = MODE_BYTE(osdCharacterGridBuffer[pos]); + uint8_t chr = CHAR_BYTE(osdCharacterGridBuffer[pos]); if (CHAR_MODE_IS_EXT(charMode)) { if (!DMM_IS_8BIT_MODE(state.registers.dmm)) { state.registers.dmm |= DMM_8BIT_MODE; @@ -621,8 +620,8 @@ void max7456RefreshAll(void) // Mark non-blank characters as dirty BITARRAY_CLR_ALL(screenIsDirty); - for (unsigned ii = 0; ii < ARRAYLEN(max7456ScreenBuffer); ii++) { - if (!CHAR_IS_BLANK(max7456ScreenBuffer[ii])) { + for (unsigned ii = 0; ii < ARRAYLEN(osdCharacterGridBuffer); ii++) { + if (!CHAR_IS_BLANK(osdCharacterGridBuffer[ii])) { bitArraySet(screenIsDirty, ii); } } diff --git a/src/main/drivers/max7456.h b/src/main/drivers/max7456.h index 9052862ce5..38ddd650c3 100644 --- a/src/main/drivers/max7456.h +++ b/src/main/drivers/max7456.h @@ -44,8 +44,6 @@ enum VIDEO_TYPES { AUTO = 0, PAL, NTSC }; #define MAX7456_MODE_BLINK (1 << 4) #define MAX7456_MODE_SOLID_BG (1 << 5) -extern uint16_t max7456ScreenBuffer[MAX7456_BUFFER_CHARS_PAL] ALIGNED(4); - void max7456Init(const videoSystem_e videoSystem); void max7456Update(void); void max7456ReadNvm(uint16_t char_address, osdCharacter_t *chr); diff --git a/src/main/drivers/osd.c b/src/main/drivers/osd.c new file mode 100644 index 0000000000..c7fbdb1136 --- /dev/null +++ b/src/main/drivers/osd.c @@ -0,0 +1,43 @@ +/* + * This file is part of INAV. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 3, as described below: + * + * This file is free software: you may copy, redistribute 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. + * + * This file 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 this program. If not, see http://www.gnu.org/licenses/. + * + */ + +#include "drivers/osd.h" + +uint16_t osdCharacterGridBuffer[OSD_CHARACTER_GRID_BUFFER_SIZE] ALIGNED(4); + +void osdCharacterGridBufferClear(void) +{ + uint32_t *ptr = (uint32_t *)osdCharacterGridBuffer; + uint32_t *end = (uint32_t *)(ARRAYEND(osdCharacterGridBuffer)); + for (; ptr < end; ptr++) { + *ptr = 0; + } +} + +uint16_t *osdCharacterGridBufferGetEntryPtr(unsigned x, unsigned y) +{ + unsigned pos = y * OSD_CHARACTER_GRID_MAX_WIDTH + x; + return &osdCharacterGridBuffer[pos]; +} diff --git a/src/main/drivers/osd.h b/src/main/drivers/osd.h index 895ddfc552..989bdd5a64 100644 --- a/src/main/drivers/osd.h +++ b/src/main/drivers/osd.h @@ -22,6 +22,8 @@ #include +#include "common/utils.h" + #define OSD_CHAR_WIDTH 12 #define OSD_CHAR_HEIGHT 18 #define OSD_CHAR_BITS_PER_PIXEL 2 @@ -57,3 +59,13 @@ typedef enum { typedef struct osdCharacter_s { uint8_t data[OSD_CHAR_BYTES]; } osdCharacter_t; + +#define OSD_CHARACTER_GRID_MAX_WIDTH 30 +#define OSD_CHARACTER_GRID_MAX_HEIGHT 16 +#define OSD_CHARACTER_GRID_BUFFER_SIZE (OSD_CHARACTER_GRID_MAX_WIDTH * OSD_CHARACTER_GRID_MAX_HEIGHT) + +extern uint16_t osdCharacterGridBuffer[OSD_CHARACTER_GRID_BUFFER_SIZE] ALIGNED(4); + +// Sets all buffer entries to 0 +void osdCharacterGridBufferClear(void); +uint16_t *osdCharacterGridBufferGetEntryPtr(unsigned x, unsigned y); diff --git a/src/main/io/frsky_osd.c b/src/main/io/frsky_osd.c index d437828138..3e552d87f6 100644 --- a/src/main/io/frsky_osd.c +++ b/src/main/io/frsky_osd.c @@ -13,7 +13,6 @@ #include "common/utils.h" #include "common/uvarint.h" -#include "drivers/max7456.h" #include "drivers/time.h" #include "io/frsky_osd.h" @@ -25,7 +24,6 @@ #define FRSKY_OSD_PREAMBLE_BYTE_0 '$' #define FRSKY_OSD_PREAMBLE_BYTE_1 'A' -#define FRSKY_OSD_GRID_BUFFER_POS(x, y) (y * MAX7456_CHARS_PER_LINE + x) #define FRSKY_OSD_GRID_BUFFER_CHAR_BITS 9 #define FRSKY_OSD_GRID_BUFFER_CHAR_MASK ((1 << FRSKY_OSD_GRID_BUFFER_CHAR_BITS) - 1) #define FRSKY_OSD_GRID_BUFFER_ENCODE(chr, attr) ((chr & FRSKY_OSD_GRID_BUFFER_CHAR_MASK) | (attr << FRSKY_OSD_GRID_BUFFER_CHAR_BITS)) @@ -694,18 +692,18 @@ void frskyOSDDrawStringInGrid(unsigned x, unsigned y, const char *buff, textAttr { unsigned charsUpdated = 0; const char *updatedCharAt = NULL; - unsigned pos = FRSKY_OSD_GRID_BUFFER_POS(x, y); + uint16_t *entry = osdCharacterGridBufferGetEntryPtr(x, y); const char *p; unsigned xx; - for (p = buff, xx = x; *p && xx < state.info.grid.columns; p++, pos++, xx++) { + for (p = buff, xx = x; *p && xx < state.info.grid.columns; p++, entry++, xx++) { unsigned val = FRSKY_OSD_GRID_BUFFER_ENCODE(*p, attr); - if (max7456ScreenBuffer[pos] != val) { + if (*entry != val) { if (++charsUpdated == 1) { // First character that needs to be updated, save it // in case we can issue a single update. updatedCharAt = p; } - max7456ScreenBuffer[pos] = val; + *entry = val; } } @@ -728,22 +726,21 @@ void frskyOSDDrawStringInGrid(unsigned x, unsigned y, const char *buff, textAttr void frskyOSDDrawCharInGrid(unsigned x, unsigned y, uint16_t chr, textAttributes_t attr) { - unsigned pos = FRSKY_OSD_GRID_BUFFER_POS(x, y); + uint16_t *entry = osdCharacterGridBufferGetEntryPtr(x, y); unsigned val = FRSKY_OSD_GRID_BUFFER_ENCODE(chr, attr); - if (max7456ScreenBuffer[pos] == val) { + if (*entry == val) { return; } frskyOSDSendCharInGrid(x, y, chr, attr); - max7456ScreenBuffer[pos] = val; + *entry = val; } bool frskyOSDReadCharInGrid(unsigned x, unsigned y, uint16_t *c, textAttributes_t *attr) { - unsigned pos = FRSKY_OSD_GRID_BUFFER_POS(x, y); - uint16_t val = max7456ScreenBuffer[pos]; + uint16_t val = *osdCharacterGridBufferGetEntryPtr(x, y); // We use the lower 10 bits for characters *c = val & FRSKY_OSD_GRID_BUFFER_CHAR_MASK; *attr = val >> FRSKY_OSD_GRID_BUFFER_CHAR_BITS; @@ -752,7 +749,7 @@ bool frskyOSDReadCharInGrid(unsigned x, unsigned y, uint16_t *c, textAttributes_ void frskyOSDClearScreen(void) { - memset(max7456ScreenBuffer, 0, sizeof(max7456ScreenBuffer)); + osdCharacterGridBufferClear(); frskyOSDSendAsyncCommand(OSD_CMD_DRAWING_CLEAR_SCREEN, NULL, 0); }