Piotr Lewandowski 2023-07-15 03:44:52 +02:00
rodzic aa7df02742
commit 35357269d0
10 zmienionych plików z 673 dodań i 19 usunięć

Wyświetl plik

@ -1,4 +1,5 @@
add_subdirectory(k5_uv_system)
add_subdirectory(lcd)
add_subdirectory(radio)
add_subdirectory(keyboard)
add_subdirectory(keyboard)
add_subdirectory(views)

Wyświetl plik

@ -0,0 +1,26 @@
set(NAME views)
add_library(${NAME} STATIC)
target_include_directories(${NAME} INTERFACE
.
)
target_include_directories(${NAME} PRIVATE
.
)
target_sources(${NAME} PRIVATE
views.cpp
)
target_link_libraries(${NAME}
uv_k5_system
lcd
keyboard
t9
radio
)
target_compile_options(${NAME} PRIVATE ${COMPILER_OPTIONS})

Wyświetl plik

@ -0,0 +1,101 @@
#pragma once
#include "views.hpp"
#include "system.hpp"
#include "keyboard.hpp"
#include "registers.hpp"
template <const System::TOrgFunctions &Fw,
const System::TOrgData &FwData,
unsigned char BackgroundViewPrescaler,
unsigned char MainViewPrescaler,
unsigned char RegisteredViews>
class CViewManager
{
friend class CKeyboard<CViewManager>;
IView* (&Modules)[RegisteredViews];
CViewStack MainViewStack;
TViewContext MainViewContext;
CKeyboard<CViewManager> Keyboard;
public:
constexpr CViewManager(IView* (&_Modules)[RegisteredViews])
: Modules(_Modules),
MainViewContext({&MainViewStack, 0, 0}),
Keyboard(*this)
{};
void Handle()
{
unsigned char u8ScreenRefreshFlag = 0;
if(!(MainViewContext.u32SystemCounter % BackgroundViewPrescaler))
{
u8ScreenRefreshFlag |= HandleBackgroundTasks();
}
auto* pViewStackTop = MainViewStack.GetTop();
if(pViewStackTop && !(MainViewContext.u32SystemCounter
% MainViewPrescaler))
{
Keyboard.Handle(Fw.PollKeyboard());
u8ScreenRefreshFlag |=
pViewStackTop->HandleMainView(MainViewContext);
}
if(u8ScreenRefreshFlag & eScreenRefreshFlag::MainScreen)
{
Fw.FlushFramebufferToScreen();
}
if(u8ScreenRefreshFlag & eScreenRefreshFlag::StatusBar)
{
Fw.FlushStatusbarBufferToScreen();
}
MainViewContext.u32SystemCounter++;
}
private:
inline unsigned char HandleBackgroundTasks()
{
unsigned char u8ScreenRefreshFlag = 0;
for(auto& pModule : Modules)
{
if(!pModule)
{
continue;
}
u8ScreenRefreshFlag |= pModule->Handle(MainViewContext);
}
return u8ScreenRefreshFlag;
}
inline void CheckOriginalFwStatus()
{
const auto *pMenuCheckData = (unsigned char *)(FwData.pDisplayBuffer + 2*128 + 6 * 8 + 1);
const auto *pFrequencyScanCheckData = (unsigned char *)(FwData.pDisplayBuffer + 6*128 + 3 * 8 + 2);
MainViewContext.OriginalFwStatus.b1MenuDrawed = *pMenuCheckData == 0xFF;
MainViewContext.OriginalFwStatus.b1FrequencyScan = *pFrequencyScanCheckData;
MainViewContext.OriginalFwStatus.b1RadioSpiCommInUse = !(GPIOC->DATA & 0b1);
}
void HandlePressedButton(unsigned char u8Key)
{
auto* const pTop = MainViewStack.GetTop();
if(pTop)
{
pTop->HandlePressedButton(u8Key);
}
}
void HandleReleasedButton(unsigned char u8Key)
{
auto* const pTop = MainViewStack.GetTop();
if(pTop)
{
pTop->HandleReleasedButton(u8Key);
}
}
};

Wyświetl plik

