From 35ea0ac4f23673b0c6f4862b18549785543740c3 Mon Sep 17 00:00:00 2001 From: ClockSelect Date: Tue, 16 Mar 2021 09:27:19 +0100 Subject: [PATCH] sources first commit --- inc/aegis.h | 234 ++++++++++ inc/devices.h | 45 ++ inc/display.h | 53 +++ inc/font.h | 31 ++ inc/printf.h | 117 +++++ inc/printf_config.h | 7 + inc/screens.h | 13 + notes.txt | 11 +- src/ST7735S.c | 439 ++++++++++++++++++ src/aegis.s | 117 +++++ src/battery.c | 66 +++ src/devices.c | 235 ++++++++++ src/display.c | 106 +++++ src/events.c | 188 ++++++++ src/font.c | 464 +++++++++++++++++++ src/init.c | 82 ++++ src/inputs.c | 400 +++++++++++++++++ src/main.c | 86 ++++ src/printf.c | 914 ++++++++++++++++++++++++++++++++++++++ src/screens.c | 185 ++++++++ src/screens/screen_main.c | 59 +++ src/startup_NUC1261.s | 230 ++++++++++ src/system.c | 288 ++++++++++++ 23 files changed, 4366 insertions(+), 4 deletions(-) create mode 100644 inc/aegis.h create mode 100644 inc/devices.h create mode 100644 inc/display.h create mode 100644 inc/font.h create mode 100644 inc/printf.h create mode 100644 inc/printf_config.h create mode 100644 inc/screens.h create mode 100644 src/ST7735S.c create mode 100644 src/aegis.s create mode 100644 src/battery.c create mode 100644 src/devices.c create mode 100644 src/display.c create mode 100644 src/events.c create mode 100644 src/font.c create mode 100644 src/init.c create mode 100644 src/inputs.c create mode 100644 src/main.c create mode 100644 src/printf.c create mode 100644 src/screens.c create mode 100644 src/screens/screen_main.c create mode 100644 src/startup_NUC1261.s create mode 100644 src/system.c diff --git a/inc/aegis.h b/inc/aegis.h new file mode 100644 index 0000000..973ab75 --- /dev/null +++ b/inc/aegis.h @@ -0,0 +1,234 @@ +#ifndef __AEGIS_H__ +#define __AEGIS_H__ +//============================================================================== +// aegis/inc/aegis.h +//------------------------------------------------------------------------------ +// Constants, Type definitions and Function prototypes +// for the Aegis Legend firmware. +//============================================================================== + +#include + +#include "printf.h" +#include "devices.h" +#include "font.h" +#include "display.h" + + +//------------------------------------------------------------------------------ +// Battery Voltage Offsets +// Correction values from ADC readings (mV) +//------------------------------------------------------------------------------ +// Those values may vary from box to box. One may test the voltage values +// delivered by the ADC with accurate voltmeter measures to find out the +// exact values needed for his specific box. +//------------------------------------------------------------------------------ +#define BVO_CELL1 (+40) +#define BVO_CELL2 (-65) +#define BVO_USB (+365) + + +//------------------------------------------------------------------------------ +// Input buttons GPIO ports +//------------------------------------------------------------------------------ +#define BTN_FIRE PE10 +#define BTN_MINUS PE13 +#define BTN_PLUS PD0 + + +//------------------------------------------------------------------------------ +// Events constants +//------------------------------------------------------------------------------ + +typedef enum eEvent +{ + EVENT_NULL = 0, // Null event + EVENT_KEY, // Key input event + EVENT_DISPLAY, // Display event + EVENT_MAX // Total number of event types +} +Event_e; + +typedef enum eEV_K +{ + EV_K_NULL = 0, + EV_K_FIRE, // Fire Button + EV_K_PLUS, // (+) Button + EV_K_MINUS, // (-) Button + EV_K_FP, // ( Fire, + ) + EV_K_FM, // ( Fire, - ) + EV_K_MP, // ( +, - ) + EV_K_FMP, // ( Fire, +, - ) + EV_K_TEST, // { ---+++ } + EV_K_ONOFF // 5 * Fire +} +EV_K_e; + +typedef enum eEV_D +{ + EV_D_NULL = 0, + EV_D_DISPLAY_STATUS, // Display on/off/sleep + EV_D_SCREEN, // Invoke screen + EV_D_BRIGHTNESS // Set screen brightness +} +EV_D_e; + + +//------------------------------------------------------------------------------ +// Event structure +//------------------------------------------------------------------------------ +// An event consist of four bytes: +// - The event type ( Key, screen, system, ... ) +// - The event subtype, depending on the event type ( Key id, ... ) +// - Two parameters, p1 and p2, depending on the event. +//------------------------------------------------------------------------------ +// Depending on the situation, events may be passed over as a pointer on an +// event structure or as a 32 bits integer, wichever is handiest. +//------------------------------------------------------------------------------ +typedef struct sEvent +{ + Event_e type; + union { + EV_K_e k; + EV_D_e d; + uint8_t id; + }; + uint8_t p1; + uint8_t p2; +} +Event_t; + +// Enforce a 4-bytes structure. +_Static_assert( sizeof(Event_t) == 4 , "Bad event structure size" ); + +// Build an integer event from 4 bytes. +#define EVENT(a,b,c,d) ((uint32_t)(((uint32_t)(d)) << 24 | \ + ((uint32_t)((uint8_t)(c))) << 16 | \ + ((uint32_t)((uint8_t)(b))) << 8 | \ + ((uint8_t)(a)))) + +// Send event after some time delay +#define DELAYED_EVENT(t,a,b,c,d) \ + TMCreateTask(t,(void(*)(uint32_t))EMSendEventInt,EVENT(a,b,c,d),0,0,0) + + +//------------------------------------------------------------------------------ +// Event management +//------------------------------------------------------------------------------ + +extern void EMStartup(); +extern int EMSendEvent( const Event_t *ev ); +extern int EMSendEventInt( const uint32_t ev ); +extern int EMSendEventNP( Event_e type, uint8_t id ); +extern int EMSendEvent1P( Event_e type, uint8_t id, uint8_t p1 ); +extern int EMSendEvent2P( Event_e type, uint8_t id, uint8_t p1, uint8_t p2 ); +extern int EMEventsPending(); +extern int EMGetNextEvent( Event_t *ev ); +extern void EMHandleEvents(); + + +//------------------------------------------------------------------------------ +// System miscs +//------------------------------------------------------------------------------ + +typedef enum eSysRbStatus +{ + RB_UNUSED = 0, + RB_AVAIL, + RB_FULL +} +SYS_RB_STATUS; + +#define SYS_MAX_RINGBUFFERS 1 // Maximum number of ringbuffers + +extern void RBStartup( void ); +extern int RBAlloc( void *buf, size_t bs, size_t ps ); +extern void RBReset( int rbid ); +extern int RBSendMessage( int rbid, const void *msg ); +extern int RBReadMessage( int rbid, void *msg ); +extern int RBHasMessages( int rbid ); + + +typedef enum eSysTaskStatus +{ + TASK_UNUSED = 0, + TASK_ACTIVE +} +SYS_TASK_STATUS; + +#define SYS_MAX_TASKS 10 // Maximum number of running tasks + +extern void TMStartup(); +extern int TMCreateTask( uint32_t delay, + void (*pftask)( uint32_t ), + uint32_t param, + uint8_t repeat, + uint32_t interval, + uint8_t *pid ); +extern void TMDestroyTask( uint8_t id ); +extern void TMUpdateTask( uint8_t id, uint32_t param, uint32_t delay ); +extern void TMExecTasks(); + + +//------------------------------------------------------------------------------ +// User inputs +//------------------------------------------------------------------------------ + +extern void ReadUserInputs( void ); + + +//------------------------------------------------------------------------------ +// Screen Management +//------------------------------------------------------------------------------ + +typedef enum eScreenId +{ + SCREEN_OFF = 0, + SCREEN_MAIN +} +SCREENID; + +extern void SMStartup( void ); +extern void SMScreen( SCREENID s ); +extern void SMShowScreen( SCREENID s ); +extern void SMRefresh( void ); +extern int SMInputEvent( Event_t *ev ); + + +//------------------------------------------------------------------------------ +// Battery Management +//------------------------------------------------------------------------------ + +extern void BMStartup( void ); +extern void BMUpdateBattery( void ); +extern void BMReadBattery( void ); +extern void BMGetCells( uint32_t *v1, uint32_t *v2 ); + + +//------------------------------------------------------------------------------ +// Timings (in ticks) (1 tick = 1ms) +//------------------------------------------------------------------------------ + +#define TI_POLL_INPUT 2 // User inputs (keys) polling interval +#define TI_EVENT_HANDLING 5 // Max time spent in event handling +#define TI_USB_TEST 10 // Test USB plug +#define TI_KEY_REPEAT 50 // Key repeat period +#define TI_SEQUENCE_TIMEOUT 500 // Max interval between keys in a sequence +#define TI_UPDATE_BATTERY 10 // Battery sampling interval + + +//============================================================================== +// Miscs Externs & Prototypes +//------------------------------------------------------------------------------ + +extern volatile uint32_t TickCounter; +static inline uint32_t GetSysTick( void ) { return TickCounter; }; +extern void WaitTicks( uint32_t ticks ); +extern void WaitUs( uint32_t us ); +extern void ResetChip( int ); + +extern uint32_t isqrt( uint32_t ); + + +//============================================================================== +#endif /* __AEGIS_H__ */ diff --git a/inc/devices.h b/inc/devices.h new file mode 100644 index 0000000..39113f1 --- /dev/null +++ b/inc/devices.h @@ -0,0 +1,45 @@ +#ifndef __DEVICES_H__ +#define __DEVICES_H__ + + +#define ADC_VREF 3300 + +#define ADC_CH_BATT_TOTAL 0 +#define ADC_CH_BOARD_TEMP 3 +#define ADC_CH_BATT_CELL1 4 +#define ADC_CH_BATT_CURR 13 +#define ADC_CH_COIL_CURR 14 +#define ADC_CH_COIL_VOLT 15 + + +#define PWM_CH_LCD 2 +#define PWM_CH_LCD_MASK (1< +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Output a character to a custom device like UART, used by the printf() function + * This function is declared here only. You have to write your custom implementation somewhere + * \param character Character to output + */ +void _putchar(char character); + + +/** + * Tiny printf implementation + * You have to implement _putchar if you use printf() + * To avoid conflicts with the regular printf() API it is overridden by macro defines + * and internal underscore-appended functions like printf_() are used + * \param format A string that specifies the format of the output + * \return The number of characters that are written into the array, not counting the terminating null character + */ +#define printf printf_ +int printf_(const char* format, ...); + + +/** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! + * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +#define sprintf sprintf_ +int sprintf_(char* buffer, const char* format, ...); + + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that COULD have been written into the buffer, not counting the terminating + * null character. A value equal or larger than count indicates truncation. Only when the returned value + * is non-negative and less than count, the string has been completely written. + */ +#define snprintf snprintf_ +#define vsnprintf vsnprintf_ +int snprintf_(char* buffer, size_t count, const char* format, ...); +int vsnprintf_(char* buffer, size_t count, const char* format, va_list va); + + +/** + * Tiny vprintf implementation + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +#define vprintf vprintf_ +int vprintf_(const char* format, va_list va); + + +/** + * printf with output function + * You may use this as dynamic alternative to printf() with its fixed _putchar() output + * \param out An output function which takes one character and an argument pointer + * \param arg An argument pointer for user data passed to output function + * \param format A string that specifies the format of the output + * \return The number of characters that are sent to the output function, not counting the terminating null character + */ +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); + + +#ifdef __cplusplus +} +#endif + + +#endif // _PRINTF_H_ diff --git a/inc/printf_config.h b/inc/printf_config.h new file mode 100644 index 0000000..4b1e6db --- /dev/null +++ b/inc/printf_config.h @@ -0,0 +1,7 @@ +#ifndef __PRINTF_CONFIG_H__ +#define __PRINTF_CONFIG_H__ +#define PRINTF_DISABLE_SUPPORT_FLOAT +#define PRINTF_DISABLE_SUPPORT_EXPONENTIAL +#define PRINTF_DISABLE_SUPPORT_LONG_LONG +#define PRINTF_DISABLE_SUPPORT_PTRDIFF_T +#endif /* __PRINTF_CONFIG_H__ */ diff --git a/inc/screens.h b/inc/screens.h new file mode 100644 index 0000000..ceba771 --- /dev/null +++ b/inc/screens.h @@ -0,0 +1,13 @@ +//============================================================================== +// aegis/src/screens/screens.h +//------------------------------------------------------------------------------ +// Screens +//============================================================================== +#include "aegis.h" + + +extern void ScrMainInit( void ); +extern int ScrMainDraw( void ); +extern int ScrMainRefresh( void ); +extern void ScrMainClose( void ); +extern int ScrMainEvent( Event_t *ev ); diff --git a/notes.txt b/notes.txt index d41ec77..9409052 100644 --- a/notes.txt +++ b/notes.txt @@ -135,11 +135,11 @@ Config = 0x55AA55AA + Config Data (52) + CRC32( config data ) 29 8 CoilResistance 30 8 Coil Current 31 8 Coil Voltage -32 8 Battery Cell 1 (Firing) -33 8 Battery Cell 2 (Firing) +32 8 Battery Cell 1 (Idle state) +33 8 Battery Cell 2 (Idle state) 34 8 35 8 -36 8 Battery Total +36 8 Battery Total (Idle state) 37 1 Atomizer Status (0:Unk,1:Low,3:Ok,4:High,5:NoAto) 38 4 Coil Resistance (Average of #29) 39 4 Coil Current (Average of #30) @@ -154,7 +154,7 @@ Config = 0x55AA55AA + Config Data (52) + CRC32( config data ) 48 4 Battery Cell 2 49 4 50 4 -51 4 Battery Total? +51 4 Battery Total 52 4 Battery Cell 1 (Average of #47) 53 4 Battery Cell 2 (Average of #48) 54 4 @@ -262,6 +262,9 @@ Events 6 6 6 7 + 9 1 + 9 2 + Key Events Parameters H 1 Key Down 2..4 Hold Time T1/T2/T3 diff --git a/src/ST7735S.c b/src/ST7735S.c new file mode 100644 index 0000000..68d7556 --- /dev/null +++ b/src/ST7735S.c @@ -0,0 +1,439 @@ +//============================================================================== +// aegis/src/ST7735S.c +//------------------------------------------------------------------------------ +// Display management +//============================================================================== +#include "aegis.h" + + +//------------------------------------------------------------------------------ +// Initialization sequence +//------------------------------------------------------------------------------ + +struct c_or_d_byte +{ + uint8_t c_or_d; + uint8_t byte; +}; + +static const struct c_or_d_byte init_sequence[] = +{ + { 0, 0x21 }, // INVON + { 0, 0xB1 }, // FRMCTR1 + { 1, 0x05 }, + { 1, 0x3A }, + { 1, 0x3A }, + { 0, 0xB2 }, // FRMCTR2 + { 1, 0x05 }, + { 1, 0x3A }, + { 1, 0x3A }, + { 0, 0xB3 }, // FRMCTR3 + { 1, 0x05 }, + { 1, 0x3A }, + { 1, 0x3A }, + { 1, 0x05 }, + { 1, 0x3A }, + { 1, 0x3A }, + { 0, 0xB4 }, // INVCTR + { 1, 0x03 }, + { 0, 0xC0 }, // PWCTR1 + { 1, 0x62 }, + { 1, 0x02 }, + { 1, 0x04 }, + { 0, 0xC1 }, // PWCTR2 + { 1, 0xC0 }, + { 0, 0xC2 }, // PWCTR3 + { 1, 0x0D }, + { 1, 0x00 }, + { 0, 0xC3 }, // PWCTR4 + { 1, 0x8D }, + { 1, 0x6A }, + { 0, 0xC4 }, // PWCTR5 + { 1, 0x8D }, + { 1, 0xEE }, + { 0, 0xC5 }, // VMCTR1 + { 1, 0x0E }, + { 0, 0xE0 }, // GMCTRP1 + { 1, 0x10 }, + { 1, 0x0E }, + { 1, 0x02 }, + { 1, 0x03 }, + { 1, 0x0E }, + { 1, 0x07 }, + { 1, 0x02 }, + { 1, 0x07 }, + { 1, 0x0A }, + { 1, 0x12 }, + { 1, 0x27 }, + { 1, 0x37 }, + { 1, 0x00 }, + { 1, 0x0D }, + { 1, 0x0E }, + { 1, 0x10 }, + { 0, 0xE1 }, // GMCTRN1 + { 1, 0x10 }, + { 1, 0x0E }, + { 1, 0x03 }, + { 1, 0x03 }, + { 1, 0x0F }, + { 1, 0x06 }, + { 1, 0x02 }, + { 1, 0x08 }, + { 1, 0x0A }, + { 1, 0x13 }, + { 1, 0x26 }, + { 1, 0x36 }, + { 1, 0x00 }, + { 1, 0x0D }, + { 1, 0x0E }, + { 1, 0x10 }, + { 0, 0x3A }, // COLMOD + { 1, 0x05 }, // 16-bit/pixel + { 0, 0x36 }, // MADCTL + { 1, 0xC0 } +}; + + +static uint16_t drawing_color; +static const font_t *font; + + +static int send_bytes( uint8_t *bytes, uint32_t len, uint32_t timeout ) +{ + int r = 0; + uint32_t start_tick = GetSysTick(); + + while ( len && !r ) + { + while ( SPI_GET_TX_FIFO_FULL_FLAG( SPI0 ) ) + { + if ( GetSysTick() - start_tick > timeout ) + { + r = 3; + break; + } + } + SPI_WRITE_TX( SPI0, *bytes++ ); + --len; + } + while ( SPI_IS_BUSY( SPI0 ) ) + ; + return r; +} + +static int send_cmd_byte( uint8_t cmd ) +{ + int r; + DISP_CSX = 0; + DISP_DCX = 0; + r = send_bytes( &cmd, 1, 5 ); + DISP_CSX = 1; + return r; +} + +static int send_data_byte( uint8_t data ) +{ + int r; + DISP_CSX = 0; + DISP_DCX = 1; + r = send_bytes( &data, 1, 5 ); + DISP_CSX = 1; + return r; +} + +static int send_data_word( uint16_t data ) +{ + int r; + uint16_t bew; + + bew = ( data << 8 ) | ( data >> 8 ); + + DISP_CSX = 0; + DISP_DCX = 1; + r = send_bytes( (uint8_t*)&bew, 2, 5 ); + DISP_CSX = 1; + + return r; +} + +static void address_rect( const rect_t *r ) +{ + uint16_t left = r->left + 26; + uint16_t right = r->right + 26; + uint16_t top = r->top + 1; + uint16_t bottom = r->bottom + 1; + + send_cmd_byte( 0x2A ); + send_data_byte( left >> 8 ); + send_data_byte( left & 0xFF ); + send_data_byte( right >> 8 ); + send_data_byte( right & 0xFF ); + send_cmd_byte( 0x2B ); + send_data_byte( top >> 8 ); + send_data_byte( top & 0xFF ); + send_data_byte( bottom >> 8 ); + send_data_byte( bottom & 0xFF ); + send_cmd_byte( 0x2C ); +} + +static void fill_rect( rect_t *r ) +{ + address_rect( r ); + + int nbPix = ( r->right - r->left + 1 ) * ( r->bottom - r->top + 1 ); + while ( nbPix-- ) + { + send_data_word( drawing_color ); + } +} + +static void StartBacklightDriver( void ) +{ + PWM_EnableOutput( PWM1, PWM_CH_2_MASK ); + PWM_Start( PWM1, PWM_CH_2_MASK ); +} + +static void StopBacklightDriver( void ) +{ + PWM_SET_CMR( PWM1, 2, 0 ); + PWM_Stop( PWM1, PWM_CH_2_MASK ); +} + +static void Open( void ) +{ + DISP_CSX = 1; + DISP_DCX = 1; + SPI_ENABLE( SPI0 ); + StartBacklightDriver(); + PD2 = 1; + PB1 = 0; +} + +static void Close( void ) +{ + SPI_DISABLE( SPI0 ); + StopBacklightDriver(); + PD2 = 0; +} + +static void Sleep( void ) +{ + send_cmd_byte( 0x10 ); + SetDisplayStatus( DISPLAY_SLEEPING ); +} + +static void Wakeup( void ) +{ + send_cmd_byte( 0x11 ); + + if ( display_status == DISPLAY_SLEEPING ) + TMCreateTask( 120, SetDisplayStatus, DISPLAY_ON, 0, 0, 0 ); +} + +static void Reset( void ) +{ + PC2 = 1; + WaitUs( 10 ); + PC2 = 0; + WaitUs( 10 ); + PC2 = 1; +} + +static void CLS( void ) +{ + drawing_color = bgcolor; + + rect_t r = { 0, 0, 79, 159 }; + + fill_rect( &r ); +} + +static uint16_t color_rgb_to_565( uint32_t rgb ) +{ + return ( rgb >> 19 &0xF ) << 11 + | ( rgb >> 10 & 0x1F ) << 5 + | ( rgb >> 3 & 0xF ) + ; +} + +static void SetColor( uint32_t rgb ) +{ + fgcolor = color_rgb_to_565( rgb ); +} + +static void SetBgColor( uint32_t rgb ) +{ + bgcolor = color_rgb_to_565( rgb ); +} + +static void Init( void ) +{ + int len = sizeof( init_sequence ) / sizeof( struct c_or_d_byte ); + int i; + for ( i = 0 ; i < len ; ++i ) + { + uint8_t byte = init_sequence[i].byte; + switch ( init_sequence[i].c_or_d ) + { + case 0: + send_cmd_byte( byte ); + break; + case 1: + send_data_byte( byte ); + break; + } + } + + send_cmd_byte( 0x29 ); + + WaitTicks( 1 ); +} + +static void SetBrightness( uint32_t b ) +{ + PWM_SET_CMR( PWM1, 2, b ); +} + +static void SetFont( const font_t *f ) +{ + font = f; +} + +static int draw_char( const uint16_t c, int x, int y ) +{ + const font_chunk_t *chunk = font->chunk; + + while ( chunk ) + { + if (( c >= chunk->char_min ) && ( c <= chunk->char_max )) + break; + chunk = chunk->next; + } + + if ( !chunk ) return 0; + + const font_chardesc_t *chardesc = &chunk->chars[ c - chunk->char_min ]; + int cw = chardesc->width; + + if ( !cw ) return 0; + + int ch = font->char_height; + + rect_t r = { x, y, x + cw - 1, y + ch - 1 }; + address_rect( &r ); + + const uint8_t *bitmap = chardesc->bitmap; + + uint8_t bits; + while ( ch-- ) + { + for ( int i = 0 ; i < cw ; ++i ) + { + if ( !( i & 0x7 ) ) bits = *bitmap++; + send_data_word( bits >> 7 ? fgcolor : bgcolor ); + bits <<= 1; + } + } + + return cw; +} + +static void Print( const char *str, const rect_t *r ) +{ + if ( !font ) return; + + int x = r->left; + int y = r->top; + + uint16_t c; + + while ( ( c = (uint16_t)*str++ ) ) + { + x += draw_char( c, x, y ); + } +} + +void rainbow( void ) +{ + rect_t rect = { 0, 0, 79, 159 }; + + address_rect( &rect ); + + int r, g, b; + + for ( int l = 0 ; l < 160 ; ++l ) + { + g = HDIV_Div( 64 * l, 160 ); + + for ( int c = 0 ; c < 80 ; ++c ) + { + r = HDIV_Div( 32 * c, 80 ); + b = HDIV_Div( 32 * ( c + l ), 240 ) ^ 0x1F; + + uint32_t c = b << 11 | g << 5 | r; + send_data_word( c ); + } + } +} + + +//------------------------------------------------------------------------------ +// Startup Task +//------------------------------------------------------------------------------ +// Does not prevent the box from operating while the screen is not up yet. +//------------------------------------------------------------------------------ + +static uint8_t startup_task_id; + +void startup_task( uint32_t step ) +{ + switch ( step ) + { + case 0: + Reset(); + TMUpdateTask( startup_task_id, 1, 1 ); + break; + + case 1: + Open(); + TMUpdateTask( startup_task_id, 2, 120 ); + break; + + case 2: + Wakeup(); + TMUpdateTask( startup_task_id, 3, 120 ); + break; + + case 3: + Init(); + TMDestroyTask( startup_task_id ); + SetDisplayStatus( DISPLAY_ON ); + break; + } +} + +void Startup( void ) +{ + if ( startup_task_id ) + { + TMDestroyTask( startup_task_id ); + } + + SetDisplayStatus( DISPLAY_OFF ); + TMCreateTask( 0, startup_task, 0, 1, 120, &startup_task_id ); +} + + +const display_t ST7735S = +{ + Startup, + Sleep, + Wakeup, + SetColor, + SetBgColor, + CLS, + SetBrightness, + SetFont, + Print +}; + diff --git a/src/aegis.s b/src/aegis.s new file mode 100644 index 0000000..6cd9efb --- /dev/null +++ b/src/aegis.s @@ -0,0 +1,117 @@ +;/****************************************************************************** +; * +; * @file aegis.s +; * +; * @brief Assembly procedures +; * +; *****************************************************************************/ + + AREA |.text|, CODE, READONLY + + +; Integer square root (Newton's method). +; Average execution time ~120 cycles, using hardware mul and div. + +HDIV EQU 0x50014000 + + ALIGN +isqrt PROC + ROUT + EXPORT isqrt + + PUSH {R4,R5} + FRAME PUSH {R4,R5} + + MOV R1, R0 + LDR R4, = HDIV + LDR R0, = 2500 +0 MOV R2, R0 + MULS R2, R2 + ADD R2, R1 + LSLS R3, R0, #1 + STR R2, [R4, #0] + STR R3, [R4, #4] + LDR R3, [R4, #8] + LDR R5, [R4, #12] + CMP R5, R0 + BLT %1 + ADDS R3, #1 +1 CMP R0, R3 + MOV R0, R3 + BNE %0 + + POP {R4,R5} + FRAME POP {R4,R5} + + BX LR + + ENDP + + + IF {FALSE} + +; Another integer square root routine without hardware multiplier or divider. +; (Pseudo-Euclidian division) +; ~250 cycles. + + ALIGN +isqrt PROC + ROUT + EXPORT isqrt + + MOV R1, R0 ; r1 = num + MOVS R0, #0 ; r0 = res + MOVS R2, #1 + LSLS R2, #30 ; r2 = bit + +0 CMP R2, R1 + BLE %1 + LSRS R2, #2 + BNE %0 + B %2 + +1 ADDS R3, R0, R2 + CMP R1, R3 + BLT %3 + SUBS R1, R3 + LSRS R0, #1 + ADDS R0, R2 + B %4 +3 LSRS R0, #1 + +4 LSRS R2, #2 + BNE %1 +2 + BX LR + + ENDP + + ENDIF + + +; Microseconds delay. +; Total cycles = 72 * R0 +; (accounting for the 6 cycles of the call, MOVS R0,#xx + BL WaitUs) +; Excess time is 1.6 * R0 nanoseconds given that CLK = 71.8848MHz, not 72. +; Drift is below 1us for delays below 624us. Good enough. +; Minimun 0.21µs for R0 = 0. Don't call this function if you don't expect to wait. + + ALIGN +WaitUs PROC + ROUT + EXPORT WaitUs + + MOVS R1, #18 ; 1 + MULS R0, R1, R0 ; 1 + SUBS R0, #4 ; 1 + BCC %1 ; 3/1 + NOP ; 1 +0 SUBS R0, #1 ; 1 + BCS %0 ; 3/1 +1 BX LR ; 3 + + ENDP + + ALIGN + + END diff --git a/src/battery.c b/src/battery.c new file mode 100644 index 0000000..ca6ea1e --- /dev/null +++ b/src/battery.c @@ -0,0 +1,66 @@ +//============================================================================== +// aegis/src/battery.c +//------------------------------------------------------------------------------ +// Battery management +//============================================================================== +#include "aegis.h" + + +typedef struct battery_s +{ + uint32_t vcell1; + uint32_t vcell2; + uint32_t vtotal; +} +battery_t; + + +static battery_t battery; + + +//------------------------------------------------------------------------------ +// Initialization. Call at startup. +//------------------------------------------------------------------------------ +void BMStartup( void ) +{ +} + + +void BMUpdateBattery( void ) +{ + static uint32_t last = 0; + + uint32_t t = GetSysTick(); + if ( t - last > TI_UPDATE_BATTERY ) + { + BMReadBattery(); + } +} + + +void BMReadBattery( void ) +{ + uint32_t sample; + uint32_t vbat1, vbat2; + + sample = ADCSample( ADC_CH_BATT_CELL1, 16 ); + vbat1 = 3 * ADC_VREF * sample >> 13; + + sample = ADCSample( ADC_CH_BATT_TOTAL, 16 ); + vbat2 = 3 * ADC_VREF * sample >> 12; + + if ( vbat2 > vbat1 ) vbat2 -= vbat1; + if ( vbat1 > 0 ) vbat1 += BVO_CELL1; + if ( vbat2 > 0 ) vbat2 += BVO_CELL2; + + battery.vcell1 = vbat1; + battery.vcell2 = vbat2; + battery.vtotal = vbat1 + vbat2; +} + + +void BMGetCells( uint32_t *v1, uint32_t *v2 ) +{ + *v1 = battery.vcell1; + *v2 = battery.vcell2; +} diff --git a/src/devices.c b/src/devices.c new file mode 100644 index 0000000..d5c3f68 --- /dev/null +++ b/src/devices.c @@ -0,0 +1,235 @@ +#include +#include "devices.h" + + +void ConfigurePins( void ) +{ + SYS->GPA_MFPL = + SYS_GPA_MFPL_PA0MFP_GPIO + | SYS_GPA_MFPL_PA1MFP_PWM1_CH4 + | SYS_GPA_MFPL_PA2MFP_PWM1_CH3 + | SYS_GPA_MFPL_PA3MFP_PWM1_CH2 + ; + + SYS->GPB_MFPL = + SYS_GPB_MFPL_PB0MFP_ADC0_CH0 + | SYS_GPB_MFPL_PB1MFP_GPIO + | SYS_GPB_MFPL_PB2MFP_GPIO + | SYS_GPB_MFPL_PB3MFP_ADC0_CH3 + | SYS_GPB_MFPL_PB4MFP_ADC0_CH4 + | SYS_GPB_MFPL_PB5MFP_ADC0_CH13 + | SYS_GPB_MFPL_PB6MFP_ADC0_CH14 + | SYS_GPB_MFPL_PB7MFP_ADC0_CH15 + ; + + GPIO_DISABLE_DIGITAL_PATH( + PB, + GPIO_PIN_PIN0_Msk + | GPIO_PIN_PIN3_Msk + | GPIO_PIN_PIN4_Msk + | GPIO_PIN_PIN5_Msk + | GPIO_PIN_PIN6_Msk + | GPIO_PIN_PIN7_Msk + ); + + SYS->GPC_MFPL = + SYS_GPC_MFPL_PC0MFP_SPI0_CLK + | SYS_GPC_MFPL_PC1MFP_GPIO + | SYS_GPC_MFPL_PC2MFP_GPIO + | SYS_GPC_MFPL_PC3MFP_SPI0_MOSI + | SYS_GPC_MFPL_PC4MFP_GPIO + ; + + SYS->GPD_MFPL = + SYS_GPD_MFPL_PD0MFP_GPIO + | SYS_GPD_MFPL_PD1MFP_GPIO + | SYS_GPD_MFPL_PD2MFP_GPIO + | SYS_GPD_MFPL_PD3MFP_GPIO + | SYS_GPD_MFPL_PD7MFP_PWM0_CH5 + ; + + SYS->GPE_MFPL = + SYS_GPE_MFPL_PE0MFP_GPIO + | SYS_GPE_MFPL_PE6MFP_GPIO + | SYS_GPE_MFPL_PE7MFP_GPIO + ; + + SYS->GPE_MFPH = + SYS_GPE_MFPH_PE10MFP_GPIO + | SYS_GPE_MFPH_PE11MFP_GPIO + | SYS_GPE_MFPH_PE12MFP_GPIO + | SYS_GPE_MFPH_PE13MFP_GPIO + ; + + SYS->GPF_MFPL = + SYS_GPF_MFPL_PF0MFP_GPIO + | SYS_GPF_MFPL_PF1MFP_GPIO + | SYS_GPF_MFPL_PF2MFP_GPIO + | SYS_GPF_MFPL_PF3MFP_GPIO + | SYS_GPF_MFPL_PF4MFP_GPIO + | SYS_GPF_MFPL_PF7MFP_GPIO + ; +} + +void ConfigureGPIO( void ) +{ + GPIO_SetMode( PA, + GPIO_PIN_PIN0_Msk, + GPIO_MODE_OUTPUT ); + + GPIO_SET_OUT_DATA( PA, 0 ); + + PA0 = 1; + + GPIO_SetMode( PB, + GPIO_PIN_PIN1_Msk|GPIO_PIN_PIN2_Msk, + GPIO_MODE_OUTPUT ); + + GPIO_SET_OUT_DATA( PB, 0 ); + + PB1 = 0; + PB2 = 1; + + GPIO_SetMode( PC, + GPIO_PIN_PIN1_Msk|GPIO_PIN_PIN2_Msk|GPIO_PIN_PIN4_Msk, + GPIO_MODE_OUTPUT ); + + GPIO_SET_OUT_DATA( PC, 0 ); + + PC1 = 0; + PC2 = 0; + PC4 = 0; + + GPIO_SetMode( PD, + GPIO_PIN_PIN0_Msk, + GPIO_MODE_QUASI ); + + GPIO_SetMode( PD, + GPIO_PIN_PIN1_Msk|GPIO_PIN_PIN2_Msk|GPIO_PIN_PIN3_Msk, + GPIO_MODE_OUTPUT ); + + GPIO_SET_OUT_DATA( PD, 0 ); + + PD0 = 1; + + PD1 = 0; + PD2 = 0; + PD3 = 0; + + GPIO_SetMode( PE, + GPIO_PIN_PIN0_Msk, + GPIO_MODE_INPUT ); + + GPIO_SetMode( PE, + GPIO_PIN_PIN6_Msk|GPIO_PIN_PIN7_Msk|GPIO_PIN_PIN11_Msk|GPIO_PIN_PIN12_Msk, + GPIO_MODE_OUTPUT ); + + GPIO_SetMode( PE, + GPIO_PIN_PIN10_Msk|GPIO_PIN_PIN13_Msk, + GPIO_MODE_QUASI ); + + GPIO_SET_OUT_DATA( PE, 0 ); + + PE6 = 0; + PE7 = 0; + PE11 = 0; + PE12 = 0; + + PE10 = 1; + PE13 = 1; + + GPIO_SetMode( PF, + GPIO_PIN_PIN0_Msk|GPIO_PIN_PIN1_Msk|GPIO_PIN_PIN2_Msk|GPIO_PIN_PIN3_Msk|GPIO_PIN_PIN4_Msk|GPIO_PIN_PIN7_Msk, + GPIO_MODE_OUTPUT ); + + GPIO_SET_OUT_DATA( PF, 0 ); + + PF0 = 0; + PF1 = 0; + PF2 = 0; + PF3 = 0; + PF4 = 1; + PF7 = 0; +} + + +void ConfigureSPI0( void ) +{ + CLK_EnableModuleClock( SPI0_MODULE ); + CLK_SetModuleClock( SPI0_MODULE, CLK_CLKSEL2_SPI0SEL_PLL, 0 ); + + NVIC_DisableIRQ( SPI0_IRQn ); + + SPI_Open( SPI0, SPI_MASTER, SPI_MODE_0, 8, 14400000 ); + SPI_DisableAutoSS( SPI0 ); +} + + +void ConfigurePWM1( void ) +{ + CLK_EnableModuleClock( PWM1_MODULE ); + CLK_SetModuleClock( PWM1_MODULE, CLK_CLKSEL1_PWM1SEL_PLL , 0 ); + + NVIC_DisableIRQ( PWM1_IRQn ); + + PWM1->CTL1 = PWM1->CTL1 + & ~( PWM_LCD_CNTTYPE_Msk | PWM_BOOST_CNTTYPE_Msk | PWM_BUCK_CNTTYPE_Msk ) + | (( PWM_UP_COUNTER << PWM_LCD_CNTTYPE_Pos ) | + ( PWM_UP_COUNTER << PWM_BOOST_CNTTYPE_Pos ) | + ( PWM_UP_COUNTER << PWM_BUCK_CNTTYPE_Pos )) + ; + + PWM_SET_OUTPUT_LEVEL( PWM1, + PWM_CH_LCD_MASK | PWM_CH_BOOST_MASK | PWM_CH_BUCK_MASK, + PWM_OUTPUT_HIGH, PWM_OUTPUT_LOW, PWM_OUTPUT_NOTHING, PWM_OUTPUT_NOTHING + ); + + PWM_SET_PRESCALER( PWM1, PWM_CH_BOOST, 5 ); + PWM_SET_CNR( PWM1, PWM_CH_BOOST, 199 ); + PWM_SET_CMR( PWM1, PWM_CH_BOOST, 0 ); + + PWM_SET_PRESCALER( PWM1, PWM_CH_BUCK, 5 ); + PWM_SET_CNR( PWM1, PWM_CH_BUCK, 199 ); + PWM_SET_CMR( PWM1, PWM_CH_BUCK, 200 ); + + PWM_SET_PRESCALER( PWM1, PWM_CH_LCD, 2 ); + PWM_SET_CNR( PWM1, PWM_CH_LCD, 99 ); + PWM_SET_CMR( PWM1, PWM_CH_LCD, 0 ); +} + + +void ConfigureADC() +{ + CLK_EnableModuleClock( ADC_MODULE ); + CLK_SetModuleClock( ADC_MODULE, CLK_CLKSEL1_ADCSEL_HIRC, CLK_CLKDIV0_ADC( 7 ) ); + + NVIC_DisableIRQ( ADC_IRQn ); + + ADC_POWER_ON( ADC ); +} + + +void ConfigureHDIV() +{ + CLK_EnableModuleClock( HDIV_MODULE ); +} + + +uint32_t ADCSample( uint32_t ch, int count ) +{ + uint32_t sample; + + ADC_Open( ADC, ADC_ADCR_DIFFEN_SINGLE_END, ADC_ADCR_ADMD_SINGLE, 0x1 << ch ); + + sample = 0; + for ( int i = 0 ; i < count ; ++i ) + { + ADC_START_CONV( ADC ); + while ( !ADC_IS_DATA_VALID( ADC, ch ) ) + ; + sample += ADC_GET_CONVERSION_DATA( ADC, ch ); + } + + sample = HDIV_Div( sample, count ); + return sample; +} diff --git a/src/display.c b/src/display.c new file mode 100644 index 0000000..165678e --- /dev/null +++ b/src/display.c @@ -0,0 +1,106 @@ +//============================================================================== +// aegis/src/display.c +//------------------------------------------------------------------------------ +// Display management +//============================================================================== +#include "aegis.h" + + + +const display_t *display; + +DISPLAY_STATUS display_status = DISPLAY_OFF; + +uint16_t fgcolor; +uint16_t bgcolor; + + +//------------------------------------------------------------------------------ +// Inform the display manager of the display we'll use. +//------------------------------------------------------------------------------ +void SetDisplay( const display_t *d ) +{ + display = d; +} + + +void SetDisplayStatus( uint32_t status ) +{ + display_status = status; + EMSendEvent1P( EVENT_DISPLAY, EV_D_DISPLAY_STATUS, status ); +} + + +DISPLAY_STATUS GetDisplayStatus( void ) +{ + return display_status; +} + + +//------------------------------------------------------------------------------ +// Number formatting +//------------------------------------------------------------------------------ +// - str: Output buffer. Nust be large enough (nbdig+2). +// - num: The number. +// - nbdig: Maximum number of output digits. +// - nbdec: Maximum number of decimal places. +// - exp: Number divider in powers of 10. +//------------------------------------------------------------------------------ +void FormatNumber( char *str, uint32_t num, int nbdig, int nbdec, int exp ) +{ + char buf[10]; + + int idx = 0; + + if ( !nbdig ) + { + *str = 0; + return; + } + + while ( num ) + { + num = HDIV_Div( num, 10 ); + uint16_t rem = HDIV->DIVREM; + buf[idx++] = '0' + rem; + } + + if ( idx <= exp ) + { + *str++ = '0'; + if ( !nbdec || !--nbdig ) + { + *str = 0; + return; + } + if ( idx < exp ) + { + *str++ = '.'; + + int nbz = 0; + while ( nbz++ < ( exp - idx ) ) + { + *str++ = '0'; + if ( !--nbdec || !--nbdig ) + { + *str = 0; + return; + } + } + } + } + + while ( nbdig-- ) + { + if ( idx == exp && nbdec ) *str++ = '.'; + if ( idx <= exp && !nbdec-- ) + { + *str = 0; + return; + } + *str++ = idx ? buf[--idx] : '0'; + } + + *str = 0; +} + diff --git a/src/events.c b/src/events.c new file mode 100644 index 0000000..267f2a4 --- /dev/null +++ b/src/events.c @@ -0,0 +1,188 @@ +//============================================================================== +// aegis/src/events.c +//------------------------------------------------------------------------------ +// Events management +//============================================================================== +#include "aegis.h" + + +static uint8_t emrbid; +static uint8_t embuffer[ 20 * sizeof( Event_t ) ]; + + +// For debugging pruposes +static void PrintEvent( const Event_t *ev ) +{ + if ( GetDisplayStatus() != DISPLAY_ON ) return; + rect_t r = { 11, 150, 79, 159 }; + char buf[12]; + snprintf( buf, sizeof( buf ), "%02X %02X %02X %02X", ev->type, ev->k, ev->p1, ev->p2 ); + display->Print( buf, &r ); +} + + +void EMStartup() +{ + emrbid = RBAlloc( embuffer, sizeof( embuffer ), sizeof( Event_t ) ); +} + + +int EMSendEvent( const Event_t *ev ) +{ + return RBSendMessage( emrbid, ev ); +} + +int EMSendEventInt( const uint32_t ev ) +{ + return RBSendMessage( emrbid, &ev ); +} + +int EMSendEventNP( Event_e type, uint8_t id ) +{ + Event_t ev; + + ev.type = type; + ev.id = id; + ev.p1 = 0; + ev.p2 = 0; + + return RBSendMessage( emrbid, &ev ); +} + +int EMSendEvent1P( Event_e type, uint8_t id, uint8_t p1 ) +{ + Event_t ev; + + ev.type = type; + ev.id = id; + ev.p1 = p1; + ev.p2 = 0; + + return RBSendMessage( emrbid, &ev ); +} + +int EMSendEvent2P( Event_e type, uint8_t id, uint8_t p1, uint8_t p2 ) +{ + Event_t ev; + + ev.type = type; + ev.id = id; + ev.p1 = p1; + ev.p2 = p2; + + return RBSendMessage( emrbid, &ev ); +} + +int EMEventsPending() +{ + return RBHasMessages( emrbid ); +} + + +int EMGetNextEvent( Event_t *ev ) +{ + return RBReadMessage( emrbid, ev ); +} + + + +//============================================================================== +// Event handling +//============================================================================== + +static void EMKeyEvent( Event_t *ev ); +static void EMDisplayEvent( Event_t *ev ); + + +void EMHandleEvents() +{ + int pending = EMEventsPending(); + if ( !pending ) return; + + uint32_t t = GetSysTick(); + + while ( 1 ) + { + Event_t ev; + EMGetNextEvent( &ev ); + + PrintEvent( &ev ); + + switch ( ev.type ) + { + case EVENT_KEY: + EMKeyEvent( &ev ); + break; + + case EVENT_DISPLAY: + EMDisplayEvent( &ev ); + break; + + case EVENT_NULL: + default: + break; + } + + if ( !--pending ) break; + if ( GetSysTick() - t > TI_EVENT_HANDLING ) break; + } +} + + +static void EMKeyEvent( Event_t *ev ) +{ + switch ( ev->k ) + { + case EV_K_FIRE: + if ( ev->p1 == 1 ) + { + ResetChip( 0 ); + } + break; + + case EV_K_FP: + if ( ev->p1 == 1 ) + { + ResetChip( 1 ); + } + break; + + case EV_K_NULL: + default: + break; + } +} + + +static void EMDisplayEvent( Event_t *ev ) +{ + switch ( ev->d ) + { + case EV_D_DISPLAY_STATUS: + { + switch ( ev->p1 ) + { + case DISPLAY_ON: + DELAYED_EVENT( 1, EVENT_DISPLAY, EV_D_BRIGHTNESS, 25, 0 ); + break; + } + break; + } + + case EV_D_SCREEN: + { + SMShowScreen( ev->p1 ); + break; + } + + case EV_D_BRIGHTNESS: + { + display->SetBrightness( ev->p1 ); + break; + } + + case EV_D_NULL: + default: + break; + } +} diff --git a/src/font.c b/src/font.c new file mode 100644 index 0000000..a443e98 --- /dev/null +++ b/src/font.c @@ -0,0 +1,464 @@ +#include +#include "font.h" + +static const uint8_t simple_font_x20[] = +{ + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000 +}; + +static const uint8_t simple_font_x21[] = +{ + 0b00000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b00000000, + 0b10000000, + 0b00000000 +}; + +static const uint8_t simple_font_x2C[] = +{ + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01000000, + 0b01000000, + 0b01000000 +}; + +static const uint8_t simple_font_x2D[] = +{ + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b11111000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000 +}; + +static const uint8_t simple_font_x2E[] = +{ + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b01000000, + 0b00000000 +}; + +static const uint8_t simple_font_x2F[] = +{ + 0b00100000, + 0b00100000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b01000000, + 0b10000000, + 0b10000000, + 0b00000000 +}; + +static const uint8_t simple_font_x30[] = +{ + 0b00000000, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000 +}; + +static const uint8_t simple_font_x31[] = +{ + 0b00000000, + 0b00100000, + 0b01100000, + 0b10100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00000000 +}; + +static const uint8_t simple_font_x32[] = +{ + 0b00000000, + 0b01110000, + 0b10001000, + 0b00001000, + 0b00001000, + 0b00010000, + 0b00100000, + 0b01000000, + 0b11111000, + 0b00000000 +}; + +static const uint8_t simple_font_x33[] = +{ + 0b00000000, + 0b01110000, + 0b10001000, + 0b00001000, + 0b00110000, + 0b00001000, + 0b00001000, + 0b10001000, + 0b01110000, + 0b00000000 +}; + +static const uint8_t simple_font_x34[] = +{ + 0b00000000, + 0b00010000, + 0b00110000, + 0b01010000, + 0b01010000, + 0b10010000, + 0b11111000, + 0b00010000, + 0b00010000, + 0b00000000 +}; + +static const uint8_t simple_font_x35[] = +{ + 0b00000000, + 0b01111000, + 0b01000000, + 0b10000000, + 0b11110000, + 0b00001000, + 0b00001000, + 0b10001000, + 0b01110000, + 0b00000000 +}; + +static const uint8_t simple_font_x36[] = +{ + 0b00000000, + 0b01110000, + 0b10001000, + 0b10000000, + 0b11110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000 +}; + +static const uint8_t simple_font_x37[] = +{ + 0b00000000, + 0b11111000, + 0b00001000, + 0b00001000, + 0b00010000, + 0b00010000, + 0b00100000, + 0b00100000, + 0b00100000, + 0b00000000 +}; + +static const uint8_t simple_font_x38[] = +{ + 0b00000000, + 0b01110000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01110000, + 0b00000000 +}; + +static const uint8_t simple_font_x39[] = +{ + 0b00000000, + 0b01110000, + 0b10001000, + 0b10001000, + 0b10001000, + 0b01111000, + 0b00001000, + 0b10001000, + 0b01110000, + 0b00000000 +}; + +static const uint8_t simple_font_x41[] = +{ + 0b00000000, + 0b00010000, + 0b00101000, + 0b00101000, + 0b00101000, + 0b01000100, + 0b01111100, + 0b10000010, + 0b10000010, + 0b00000000 +}; + +static const uint8_t simple_font_x42[] = +{ + 0b00000000, + 0b11111000, + 0b10000100, + 0b10000100, + 0b11111100, + 0b10000100, + 0b10000100, + 0b10000100, + 0b11111000, + 0b00000000 +}; + +static const uint8_t simple_font_x43[] = +{ + 0b00000000, + 0b00111000, + 0b01000100, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b01000100, + 0b00111000, + 0b00000000 +}; + +static const uint8_t simple_font_x44[] = +{ + 0b00000000, + 0b11110000, + 0b10001000, + 0b10000100, + 0b10000100, + 0b10000100, + 0b10000100, + 0b10001000, + 0b11110000, + 0b00000000 +}; + +static const uint8_t simple_font_x45[] = +{ + 0b00000000, + 0b11111000, + 0b10000000, + 0b10000000, + 0b11111000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b11111000, + 0b00000000 +}; + +static const uint8_t simple_font_x46[] = +{ + 0b00000000, + 0b11111000, + 0b10000000, + 0b10000000, + 0b11111000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b00000000 +}; + +static const uint8_t simple_font_x48[] = +{ + 0b00000000, + 0b10000100, + 0b10000100, + 0b10000100, + 0b11111100, + 0b10000100, + 0b10000100, + 0b10000100, + 0b10000100, + 0b00000000 +}; + +static const uint8_t simple_font_x4C[] = +{ + 0b00000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b10000000, + 0b11111000, + 0b00000000 +}; + +static const uint8_t simple_font_x4F[] = +{ + 0b00000000, + 0b00111000, + 0b01000100, + 0b10000010, + 0b10000010, + 0b10000010, + 0b10000010, + 0b01000100, + 0b00111000, + 0b00000000 +}; + +static const uint8_t simple_font_x52[] = +{ + 0b00000000, + 0b11111000, + 0b10000100, + 0b10000100, + 0b11111000, + 0b10010000, + 0b10001000, + 0b10001000, + 0b10000100, + 0b00000000 +}; + +static const uint8_t simple_font_x57[] = +{ + 0b00000000, 0b00000000, + 0b10000100, 0b00100000, + 0b10001010, 0b00100000, + 0b01001010, 0b01000000, + 0b01001010, 0b01000000, + 0b01010001, 0b01000000, + 0b01010001, 0b01000000, + 0b00100000, 0b10000000, + 0b00100000, 0b10000000, + 0b00000000, 0b00000000 +}; + +static const font_chardesc_t simple_font_chars_1[] = +{ + { 3, simple_font_x20 }, + { 2, simple_font_x21 } +}; + +static const font_chardesc_t simple_font_chars_2[] = +{ + { 3, simple_font_x2C }, + { 6, simple_font_x2D }, + { 3, simple_font_x2E }, + { 3, simple_font_x2F }, + { 6, simple_font_x30 }, + { 6, simple_font_x31 }, + { 6, simple_font_x32 }, + { 6, simple_font_x33 }, + { 6, simple_font_x34 }, + { 6, simple_font_x35 }, + { 6, simple_font_x36 }, + { 6, simple_font_x37 }, + { 6, simple_font_x38 }, + { 6, simple_font_x39 } +}; + +static const font_chardesc_t simple_font_chars_3[] = +{ + { 7, simple_font_x41 }, + { 7, simple_font_x42 }, + { 7, simple_font_x43 }, + { 6, simple_font_x44 }, + { 6, simple_font_x45 }, + { 6, simple_font_x46 }, + { 0, 0 }, + { 7, simple_font_x48 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 6, simple_font_x4C }, + { 0, 0 }, + { 0, 0 }, + { 8, simple_font_x4F }, + { 0, 0 }, + { 0, 0 }, + { 7, simple_font_x52 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 12, simple_font_x57 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 } +}; + +static const font_chunk_t simple_font_chunk_3 = +{ + 0x41, + 0x5A, + simple_font_chars_3, + 0 +}; + +static const font_chunk_t simple_font_chunk_2 = +{ + 0x2C, + 0x39, + simple_font_chars_2, + &simple_font_chunk_3 +}; + +static const font_chunk_t simple_font_chunk_1 = +{ + 0x20, + 0x21, + simple_font_chars_1, + &simple_font_chunk_2 +}; + +const font_t simple_font = +{ + 10, + 10, + &simple_font_chunk_1 +}; diff --git a/src/init.c b/src/init.c new file mode 100644 index 0000000..d3304f5 --- /dev/null +++ b/src/init.c @@ -0,0 +1,82 @@ +#include + + +/*---------------------------------------------------------------------------- + Clock Variable definitions + *----------------------------------------------------------------------------*/ +uint32_t SystemCoreClock = __HSI; /*!< System Clock Frequency (Core Clock) */ +uint32_t CyclesPerUs = (__HSI / 1000000); /*!< Cycles per micro second */ +uint32_t PllClock = __HSI; /*!< PLL Output Clock Frequency */ +const uint32_t gau32ClkSrcTbl[] = {__HXT, __LXT, __HSI, __LIRC, __HIRC48, 0UL, 0UL, __HIRC}; + + +/** + * @brief Update the Variable SystemCoreClock + * + * @param None + * + * @return None + * + * @details This function is used to update the variable SystemCoreClock + * and must be called whenever the core clock is changed. + */ +void SystemCoreClockUpdate(void) +{ + uint32_t u32Freq, u32ClkSrc; + uint32_t u32HclkDiv; + + u32ClkSrc = CLK->CLKSEL0 & CLK_CLKSEL0_HCLKSEL_Msk; + + /* Update PLL Clock */ + PllClock = CLK_GetPLLClockFreq(); + + if(u32ClkSrc != CLK_CLKSEL0_HCLKSEL_PLL) + { + /* Use the clock sources directly */ + u32Freq = gau32ClkSrcTbl[u32ClkSrc]; + } + else + { + /* Use PLL clock */ + u32Freq = PllClock; + } + + u32HclkDiv = (CLK->CLKDIV0 & CLK_CLKDIV0_HCLKDIV_Msk) + 1; + + /* Update System Core Clock */ + SystemCoreClock = u32Freq / u32HclkDiv; + + CyclesPerUs = (SystemCoreClock + 500000) / 1000000; +} + + +/** + * @brief System Initialization + * + * @param None + * + * @return None + * + * @details The necessary initialization of system. Global variables are forbidden here. + */ +void SystemInit( void ) +{ + SYS_UnlockReg(); + SYS_DISABLE_POR(); + + CLK_EnableXtalRC( CLK_PWRCTL_HIRCEN_Msk ); + CLK_WaitClockReady( CLK_STATUS_HIRCSTB_Msk ); + CLK_SetHCLK( CLK_CLKSEL0_HCLKSEL_HIRC, CLK_CLKDIV0_HCLK(1) ); + CLK_DisableXtalRC( CLK_PWRCTL_LXTEN_Msk ); + CLK_SetCoreClock( 72000000 ); + CLK_WaitClockReady( CLK_STATUS_PLLSTB_Msk ); + + CLK_EnableSysTick( CLK_CLKSEL0_STCLKSEL_HCLK, 72000 ); + + SYS_EnableBOD( SYS_BODCTL_BOD_INTERRUPT_EN, SYS_BODCTL_BODVL_2_7V ); + NVIC_EnableIRQ( BOD_IRQn ); + + SYS_LockReg(); +} + + diff --git a/src/inputs.c b/src/inputs.c new file mode 100644 index 0000000..3a8c3bd --- /dev/null +++ b/src/inputs.c @@ -0,0 +1,400 @@ +//============================================================================== +// aegis/src/inputs.c +//------------------------------------------------------------------------------ +// User input management +//============================================================================== +#include "aegis.h" + +#include + + +//------------------------------------------------------------------------------ +/* Structure defining what is a keypress event + */ + +typedef struct key +{ + int (*pf_test)( void ); // Key/combo pressed test function + EV_K_e key_event; // Key event type for the key/combo + uint8_t nbuttons; // Number of keys in the combo + uint16_t kh1_ticks; // Min ticks before event hold 1 + uint16_t kh2_ticks; // Min ticks before event hold 2 +} +key_t; + + +//------------------------------------------------------------------------------ +/* Structure defining a sequence of keypresses + */ + +#define MAX_SEQ_KEYS 6 + +typedef struct sequence +{ + EV_K_e key_event; // Sequence event + uint8_t reset; // Sequence cannot be prefix of another sequence + uint8_t length; // Sequence length + EV_K_e sequence[MAX_SEQ_KEYS]; // Sequence keys +} +sequence_t; + + +//------------------------------------------------------------------------------ +/* Key state + */ + +typedef struct keystate +{ + EV_K_e last; // Last key event + EV_K_e current; // Current key event + uint8_t rstep; // Repeat step + uint8_t nbuttons; // # of buttons implied in the event + uint32_t last_tick; // Repeat tick counter + uint32_t tick; // Tick of event start + uint32_t seq_tick; // Last sequence tick + uint8_t rcount; // Repeat count + uint8_t seq_count; // Current sequence length + EV_K_e seq[MAX_SEQ_KEYS]; // Current key sequence +} +keystate_t; + + +static keystate_t ks = { 0 }; + + +//------------------------------------------------------------------------------ +/* Predefinition of test functions + */ + +static int TestFMP(); +static int TestFM(); +static int TestFP(); +static int TestMP(); +static int TestF(); +static int TestM(); +static int TestP(); + + +//------------------------------------------------------------------------------ +/* Available key input events + * Defined by priority order + */ + +static const key_t keys[] = +{ + { + TestFMP, + EV_K_FMP, + 3, + 50, + 1000 + }, + { + TestFM, + EV_K_FM, + 2, + 50, + 1000 + }, + { + TestFP, + EV_K_FP, + 2, + 50, + 1000 + }, + { + TestMP, + EV_K_MP, + 2, + 50, + 2000 + }, + { + TestF, + EV_K_FIRE, + 1, + 50, + 1000 + }, + { + TestM, + EV_K_MINUS, + 1, + 50, + 1000 + }, + { + TestP, + EV_K_PLUS, + 1, + 50, + 1000 + } +}; + +#define NUM_KEYS (sizeof(keys)/sizeof(key_t)) + + +//------------------------------------------------------------------------------ +// Key sequences + +static const sequence_t sequences[] = +{ + { + EV_K_TEST, + 1, + 6, + { EV_K_MINUS, EV_K_MINUS, EV_K_MINUS, EV_K_PLUS, EV_K_PLUS, EV_K_PLUS } + }, + { + EV_K_ONOFF, + 1, + 5, + { EV_K_FIRE, EV_K_FIRE, EV_K_FIRE, EV_K_FIRE, EV_K_FIRE } + } +}; + +#define NUM_SEQS (sizeof(sequences)/sizeof(sequence_t)) + + +//------------------------------------------------------------------------------ +// Inputs test functions +//------------------------------------------------------------------------------ +static int TestFMP() +{ + int count = 6; + while ( --count ) + if (( BTN_FIRE ) || ( BTN_MINUS ) || ( BTN_PLUS )) break; + + return ( count == 0 ); +} + +static int TestFM() +{ + int count = 6; + while ( --count ) + if (( BTN_FIRE ) || ( BTN_MINUS )) break; + + return ( count == 0 ); +} + +static int TestFP() +{ + int count = 6; + while ( --count ) + if (( BTN_FIRE ) || ( BTN_PLUS )) break; + + return ( count == 0 ); +} + +static int TestMP() +{ + int count = 6; + while ( --count ) + if (( BTN_MINUS ) || ( BTN_PLUS )) break; + + return ( count == 0 ); +} + +static int TestF() +{ + int count = 6; + while ( --count ) if ( BTN_FIRE ) break; + return ( count == 0 ); +} + +static int TestM() +{ + int count = 6; + while ( --count ) if ( BTN_MINUS ) break; + return ( count == 0 ); +} + +static int TestP() +{ + int count = 6; + while ( --count ) if ( BTN_PLUS ) break; + return ( count == 0 ); +} + + +//------------------------------------------------------------------------------ +// Sequence detection +//------------------------------------------------------------------------------ +static void DetectSequence() +{ + if ( ks.current == EV_K_NULL || ks.rstep != 0 ) + return; + + EV_K_e ke = ks.current; + EV_K_e se = EV_K_NULL; + + if ( ks.tick - ks.seq_tick > TI_SEQUENCE_TIMEOUT ) + { + ks.seq_count = 0; + } + + if ( ks.seq_count == MAX_SEQ_KEYS ) + { + memcpy( &ks.seq[0], &ks.seq[1], sizeof( ks.seq[0] ) * ( MAX_SEQ_KEYS - 1 ) ); + --ks.seq_count; + } + + ks.seq[ks.seq_count++] = ke; + ks.seq_tick = ks.tick; + + for ( int s = 0 ; s < NUM_SEQS ; ++s ) + { + const sequence_t *seq = &sequences[s]; + + if ( seq->length > ks.seq_count ) continue; + + int i = ks.seq_count - seq->length; + int j; + + for ( j = 0 ; j < seq->length ; ++j ) + { + if ( seq->sequence[j] != ks.seq[i+j] ) + break; + } + + if ( j == sequences[s].length ) + { + se = seq->key_event; + if ( seq->reset ) ks.seq_count = 0; + break; + } + } + + if ( se != EV_K_NULL ) + { + EMSendEvent1P( EVENT_KEY, se, 1 ); + } +} + + +//------------------------------------------------------------------------------ +// Single keys & Combos inputs detection +//------------------------------------------------------------------------------ +static void ReadKeyInputs() +{ + uint8_t nb; + int k; + + EV_K_e last = ks.last; + + ks.last = ks.current; + EV_K_e ke = EV_K_NULL; + + for ( k = 0 ; k < NUM_KEYS ; ++k ) + { + if ( keys[k].pf_test() ) + { + ke = keys[k].key_event; + break; + } + } + + uint32_t t = GetSysTick(); + + ks.current = ke; + + if ( ks.current != ks.last ) + { + ks.tick = t; + ks.rstep = 0; + ks.rcount = 0; + + if ( ks.current != EV_K_NULL ) + { + nb = keys[k].nbuttons; + + if ( ks.last != EV_K_NULL ) + { + if ( ks.nbuttons < nb ) + { + ks.nbuttons = nb; + EMSendEvent1P( EVENT_KEY, ks.current, 1 ); + } + else + { + ks.last = last; + } + } + else + { + ks.nbuttons = nb; + EMSendEvent1P( EVENT_KEY, ks.current, 1 ); + } + } + else + { + ks.nbuttons = 0; + EMSendEvent1P( EVENT_KEY, last, 0 ); + } + } + else if ( ks.current != EV_K_NULL ) + { + if ( ks.nbuttons > keys[k].nbuttons ) + { + ks.last = last; + return; + } + + switch ( ks.rstep ) + { + case 0: + ++ks.rstep; + // nobreak; + case 1: + if ( t - ks.tick > keys[k].kh1_ticks ) + { + ks.last_tick = t; + ++ks.rstep; + EMSendEvent2P( EVENT_KEY, ks.last, ks.rstep, 0 ); + } + break; + + case 2: + if ( t - ks.last_tick > TI_KEY_REPEAT ) + { + if ( t - ks.tick > keys[k].kh2_ticks ) + ++ks.rstep; + + if ( ks.rcount < 255 ) ++ks.rcount; + EMSendEvent2P( EVENT_KEY, ks.last, ks.rstep, ks.rcount ); + + ks.last_tick = t; + } + break; + + case 3: + if ( t - ks.last_tick > TI_KEY_REPEAT ) + { + if ( ks.rcount < 255 ) ++ks.rcount; + EMSendEvent2P( EVENT_KEY, ks.last, ks.rstep, ks.rcount ); + + ks.last_tick = t; + } + break; + } + } +} + + +//------------------------------------------------------------------------------ +// User inputs detection +//------------------------------------------------------------------------------ +void ReadUserInputs() +{ + static uint32_t last = 0; + + uint32_t t = GetSysTick(); + if ( t - last > TI_POLL_INPUT ) + { + last = t; + ReadKeyInputs(); + DetectSequence(); + } +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..ddc6638 --- /dev/null +++ b/src/main.c @@ -0,0 +1,86 @@ +#include "aegis.h" + + +void _putchar( char c ) +{ +} + + +void StartupDevices( void ) +{ + ConfigurePins(); + ConfigureGPIO(); + ConfigureADC(); + ConfigurePWM1(); + ConfigureSPI0(); + ConfigureHDIV(); +} + + +void ResetChip( int to ) +{ + SYS_UnlockReg(); + + FMC_SELECT_NEXT_BOOT( to & 1 ); + SYS_ResetChip(); + + SYS_LockReg(); + while ( 1 ) + ; +} + + +void BOD_IRQHandler( void ) +{ + SYS_CLEAR_BOD_INT_FLAG(); +} + + +volatile uint32_t TickCounter; + +void SysTick_Handler( void ) +{ + TickCounter++; +} + + +void WaitTicks( uint32_t ticks ) +{ + uint32_t end = TickCounter + ticks; + while ( TickCounter <= end ) + ; +} + + +/** + * @brief Firmware entry point + * + * @param None + * + * @return None + * + * @details None + */ + +int main( void ) +{ + StartupDevices(); + + RBStartup(); + TMStartup(); + EMStartup(); + BMStartup(); + SMStartup(); + + SetDisplay( &ST7735S ); + display->Startup(); + + while ( 1 ) + { + SMRefresh(); + ReadUserInputs(); + BMUpdateBattery(); + EMHandleEvents(); + TMExecTasks(); + } +} diff --git a/src/printf.c b/src/printf.c new file mode 100644 index 0000000..9302974 --- /dev/null +++ b/src/printf.c @@ -0,0 +1,914 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. These routines are thread +// safe and reentrant! +// Use this instead of the bloated standard/newlib printf cause these use +// malloc for printf (and may not be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "printf.h" + + +// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the +// printf_config.h header file +// default: undefined +#ifdef PRINTF_INCLUDE_CONFIG_H +#include "printf_config.h" +#endif + + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_NTOA_BUFFER_SIZE +#define PRINTF_NTOA_BUFFER_SIZE 32U +#endif + +// 'ftoa' conversion buffer size, this must be big enough to hold one converted +// float number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_FTOA_BUFFER_SIZE +#define PRINTF_FTOA_BUFFER_SIZE 32U +#endif + +// support for the floating point type (%f) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_FLOAT +#define PRINTF_SUPPORT_FLOAT +#endif + +// support for exponential floating point notation (%e/%g) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL +#define PRINTF_SUPPORT_EXPONENTIAL +#endif + +// define the default floating point precision +// default: 6 digits +#ifndef PRINTF_DEFAULT_FLOAT_PRECISION +#define PRINTF_DEFAULT_FLOAT_PRECISION 6U +#endif + +// define the largest float suitable to print with %f +// default: 1e9 +#ifndef PRINTF_MAX_FLOAT +#define PRINTF_MAX_FLOAT 1e9 +#endif + +// support for the long long types (%llu or %p) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG +#define PRINTF_SUPPORT_LONG_LONG +#endif + +// support for the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T +#define PRINTF_SUPPORT_PTRDIFF_T +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_ADAPT_EXP (1U << 11U) + + +// import float.h for DBL_MAX +#if defined(PRINTF_SUPPORT_FLOAT) +#include +#endif + + +// output function type +typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); + + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void* arg); + void* arg; +} out_fct_wrap_type; + + +// internal buffer output +static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) +{ + if (idx < maxlen) { + ((char*)buffer)[idx] = character; + } +} + + +// internal null output +static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)character; (void)buffer; (void)idx; (void)maxlen; +} + + +// internal _putchar wrapper +static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)buffer; (void)idx; (void)maxlen; + if (character) { + _putchar(character); + } +} + + +// internal output function wrapper +static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)idx; (void)maxlen; + if (character) { + // buffer is the output fct pointer + ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); + } +} + + +// internal secure strlen +// \return The length of the string (excluding the terminating 0) limited by 'maxsize' +static inline unsigned int _strnlen_s(const char* str, size_t maxsize) +{ + const char* s; + for (s = str; *s && maxsize--; ++s); + return (unsigned int)(s - str); +} + + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool _is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + + +// internal ASCII string to unsigned int conversion +static unsigned int _atoi(const char** str) +{ + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + + +// output the specified string in reverse, taking care of any zero-padding +static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + while (len) { + out(buf[--len], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + + +// internal itoa format +static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +{ + // pad leading zeros + if (!(flags & FLAGS_LEFT)) { + if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + // handle hash + if (flags & FLAGS_HASH) { + if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { + len--; + if (len && (base == 16U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_NTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + +// internal itoa for 'long' type +static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} + + +// internal itoa for 'long long' type +#if defined(PRINTF_SUPPORT_LONG_LONG) +static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} +#endif // PRINTF_SUPPORT_LONG_LONG + + +#if defined(PRINTF_SUPPORT_FLOAT) + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); +#endif + + +// internal ftoa for fixed decimal floating point +static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + + // test for special values + if (value != value) + return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad + if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); +#else + return 0U; +#endif + } + + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } + else if (diff < 0.5) { + } + else if ((frac == 0U) || (frac & 1U)) { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if (prec == 0U) { + diff = value - (double)whole; + if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } + else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } + } + + // pad leading zeros + if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + // check for NaN and special values + if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { + return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if (negative) { + value = -value; + } + + // default precision + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + + // determine the decimal exponent + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + union { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if (flags & FLAGS_ADAPT_EXP) { + // do we want to fall-back to "%f" mode? + if ((value >= 1e-4) && (value < 1e6)) { + if ((int)prec > expval) { + prec = (unsigned)((int)prec - expval - 1); + } + else { + prec = 0; + } + flags |= FLAGS_PRECISION; // make sure _ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } + else { + // we use one sigfig for the whole part + if ((prec > 0) && (flags & FLAGS_PRECISION)) { + --prec; + } + } + } + + // will everything fit? + unsigned int fwidth = width; + if (width > minwidth) { + // we didn't fall-back so subtract the characters required for the exponent + fwidth -= minwidth; + } else { + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if ((flags & FLAGS_LEFT) && minwidth) { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if (expval) { + value /= conv.F; + } + + // output the floating part + const size_t start_idx = idx; + idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); + + // output the exponent part + if (minwidth) { + // output the exponential symbol + out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS); + // might need to right-pad spaces + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); + } + } + return idx; +} +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + + +// internal vsnprintf +static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = _out_null; + } + + while (*format) + { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } + else { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; + case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; + case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; + case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; + case '#': flags |= FLAGS_HASH; format++; n = 1U; break; + default : n = 0U; break; + } + } while (n); + + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } + else if (*format == '*') { + const int w = va_arg(va, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } + else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } + else if (*format == '*') { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l' : + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h' : + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't' : + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j' : + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z' : + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default : + break; + } + + // evaluate specifier + switch (*format) { + case 'd' : + case 'i' : + case 'u' : + case 'x' : + case 'X' : + case 'o' : + case 'b' : { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } + else if (*format == 'o') { + base = 8U; + } + else if (*format == 'b') { + base = 2U; + } + else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + else { + const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + } + else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); + } + else { + const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } +#if defined(PRINTF_SUPPORT_FLOAT) + case 'f' : + case 'F' : + if (*format == 'F') flags |= FLAGS_UPPERCASE; + idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE; + idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + case 'c' : { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's' : { + const char* p = va_arg(va, char*); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p' : { + width = sizeof(void*) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); + } + else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%' : + out('%', buffer, idx++, maxlen); + format++; + break; + + default : + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + + +/////////////////////////////////////////////////////////////////////////////// + +int printf_(const char* format, ...) +{ + va_list va; + va_start(va, format); + char buffer[1]; + const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + + +int sprintf_(char* buffer, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + + +int snprintf_(char* buffer, size_t count, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + + +int vprintf_(const char* format, va_list va) +{ + char buffer[1]; + return _vsnprintf(_out_char, buffer, (size_t)-1, format, va); +} + + +int vsnprintf_(char* buffer, size_t count, const char* format, va_list va) +{ + return _vsnprintf(_out_buffer, buffer, count, format, va); +} + + +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...) +{ + va_list va; + va_start(va, format); + const out_fct_wrap_type out_fct_wrap = { out, arg }; + const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); + va_end(va); + return ret; +} diff --git a/src/screens.c b/src/screens.c new file mode 100644 index 0000000..35182e5 --- /dev/null +++ b/src/screens.c @@ -0,0 +1,185 @@ +//============================================================================== +// aegis/src/screens.c +//------------------------------------------------------------------------------ +// Screens management +//============================================================================== +#include "aegis.h" + +#include "screens.h" + + +//------------------------------------------------------------------------------ +// Screen object definition +//------------------------------------------------------------------------------ +typedef struct screen_desc +{ + SCREENID id; + uint8_t dialog; + uint32_t refresh_rate; + uint32_t duration; + void (*pf_init)( void ); + int (*pf_draw)( void ); + int (*pf_refresh)( void ); + void (*pf_close)( void ); + int (*pf_event)( Event_t *ev ); +} +screen_desc_t; + + +static int screen_cls( void ) { display->CLS(); return 1; } +static void screen_null( void ) {} +static int screen_null_draw( void ) { return 1; } +static int screen_noev( Event_t *ev ) { return 0; } + + +static const screen_desc_t screens[] = +{ + { + SCREEN_OFF, + 0, + 0, + 0, + screen_null, + screen_cls, + screen_null_draw, + screen_null, + screen_noev + }, + { + SCREEN_MAIN, + 0, + 50, + 0, + ScrMainInit, + ScrMainDraw, + ScrMainRefresh, + ScrMainClose, + ScrMainEvent + } +}; + +#define NUM_SCREENS (sizeof(screens)/sizeof(screen_desc_t)) + + +typedef struct screen +{ + const screen_desc_t* s; + uint32_t opening_tick; + uint32_t last_refresh; + SCREENID last_screen_id; +} +screen_t; + + +static screen_t screen; + + +//------------------------------------------------------------------------------ +// Initialization. Call at startup. +//------------------------------------------------------------------------------ +void SMStartup( void ) +{ + SMScreen( SCREEN_MAIN ); +} + + +//------------------------------------------------------------------------------ +// Screen invocation (gently asked). +//------------------------------------------------------------------------------ +void SMScreen( SCREENID sid ) +{ + EMSendEvent1P( EVENT_DISPLAY, EV_D_SCREEN, sid ); +} + + +//------------------------------------------------------------------------------ +// Screen invocation (now do it). +//------------------------------------------------------------------------------ +void SMShowScreen( SCREENID sid ) +{ + const screen_desc_t *s = 0; + + for ( int i = 0 ; i < NUM_SCREENS ; ++i ) + { + if ( screens[i].id == sid ) + { + s = &screens[i]; + break; + } + } + + if ( !s ) return; + + if ( s->dialog ) + { + if ( screen.s ) + { + screen.last_screen_id = screen.s->id; + screen.s->pf_close(); + } + screen.s = s; + screen.s->pf_init(); + screen.last_refresh = 0; + } + else + { + if ( screen.s ) + { + screen.s->pf_close(); + } + screen.s = s; + screen.s->pf_init(); + screen.last_refresh = 0; + } +} + + +//------------------------------------------------------------------------------ +// Screen refresh. +//------------------------------------------------------------------------------ +void SMRefresh( void ) +{ + if ( GetDisplayStatus() != DISPLAY_ON ) return; + + uint32_t t = GetSysTick(); + + if ( ( screen.s->duration ) && ( t - screen.opening_tick > screen.s->duration ) ) + { + SMScreen( screen.last_screen_id ); + return; + } + + if ( !screen.last_refresh ) + { + if ( screen.s->pf_draw() ) + { + screen.last_refresh = t; + } + } + else if ( ( screen.s->refresh_rate ) && ( t - screen.last_refresh > screen.s->refresh_rate ) ) + { + if ( screen.s->pf_refresh() ) + { + screen.last_refresh = t; + } + } +} + + +//------------------------------------------------------------------------------ +// Key Event. +//------------------------------------------------------------------------------ +int SMInputEvent( Event_t *ev ) +{ + return 0; +} + + +//------------------------------------------------------------------------------ +// Display/Screen Event. +//------------------------------------------------------------------------------ +int SMDisplayEvent( Event_t *ev ) +{ + return 0; +} + diff --git a/src/screens/screen_main.c b/src/screens/screen_main.c new file mode 100644 index 0000000..c2a2502 --- /dev/null +++ b/src/screens/screen_main.c @@ -0,0 +1,59 @@ +//============================================================================== +// aegis/src/screens/screen_main.c +//------------------------------------------------------------------------------ +// Main screen +//============================================================================== +#include "aegis.h" + + + +extern void ScrMainInit( void ) +{ + display->SetFont( &simple_font ); + display->SetColor( 0x00FF00 ); + display->SetBgColor( 0x000000 ); +} + +extern int ScrMainDraw( void ) +{ + display->CLS(); + return 1; +} + +extern int ScrMainRefresh( void ) +{ + static uint32_t last_r_batt = 0; + + uint32_t t = GetSysTick(); + + if ( t - last_r_batt > 1000 ) + { + last_r_batt = t; + + rect_t r = { 0, 10, 79, 19 }; + + char buf[16]; + uint32_t vbat1, vbat2; + + BMGetCells( &vbat1, &vbat2 ); + + FormatNumber( buf, vbat1, 4, 3, 3 ); + r.left = 9; + display->Print( buf, &r ); + + FormatNumber( buf, vbat2, 4, 3, 3 ); + r.left = 44; + display->Print( buf, &r ); + } + + return 1; +} + +extern void ScrMainClose( void ) +{ +} + +extern int ScrMainEvent( Event_t *ev ) +{ + return 0; +} diff --git a/src/startup_NUC1261.s b/src/startup_NUC1261.s new file mode 100644 index 0000000..997a257 --- /dev/null +++ b/src/startup_NUC1261.s @@ -0,0 +1,230 @@ +;/**************************************************************************//** +; * @file startup_M051Series.s +; * @version V2.00 +; * $Revision: 2 $ +; * $Date: 16/06/28 1:34p $ +; * @brief M051 Series Startup Source File +; * +; * @note +; * SPDX-License-Identifier: Apache-2.0 +; * +; * Copyright (C) 2011 Nuvoton Technology Corp. All rights reserved. +; * +; ******************************************************************************/ + IF :LNOT: :DEF: Stack_Size +Stack_Size EQU 0x00000400 + ENDIF + + AREA STACK, NOINIT, READWRITE, ALIGN=3 +Stack_Mem SPACE Stack_Size +__initial_sp + + +; Heap Configuration +; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> +; + IF :LNOT: :DEF: Heap_Size +Heap_Size EQU 0x00000000 + ENDIF + AREA HEAP, NOINIT, READWRITE, ALIGN=3 +__heap_base +Heap_Mem SPACE Heap_Size +__heap_limit + + + PRESERVE8 + THUMB + + +; Vector Table Mapped to Address 0 at Reset + AREA RESET, DATA, READONLY + EXPORT __Vectors + +__Vectors DCD __initial_sp ; Top of Stack + DCD Reset_Handler ; Reset Handler + DCD NMI_Handler ; NMI Handler + DCD HardFault_Handler ; Hard Fault Handler + DCD 0 ; Reserved + DCD 0 ; Reserved + DCD 0 ; Reserved + DCD 0 ; Reserved + DCD 0 ; Reserved + DCD 0 ; Reserved + DCD 0 ; Reserved + DCD SVC_Handler ; SVCall Handler + DCD 0 ; Reserved + DCD 0 ; Reserved + DCD PendSV_Handler ; PendSV Handler + DCD SysTick_Handler ; SysTick Handler + + ; External Interrupts + ; maximum of 32 External Interrupts are possible + DCD BOD_IRQHandler + DCD WDT_IRQHandler + DCD EINT024_IRQHandler + DCD EINT135_IRQHandler + DCD GPAB_IRQHandler + DCD GPCDEF_IRQHandler + DCD PWM0_IRQHandler + DCD PWM1_IRQHandler + DCD TMR0_IRQHandler + DCD TMR1_IRQHandler + DCD TMR2_IRQHandler + DCD TMR3_IRQHandler + DCD UART02_IRQHandler + DCD UART1_IRQHandler + DCD SPI0_IRQHandler + DCD SPI1_IRQHandler + DCD Default_Handler + DCD Default_Handler + DCD I2C0_IRQHandler + DCD I2C1_IRQHandler + DCD Default_Handler + DCD Default_Handler + DCD USCI_IRQHandler + DCD USBD_IRQHandler + DCD SC01_IRQHandler + DCD ACMP01_IRQHandler + DCD PDMA_IRQHandler + DCD Default_Handler + DCD PWRWU_IRQHandler + DCD ADC_IRQHandler + DCD CLKDIRC_IRQHandler + DCD RTC_IRQHandler + + + + AREA |.text|, CODE, READONLY + + + +; Reset Handler + + ENTRY + +Reset_Handler PROC + EXPORT Reset_Handler [WEAK] + IMPORT SystemInit + IMPORT __main + + LDR R0, =SystemInit + BLX R0 + LDR R0, =__main + BX R0 + ENDP + + + +; Dummy Exception Handlers (infinite loops which can be modified) + +NMI_Handler PROC + EXPORT NMI_Handler [WEAK] + B . + ENDP +HardFault_Handler\ + PROC + EXPORT HardFault_Handler [WEAK] + B . + ENDP +SVC_Handler PROC + EXPORT SVC_Handler [WEAK] + B . + ENDP +PendSV_Handler PROC + EXPORT PendSV_Handler [WEAK] + B . + ENDP +SysTick_Handler PROC + EXPORT SysTick_Handler [WEAK] + B . + ENDP + +Default_Handler PROC + + EXPORT BOD_IRQHandler [WEAK] + EXPORT WDT_IRQHandler [WEAK] + EXPORT EINT024_IRQHandler [WEAK] + EXPORT EINT135_IRQHandler [WEAK] + EXPORT GPAB_IRQHandler [WEAK] + EXPORT GPCDEF_IRQHandler [WEAK] + EXPORT PWM0_IRQHandler [WEAK] + EXPORT PWM1_IRQHandler [WEAK] + EXPORT TMR0_IRQHandler [WEAK] + EXPORT TMR1_IRQHandler [WEAK] + EXPORT TMR2_IRQHandler [WEAK] + EXPORT TMR3_IRQHandler [WEAK] + EXPORT UART02_IRQHandler [WEAK] + EXPORT UART1_IRQHandler [WEAK] + EXPORT SPI0_IRQHandler [WEAK] + EXPORT SPI1_IRQHandler [WEAK] + EXPORT I2C0_IRQHandler [WEAK] + EXPORT I2C1_IRQHandler [WEAK] + EXPORT USCI_IRQHandler [WEAK] + EXPORT USBD_IRQHandler [WEAK] + EXPORT SC01_IRQHandler [WEAK] + EXPORT ACMP01_IRQHandler [WEAK] + EXPORT PDMA_IRQHandler [WEAK] + EXPORT PWRWU_IRQHandler [WEAK] + EXPORT ADC_IRQHandler [WEAK] + EXPORT CLKDIRC_IRQHandler [WEAK] + EXPORT RTC_IRQHandler [WEAK] + +BOD_IRQHandler +WDT_IRQHandler +EINT024_IRQHandler +EINT135_IRQHandler +GPAB_IRQHandler +GPCDEF_IRQHandler +PWM0_IRQHandler +PWM1_IRQHandler +TMR0_IRQHandler +TMR1_IRQHandler +TMR2_IRQHandler +TMR3_IRQHandler +UART02_IRQHandler +UART1_IRQHandler +SPI0_IRQHandler +SPI1_IRQHandler +I2C0_IRQHandler +I2C1_IRQHandler +USCI_IRQHandler +USBD_IRQHandler +SC01_IRQHandler +ACMP01_IRQHandler +PDMA_IRQHandler +PWRWU_IRQHandler +ADC_IRQHandler +CLKDIRC_IRQHandler +RTC_IRQHandler + B . + ENDP + + + ALIGN + + +; User Initial Stack & Heap + + IF :DEF:__MICROLIB + + EXPORT __initial_sp + EXPORT __heap_base + EXPORT __heap_limit + + ELSE + + IMPORT __use_two_region_memory + EXPORT __user_initial_stackheap +__user_initial_stackheap + + LDR R0, = Heap_Mem + LDR R1, = (Stack_Mem + Stack_Size) + LDR R2, = (Heap_Mem + Heap_Size) + LDR R3, = Stack_Mem + BX LR + + ALIGN + + ENDIF + + END diff --git a/src/system.c b/src/system.c new file mode 100644 index 0000000..367c772 --- /dev/null +++ b/src/system.c @@ -0,0 +1,288 @@ +//============================================================================== +// aegis/src/system.c +//------------------------------------------------------------------------------ +// Miscellaneous systems objects +//============================================================================== +#include "aegis.h" + +#include + + +//============================================================================== +// Ring Buffers +//------------------------------------------------------------------------------ +// Ring buffers are the way different parts of the software communicate. +// The maximum number of available ringbuffers is defined in the aegis.h header. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Structure definition +//------------------------------------------------------------------------------ +typedef struct ringbuffer +{ + void* pBuffer; + size_t BufferLength; + size_t PacketSize; + intptr_t Head; + intptr_t Tail; + uint32_t NMsgs; + SYS_RB_STATUS eStatus; +} +ringbuffer_t; + + +//------------------------------------------------------------------------------ +// Buffers +//------------------------------------------------------------------------------ + +static ringbuffer_t ringbuffers[SYS_MAX_RINGBUFFERS]; + + +//------------------------------------------------------------------------------ +// Startup +//------------------------------------------------------------------------------ +// This method should be called at system startup. +//------------------------------------------------------------------------------ +void RBStartup() +{ + for ( int rbid = 0 ; rbid < SYS_MAX_RINGBUFFERS ; ++rbid ) + { + ringbuffers[rbid].eStatus = RB_UNUSED; + } +} + + +//------------------------------------------------------------------------------ +// Allocation +//------------------------------------------------------------------------------ +// Allocate a ringbuffer for a specific purpose. +// A buffer must be provided, along with the buffer length and the individual +// message length. The buffer size needs not to be an exact multiple of the +// message length, but this would be a loss of space. +//------------------------------------------------------------------------------ +int RBAlloc( void *buf, size_t bsize, size_t msize ) +{ + int rbid; + ringbuffer_t *rb = NULL; + + for ( rbid = 0 ; rbid < SYS_MAX_RINGBUFFERS ; ++rbid ) + { + rb = &ringbuffers[rbid]; + if ( rb->eStatus == RB_UNUSED ) + break; + } + + if ( rbid >= SYS_MAX_RINGBUFFERS ) + return -1; + + rb->pBuffer = buf; + rb->BufferLength = bsize; + rb->PacketSize = msize; + RBReset( rbid ); + + return rbid; +} + + +//------------------------------------------------------------------------------ +// Reset +//------------------------------------------------------------------------------ +// Clears a buffer. +//------------------------------------------------------------------------------ +void RBReset( int rbid ) +{ + ringbuffer_t *rb = &ringbuffers[rbid]; + + rb->eStatus = RB_AVAIL; + rb->Head = 0; + rb->Tail = 0; + rb->NMsgs = 0; +} + + +//------------------------------------------------------------------------------ +// Polling +//------------------------------------------------------------------------------ +// Returns a non-zero value if messages are pending. +//------------------------------------------------------------------------------ +int RBHasMessages( int rbid ) +{ + return ( ringbuffers[rbid].NMsgs ); +} + + +//------------------------------------------------------------------------------ +// Send a packet +//------------------------------------------------------------------------------ +// Returns 0 for success, -1 if buffer full. +//------------------------------------------------------------------------------ +int RBSendMessage( int rbid, const void *msg ) +{ + ringbuffer_t *rb = &ringbuffers[rbid]; + + if ( rb->eStatus == RB_FULL ) return -1; + + memcpy( rb->pBuffer + rb->Tail, msg, rb->PacketSize ); + rb->Tail += rb->PacketSize; + + if ( rb->Tail + rb->PacketSize > rb->BufferLength ) + { + rb->Tail = 0; + } + + ++rb->NMsgs; + + if ( rb->Tail == rb->Head ) + { + rb->eStatus = RB_FULL; + } + + return 0; +} + + +//------------------------------------------------------------------------------ +// Read a packet +//------------------------------------------------------------------------------ +// Returns 0 for success, -1 if buffer empty. +//------------------------------------------------------------------------------ +int RBReadMessage( int rbid, void *msg ) +{ + ringbuffer_t *rb = &ringbuffers[rbid]; + + if ( rb->NMsgs == 0 ) return -1; + + memcpy( msg, rb->pBuffer + rb->Head, rb->PacketSize ); + rb->Head += rb->PacketSize; + + if ( rb->Head + rb->PacketSize > rb->BufferLength ) + { + rb->Head = 0; + } + + --rb->NMsgs; + rb->eStatus = RB_AVAIL; + + return rb->NMsgs; +} + + +//============================================================================== +// Task management +//------------------------------------------------------------------------------ +typedef struct task +{ + uint8_t *pid; + void (*pftask)( uint32_t ); + uint32_t param; + uint32_t delay; + uint32_t interval; + uint32_t last; + uint8_t repeat; + SYS_TASK_STATUS status; +} +task_t; + +static task_t tasks[SYS_MAX_TASKS]; + + +//------------------------------------------------------------------------------ +// Call at startup. +//------------------------------------------------------------------------------ +void TMStartup() +{ + for ( int k = 0 ; k < SYS_MAX_TASKS ; ++k ) tasks[k].status = TASK_UNUSED; +} + + +//------------------------------------------------------------------------------ +// Task creation. +//------------------------------------------------------------------------------ +int TMCreateTask( uint32_t delay, + void (*pftask)( uint32_t ), + uint32_t param, + uint8_t repeat, + uint32_t interval, + uint8_t *pid ) +{ + int k; + + for ( k = 0 ; k < SYS_MAX_TASKS ; ++k ) + if ( tasks[k].status == TASK_UNUSED ) break; + + if ( k == SYS_MAX_TASKS ) + { + if ( pid ) *pid = 0; + return 0; + } + + task_t *task = &tasks[k]; + + task->pid = pid; + if ( pid ) *pid = ++k; + + task->pftask = pftask; + task->param = param; + task->delay = delay; + task->repeat = repeat; + task->interval = interval; + + task->last = GetSysTick(); + task->status = TASK_ACTIVE; + + return k; +} + + +void TMDestroyTask( uint8_t id ) +{ + if ( !id || id > SYS_MAX_TASKS ) return; + task_t *task = &tasks[--id]; + + if ( task->status == TASK_UNUSED ) return; + + task->status = TASK_UNUSED; + if ( task->pid ) *task->pid = 0; +} + + +void TMUpdateTask( uint8_t id, uint32_t param, uint32_t delay ) +{ + if ( !id || id > SYS_MAX_TASKS ) return; + task_t *task = &tasks[--id]; + + task->param = param; + task->delay = delay; + + if ( task->repeat ) + { + task->interval = delay; + } +} + + +void TMExecTasks() +{ + for ( int k = 0 ; k < SYS_MAX_TASKS ; ++k ) + { + if ( tasks[k].status != TASK_ACTIVE ) continue; + + uint32_t t = GetSysTick(); + + if ( t - tasks[k].last >= tasks[k].delay ) + { + tasks[k].pftask( tasks[k].param ); + tasks[k].last = t; + + if ( tasks[k].repeat ) + { + tasks[k].delay = tasks[k].interval; + } + else + { + tasks[k].status = TASK_UNUSED; + if ( tasks[k].pid ) *tasks[k].pid = 0; + } + } + } +}