@ -0,0 +1,178 @@
#pragma once
#include "system.hpp"
#include "uv_k5_display.hpp"
#include "t9.hpp"
#include "radio.hpp"
#include "manager.hpp"
template <
TUV_K5Display &DisplayBuff,
const System::TOrgFunctions &Fw,
const System::TOrgData &FwData,
Radio::CBK4819<Fw> &RadioDriver>
class CMessenger : public Radio::IRadioUser, public IView
{
public:
static constexpr auto MaxCharsInLine = 128 / 8;
enum class eState : unsigned char
{
InitFirst,
InitRx,
InitTx,
RxDone,
WaitForRx,
};
CMessenger()
: T9(S8TxBuff),
bDisplayCleared(true),
bEnabled(0),
State(eState::InitRx),
u8RxDoneLabelCnt(0xFF){};
void Handle()
{
if (!(GPIOC->DATA & 0b1))
{
return;
}
if (!FreeToDraw())
{
if (!bDisplayCleared)
{
bDisplayCleared = true;
ClearDrawings();
Fw.FlushFramebufferToScreen();
}
return;
}
if (bDisplayCleared)
{
}
char C8PrintBuff[30];
bDisplayCleared = false;
ClearDrawings();
Display.DrawHLine(3, 3 + 10, 1 * 8 + T9.GetIdx() * 8 + 2);
// print tx data
Fw.FormatString(C8PrintBuff, ">%s", T9.C8WorkingBuff);
Fw.PrintTextOnScreen(C8PrintBuff, 0, 128, 0, 8, 0);
// print rx data
char C8Temp = S8RxBuff[MaxCharsInLine];
S8RxBuff[MaxCharsInLine] = '\0';
Fw.PrintTextOnScreen(S8RxBuff, 1, 128, 3, 8, 0);
S8RxBuff[MaxCharsInLine] = C8Temp;
Fw.PrintTextOnScreen(S8RxBuff + MaxCharsInLine, 1, 128, 5, 8, 0);
Display.DrawRectangle(0, (8 * 4) - 6, 127, 24 + 6, false);
if (u8RxDoneLabelCnt < 100)
{
u8RxDoneLabelCnt++;
Fw.PrintTextOnScreen(" >> RX << ", 0, 128, 2, 8, 1);
}
switch (State)
{
case eState::InitRx:
{
InitRxHandler();
break;
}
case eState::InitTx:
{
static unsigned char u8TxDelay = 0;
if (u8TxDelay++ >= 1)
{
u8TxDelay = 0;
RadioDriver.SendSyncAirCopyMode72((unsigned char *)S8TxBuff);
State = eState::InitRx;
}
Fw.PrintTextOnScreen(" >> TX << ", 0, 128, 2, 8, 1);
break;
}
default:
break;
}
Fw.FlushFramebufferToScreen();
}
void RxDoneHandler(unsigned char u8DataLen, bool bCrcOk) override
{
bEnabled = true;
State = eState::InitRx;
u8RxDoneLabelCnt = 0;
}
private:
bool
FreeToDraw()
{
bool bFlashlight = (GPIOC->DATA & GPIO_PIN_3);
if (bFlashlight)
{
bEnabled = true;
GPIOC->DATA &= ~GPIO_PIN_3;
*FwData.p8FlashLightStatus = 3;
}
if (bEnabled)
{
// Keyboard.Handle(Fw.PollKeyboard());
}
return bEnabled;
}
void InitRxHandler()
{
RadioDriver.RecieveAsyncAirCopyMode((unsigned char *)S8RxBuff, sizeof(S8RxBuff), this);
State = eState::WaitForRx;
}
void ClearDrawings()
{
memset(FwData.pDisplayBuffer, 0, (DisplayBuff.SizeX / 8) * DisplayBuff.SizeY);
}
void HandlePressedButton(unsigned char u8Button) override
{
}
void HandleReleasedButton(unsigned char u8Button) override
{
if (u8Button == 10)
{
State = eState::InitTx;
return;
}
if (u8Button == 13 && !T9.GetIdx())
{
bEnabled = false;
return;
}
T9.ProcessButton(u8Button);
}
char S8TxBuff[50];
char S8RxBuff[72];
CDisplay<const TUV_K5Display> Display;
CT9Decoder<sizeof(S8TxBuff)> T9;
bool bDisplayCleared;
unsigned char u8LastBtnPressed;
bool bEnabled;
eState State;
unsigned char u8RxDoneLabelCnt;
};

Wyświetl plik

@ -0,0 +1,104 @@
#pragma once
#include "system.hpp"
#include "uv_k5_display.hpp"
#include "manager.hpp"
template <
System::TOrgFunctions &Fw,
System::TOrgData &FwData,
TUV_K5Display &DisplayBuff,
CDisplay<TUV_K5Display> &Display,
TUV_K5SmallNumbers &FontSmallNr>
class CRssiPrinter : public IView
{
public:
static constexpr auto ChartStartX = 4 * 7 + 4;
eScreenRefreshFlag HandleBackground(TViewContext &Context) override
{
static bool bIsCleared = true;
static unsigned char u8ChartPosition = 0;
static unsigned char u8SqlDelayCnt = 0xFF;
static unsigned char U8ScreenHistory[128 - ChartStartX] = {0};
if (Context.OriginalFwStatus.b1RadioSpiCommInUse)
{
return eScreenRefreshFlag::NoRefresh;
}
if (Fw.BK4819Read(0x0C) & 0b10)
{
u8SqlDelayCnt = 0;
}
if (u8SqlDelayCnt > 20 || Context.OriginalFwStatus.b1MenuDrawed)
{
if (!bIsCleared)
{
bIsCleared = true;
auto *pDData = (unsigned char *)DisplayBuff.GetCoursorData(DisplayBuff.GetCoursorPosition(3, 0));
memset(pDData, 0, DisplayBuff.SizeX);
memset(U8ScreenHistory, 0, sizeof(U8ScreenHistory));
u8ChartPosition = 0;
if (!Context.OriginalFwStatus.b1MenuDrawed)
{
return eScreenRefreshFlag::MainScreen;
}
}
return eScreenRefreshFlag::NoRefresh;
}
u8SqlDelayCnt++;
bIsCleared = false;
Display.SetCoursor(3, 0);
Display.SetFont(&FontSmallNr);
char C8RssiString[] = "g000";
unsigned char u8Rssi = ((Fw.BK4819Read(0x67) >> 1) & 0xFF);
if (!u8Rssi)
{
return eScreenRefreshFlag::NoRefresh;
}
if (u8Rssi > 160)
{
u8Rssi -= 160;
C8RssiString[0] = ' ';
}
else
{
u8Rssi = 160 - u8Rssi;
C8RssiString[0] = '-';
}
C8RssiString[1] = '0' + u8Rssi / 100;
C8RssiString[2] = '0' + (u8Rssi / 10) % 10;
C8RssiString[3] = '0' + u8Rssi % 10;
Display.Print(C8RssiString);
if (u8ChartPosition < ChartStartX || u8ChartPosition >= TUV_K5Display::SizeX)
u8ChartPosition = ChartStartX;
unsigned char u8Sub = (u8Rssi * 7) >> 7;
unsigned char u8PrintShift = (u8Sub > 7 ? 7 : u8Sub);
// Turn the proper pixel on, and the ones below it on as well
// The code to turn just the correct pixel on is: U8ScreenHistory[u8ChartPosition - ChartStartX] = (1 << u8PrintShift) & 0xFF;
U8ScreenHistory[u8ChartPosition - ChartStartX] = ~(0xFF >> (7 - u8PrintShift));
if (u8ChartPosition + 4 < DisplayBuff.SizeX)
{
for (unsigned char i = 0; i < 4; i++)
{
U8ScreenHistory[u8ChartPosition - ChartStartX + i + 1] = 0;
}
}
auto *pDData = (unsigned char *)DisplayBuff.GetCoursorData(DisplayBuff.GetCoursorPosition(3, 0) + ChartStartX);
memcpy(pDData, U8ScreenHistory, sizeof(U8ScreenHistory));
u8ChartPosition++;
return eScreenRefreshFlag::MainScreen;
}
};

Wyświetl plik

@ -0,0 +1,187 @@
#pragma once
#include "system.hpp"
#include "uv_k5_display.hpp"
namespace Rssi
{
inline const unsigned char U8RssiMap[] =
{
141,
135,
129,
123,
117,
111,
105,
99,
93,
83,
73,
63,
53,
};
struct TRssi
{
TRssi(unsigned char u8Val)
{
unsigned char i;
for (i = 0; i < sizeof(U8RssiMap); i++)
{
if (u8Val >= U8RssiMap[i])
{
u8SValue = i + 1;
return;
}
}
u8SValue = i + 1;
}
unsigned char u8SValue;
};
}
template <
System::TOrgFunctions &Fw,
System::TOrgData &FwData,
TUV_K5Display &DisplayBuff,
CDisplay<TUV_K5Display> &Display,
TUV_K5SmallNumbers &FontSmallNr>
class CRssiSbar
{
public:
static constexpr auto ChartStartX = 5 * 7 + 8 + 3 * 7; // 32;
static constexpr auto BlockSizeX = 4;
static constexpr auto BlockSizeY = 7;
static constexpr auto BlockSpace = 1;
static constexpr auto BlocksCnt = (128 - ChartStartX) / (BlockSizeX + BlockSpace);
static constexpr auto LinearBlocksCnt = 9;
static constexpr auto VoltageOffset = 77;
eScreenRefreshFlag HandleBackground(TViewContext &Context) override
{
static bool bIsCleared = true;
static unsigned char u8SqlDelayCnt = 0xFF;
TUV_K5Display StatusBarBuff(FwData.pStatusBarData);
CDisplay<TUV_K5Display> DisplayStatusBar(StatusBarBuff);
DisplayStatusBar.SetFont(&FontSmallNr);
if (Context.OriginalFwStatus.b1RadioSpiCommInUse)
{
return eScreenRefreshFlag::NoRefresh;
}
static unsigned int u32DrawVoltagePsc = 0;
if (u32DrawVoltagePsc++ % 16)
{
memset(FwData.pStatusBarData + VoltageOffset, 0, 4 * 5);
DisplayStatusBar.SetCoursor(0, VoltageOffset);
DisplayStatusBar.PrintFixedDigitsNumber2(*FwData.p16Voltage, 2, 1);
memset(FwData.pStatusBarData + VoltageOffset + 7 + 1, 0b1100000, 2); // dot
DisplayStatusBar.SetCoursor(0, VoltageOffset + 7 + 4);
DisplayStatusBar.PrintFixedDigitsNumber2(*FwData.p16Voltage, 0, 2);
memcpy(FwData.pStatusBarData + VoltageOffset + 4 * 6 + 2, FwData.pSmallLeters + 128 * 2 + 102, 5); // V character
Fw.FlushStatusbarBufferToScreen();
}
if (Fw.BK4819Read(0x0C) & 0b10)
{
u8SqlDelayCnt = 0;
}
auto *pDData = (unsigned char *)DisplayBuff.GetCoursorData(DisplayBuff.GetCoursorPosition(3, 0));
if (u8SqlDelayCnt > 20 || Context.OriginalFwStatus.b1MenuDrawed)
{
if (!bIsCleared)
{
bIsCleared = true;
memset(pDData, 0, DisplayBuff.SizeX);
if (!Context.OriginalFwStatus.b1MenuDrawed)
{
return eScreenRefreshFlag::MainScreen;
}
}
return eScreenRefreshFlag::NoRefresh;
}
u8SqlDelayCnt++;
bIsCleared = false;
memset(pDData, 0, DisplayBuff.SizeX);
Display.SetCoursor(3, 0);
Display.SetFont(&FontSmallNr);
char C8RssiString[] = "g000";
unsigned char u8Rssi = ((Fw.BK4819Read(0x67) >> 1) & 0xFF);
if (!u8Rssi)
{
return eScreenRefreshFlag::NoRefresh;
}
if (u8Rssi > 160)
{
u8Rssi -= 160;
}
else
{
u8Rssi = 160 - u8Rssi;
C8RssiString[0] = '-';
}
u8Rssi += 10;
unsigned char u8RssiCpy = u8Rssi;
unsigned char hundreds = 0;
while (u8RssiCpy >= 100)
{
hundreds++;
u8RssiCpy -= 100;
}
unsigned char tens = 0;
while (u8RssiCpy >= 10)
{
tens++;
u8RssiCpy -= 10;
}
C8RssiString[1] = '0' + hundreds;
C8RssiString[2] = '0' + tens;
C8RssiString[3] = '0' + u8RssiCpy;
Display.Print(C8RssiString);
unsigned char u8Sub = (u8Rssi * BlocksCnt) >> 7;
unsigned char u8BlocksToFill = (u8Sub > BlocksCnt ? BlocksCnt : u8Sub);
u8BlocksToFill = Rssi::TRssi(u8Rssi).u8SValue;
char C8SignalString[] = " ";
if (u8BlocksToFill > 9)
{
memcpy(pDData + 5 * 7, FwData.pSmallLeters + 109 - 3 * 8, 8);
C8SignalString[1] = '0';
C8SignalString[0] = '0' + u8BlocksToFill - 9;
}
else
{
memcpy(pDData + 5 * 7, FwData.pSmallLeters + 109, 8);
C8SignalString[0] = '0' + u8BlocksToFill;
C8SignalString[1] = ' ';
}
Display.SetCoursor(3, 5 * 7 + 8);
Display.Print(C8SignalString);
u8BlocksToFill = u8BlocksToFill > 13 ? 13 : u8BlocksToFill;
for (unsigned char i = 0; i < u8BlocksToFill; i++)
{
unsigned char u8BlockHeight = i + 1 > BlockSizeY ? BlockSizeY : i + 1;
unsigned char u8X = i * (BlockSizeX + BlockSpace) + ChartStartX;
Display.DrawRectangle(u8X, 24 + BlockSizeY - u8BlockHeight, BlockSizeX,
u8BlockHeight, i < LinearBlocksCnt);
}
return eScreenRefreshFlag::MainScreen;
}
};

Wyświetl plik

@ -0,0 +1,5 @@
#include "views.hpp"
#include "manager.hpp"
#include "rssi_printer.hpp"
#include "rssi_sbar.hpp"
#include "messenger.hpp"

Wyświetl plik

@ -0,0 +1,70 @@
#pragma once
enum eScreenRefreshFlag : unsigned char
{
NoRefresh = 0,
StatusBar = 0b01,
MainScreen = 0b10,
};
class CViewStack;
struct TViewContext
{
CViewStack* pViewStack;
unsigned int u32SystemCounter;
union
{
unsigned char u8Status;
struct
{
unsigned char b1MenuDrawed : 1;
unsigned char b1LockScreen : 1;
unsigned char b1FrequencyScan : 1;
unsigned char b1RadioSpiCommInUse : 1;
};
}OriginalFwStatus;
};
struct IView
{
IView* pNext;
// only called by manager only when on top of view stack
virtual eScreenRefreshFlag HandleMainView(TViewContext& Context) {return eScreenRefreshFlag::NoRefresh;}
// always called, can be used to update some notifications on status bar
virtual eScreenRefreshFlag HandleBackground(TViewContext& Context) {return eScreenRefreshFlag::NoRefresh;}
virtual void HandlePressedButton(unsigned char u8Key) {};
virtual void HandleReleasedButton(unsigned char u8Key) {};
};
class CViewStack
{
IView* pTop;
public:
CViewStack():pTop(nullptr){};
void Push(IView& View)
{
View.pNext = pTop;
pTop = &View;
}
IView* Pop()
{
auto* const pPopek = pTop;
if(pTop)
{
pTop = pTop->pNext;
pPopek->pNext = nullptr;
}
return pPopek;
}
IView* GetTop()
{
return pTop;
}
};

Wyświetl plik

@ -1,17 +0,0 @@
#include "registers.hpp"
class CExec final
{
public:
CExec(){};
void InterruptCallback()
{
CheckButtons();
}
private:
void CheckButtons() const
{
}
};

Wyświetl plik

@ -1,5 +1,4 @@
#pragma once
#include "system.hpp"
#include "uv_k5_display.hpp"
#include "keyboard.hpp"
#include "radio.hpp"