Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Robey Pointer
reform
Commits
63eaf98a
Commit
63eaf98a
authored
Aug 17, 2021
by
Robey Pointer
Browse files
improve the menu to allow hidden items and a bigger font; remove old gfx code
parent
fa762376
Changes
12
Hide whitespace changes
Inline
Side-by-side
reform2-keyboard-fw/Keyboard.c
View file @
63eaf98a
...
...
@@ -41,6 +41,7 @@
#include
"scancodes.h"
#include
"controller.h"
#include
"hid_report.h"
#include
"menu.h"
#include
"ux.h"
#include
"Keyboard.h"
...
...
@@ -136,29 +137,18 @@ static void remote_check_for_low_battery(void) {
}
}
int
oledbrt
=
0
;
void
oled_brightness_inc
(
void
)
{
oledbrt
+=
10
;
if
(
oledbrt
>=
0xff
)
oledbrt
=
0xff
;
gfx_contrast
(
oledbrt
);
}
void
oled_brightness_dec
(
void
)
{
oledbrt
-=
10
;
if
(
oledbrt
<
0
)
oledbrt
=
0
;
gfx_contrast
(
oledbrt
);
}
int16_t
pwmval
=
8
;
void
kbd_brightness_init
(
void
)
{
// initial brightness
OCR0A
=
pwmval
;
// initial brightness
OCR0A
=
pwmval
;
// clear/set, WGM1:0 set (Phase correct PWM)
TCCR0A
=
(
1
<<
7
)
|
(
0
<<
6
)
|
(
0
<<
1
)
|
1
;
// clear/set, WGM1:0 set (Phase correct PWM)
TCCR0A
=
(
1
<<
7
)
|
(
0
<<
6
)
|
(
0
<<
1
)
|
1
;
// 3=WGM02, (cs02 2:0 -> clock/256 = 100)
TCCR0B
=
/*(1 << 3) |*/
(
1
<<
0
)
|
(
0
<<
1
)
|
1
;
// 3=WGM02, (cs02 2:0 -> clock/256 = 100)
TCCR0B
=
/*(1 << 3) |*/
(
1
<<
0
)
|
(
0
<<
1
)
|
1
;
}
void
kbd_brightness_inc
(
void
)
{
...
...
@@ -180,36 +170,6 @@ void kbd_brightness_set(int brite) {
OCR0A
=
pwmval
;
}
void
remote_turn_on_som
(
void
)
{
gfx_clear
();
empty_serial
();
term_x
=
0
;
term_y
=
0
;
Serial_SendByte
(
'1'
);
Serial_SendByte
(
'p'
);
Serial_SendByte
(
'\r'
);
Delay_MS
(
1
);
empty_serial
();
ux_splash
();
kbd_brightness_init
();
}
void
remote_turn_off_som
(
void
)
{
ux_unsplash
();
empty_serial
();
term_x
=
0
;
term_y
=
0
;
Serial_SendByte
(
'0'
);
Serial_SendByte
(
'p'
);
Serial_SendByte
(
'\r'
);
Delay_MS
(
1
);
empty_serial
();
}
void
remote_reset_som
(
void
)
{
empty_serial
();
...
...
@@ -313,18 +273,21 @@ const MenuItem menu_items[] = {
{
"KBD Power-Off p"
,
KEY_P
}
};
#include
"menu.h"
const
menu_item_t
circle_menu
[]
=
{
{
"Exit Menu
ESC"
,
KEY_ESCAPE
,
NULL
},
{
"Power On
1"
,
KEY_1
,
controller_turn_on_som
},
{
"Power Off
0"
,
KEY_0
,
controller_turn_off_som
},
{
"Reset
R"
,
KEY_R
,
NULL
},
{
"Battery Status
B"
,
KEY_B
,
ux_show_battery
},
{
"Key
Backl
ight - F1"
,
KEY_F1
,
NULL
},
{
"Key
Backl
ight + F2"
,
KEY_F2
,
NULL
},
{
"Wake
SPC"
,
KEY_SPACE
,
NULL
},
{
"System Status
S"
,
KEY_S
,
ux_show_status
},
MENU_END
{
"Exit Menu
"
,
"
ESC"
,
KEY_ESCAPE
,
true
,
NULL
},
{
"Power On
"
,
"
1"
,
KEY_1
,
true
,
controller_turn_on_som
},
{
"Power Off
"
,
"
0"
,
KEY_0
,
true
,
controller_turn_off_som
},
{
"Reset
"
,
"
R"
,
KEY_R
,
true
,
NULL
},
{
"Battery Status
"
,
"
B"
,
KEY_B
,
true
,
ux_show_battery
},
{
"Key
L
ight -
"
,
"
F1"
,
KEY_F1
,
false
,
ux_decrease_oled_brightness
},
{
"Key
L
ight +
"
,
"
F2"
,
KEY_F2
,
false
,
ux_increase_oled_brightness
},
{
"Wake
"
,
"
SPC"
,
KEY_SPACE
,
true
,
NULL
},
{
"System Status
"
,
"
S"
,
KEY_S
,
true
,
ux_show_status
},
MENU_END
};
#endif
...
...
@@ -334,16 +297,6 @@ int active_meta_mode = 0;
int
execute_meta_function
(
int
keycode
);
void
render_menu
(
int
y
)
{
gfx_clear
();
gfx_invert_row
(
current_menu_y
-
y
);
for
(
int
i
=
0
;
i
<
MENU_NUM_ITEMS
;
i
++
)
{
gfx_poke_str
(
0
,
i
-
y
,
menu_items
[
i
].
title
);
}
gfx_on
();
gfx_flush
();
}
int
execute_menu_function
(
int
y
)
{
if
(
y
>=
0
&&
y
<
MENU_NUM_ITEMS
)
{
return
execute_meta_function
(
menu_items
[
y
].
keycode
);
...
...
@@ -353,16 +306,7 @@ int execute_menu_function(int y) {
// returns 1 for navigation function (stay in meta mode), 0 for terminal function
int
execute_meta_function
(
int
keycode
)
{
if
(
keycode
==
KEY_0
)
{
// TODO: are you sure?
remote_turn_off_som
();
EnterPowerOff
();
}
else
if
(
keycode
==
KEY_1
)
{
remote_turn_on_som
();
return
0
;
}
else
if
(
keycode
==
KEY_R
)
{
if
(
keycode
==
KEY_R
)
{
// TODO: are you sure?
remote_reset_som
();
}
...
...
@@ -375,14 +319,6 @@ int execute_meta_function(int keycode) {
else if (keycode == KEY_V) {
remote_turn_off_aux();
}*/
else
if
(
keycode
==
KEY_B
)
{
ux_show_battery
();
return
0
;
}
else
if
(
keycode
==
KEY_S
)
{
ux_show_status
();
return
0
;
}
else
if
(
keycode
==
KEY_Z
)
{
low_battery_alert
=
!
low_battery_alert
;
if
(
!
low_battery_alert
)
{
...
...
@@ -391,42 +327,6 @@ int execute_meta_function(int keycode) {
}
return
0
;
}
else
if
(
keycode
==
KEY_F1
)
{
kbd_brightness_dec
();
return
1
;
}
else
if
(
keycode
==
KEY_F2
)
{
kbd_brightness_inc
();
return
1
;
}
else
if
(
keycode
==
HID_KEYBOARD_SC_UP_ARROW
)
{
current_menu_y
--
;
if
(
current_menu_y
<
0
)
current_menu_y
=
0
;
if
(
current_menu_y
<=
current_scroll_y
)
current_scroll_y
--
;
if
(
current_scroll_y
<
0
)
current_scroll_y
=
0
;
render_menu
(
current_scroll_y
);
return
1
;
}
else
if
(
keycode
==
HID_KEYBOARD_SC_DOWN_ARROW
)
{
current_menu_y
++
;
if
(
current_menu_y
>=
MENU_NUM_ITEMS
)
current_menu_y
=
MENU_NUM_ITEMS
-
1
;
if
(
current_menu_y
>=
current_scroll_y
+
3
)
current_scroll_y
++
;
render_menu
(
current_scroll_y
);
return
1
;
}
else
if
(
keycode
==
KEY_ENTER
)
{
return
execute_menu_function
(
current_menu_y
);
}
else
if
(
keycode
==
KEY_ESCAPE
)
{
gfx_clear
();
gfx_flush
();
}
else
if
(
keycode
==
KEY_P
)
{
EnterPowerOff
();
}
gfx_clear
();
gfx_flush
();
return
0
;
}
...
...
@@ -533,14 +433,7 @@ static uint8_t scan_keyboard_enhanced(uint8_t keys[]) {
uint8_t
count
=
scan_keyboard
(
keys
);
if
(
count
==
1
&&
keys
[
0
]
==
KEY_CIRCLE
&&
!
in_circle_menu
&&
!
previous_key
)
{
#if 0
current_scroll_y = 0;
current_menu_y = 0;
// render menu
render_menu(current_scroll_y);
#else
menu_start
(
circle_menu
);
#endif
in_circle_menu
=
true
;
previous_key
=
KEY_CIRCLE
;
return
0
;
...
...
@@ -552,13 +445,8 @@ static uint8_t scan_keyboard_enhanced(uint8_t keys[]) {
if
(
in_circle_menu
)
{
if
(
count
==
1
&&
keys
[
0
]
!=
previous_key
)
{
#if 0
int stay_in_menu = execute_meta_function(keys[0]);
#else
int
stay_in_menu
=
menu_key
(
keys
[
0
]);
#endif
in_circle_menu
=
menu_key
(
keys
[
0
]);
previous_key
=
keys
[
0
];
if
(
!
stay_in_menu
)
in_circle_menu
=
false
;
}
return
0
;
}
...
...
@@ -681,8 +569,6 @@ void SetupHardware()
kbd_brightness_init
();
oled_init
();
display_init
(
&
font_oranj
);
gfx_clear
();
gfx_flush
();
hid_report_init
();
ux_splash
();
...
...
reform2-keyboard-fw/Keyboard.h
View file @
63eaf98a
...
...
@@ -67,6 +67,7 @@
/* Function Prototypes: */
void
SetupHardware
(
void
);
void
kbd_brightness_init
(
void
);
void
EVENT_USB_Device_Connect
(
void
);
void
EVENT_USB_Device_Disconnect
(
void
);
...
...
reform2-keyboard-fw/controller.c
View file @
63eaf98a
...
...
@@ -11,6 +11,9 @@
#include
<stdlib.h>
#include
"LUFA/Drivers/Peripheral/Serial.h"
#include
"controller.h"
#include
"display.h"
#include
"Keyboard.h"
#include
"ux.h"
// how long do we wait (busy loops) before giving up on a response
#define TIMEOUT (500000)
...
...
@@ -95,19 +98,18 @@ void controller_probe_batteries(battery_info_t *info) {
info
->
total_percent
=
atoi
(
bat_gauge
);
}
bool
controller_turn_on_som
(
void
)
{
void
controller_turn_on_som
(
void
)
{
display_clear
();
display_flush
();
controller_send
(
"1p"
);
flush
();
ux_splash
();
kbd_brightness_init
();
return
false
;
}
bool
controller_turn_off_som
(
void
)
{
void
controller_turn_off_som
(
void
)
{
ux_unsplash
();
controller_send
(
"0p"
);
flush
();
return
false
;
EnterPowerOff
()
;
}
reform2-keyboard-fw/controller.h
View file @
63eaf98a
...
...
@@ -20,5 +20,5 @@ typedef struct {
void
controller_init
(
void
);
const
char
*
controller_request
(
const
char
*
command
);
void
controller_probe_batteries
(
battery_info_t
*
info
);
bool
controller_turn_on_som
(
void
);
bool
controller_turn_off_som
(
void
);
void
controller_turn_on_som
(
void
);
void
controller_turn_off_som
(
void
);
reform2-keyboard-fw/display.c
View file @
63eaf98a
...
...
@@ -27,7 +27,6 @@ static uint8_t text_width = 0;
static
uint8_t
text_cursor
=
0
;
static
bool
text_dirty
=
false
;
static
bool
text_inverting
=
false
;
static
uint8_t
text_roll
=
0
;
// FIXME hack
void
display_init
(
const
monospace_font_t
*
font
)
{
text_font
=
font
;
...
...
@@ -43,7 +42,6 @@ void display_clear(void) {
text_cursor
=
0
;
text_dirty
=
true
;
text_inverting
=
false
;
text_roll
=
0
;
}
void
display_clear_line
(
uint8_t
line
)
{
...
...
@@ -59,6 +57,10 @@ void display_invert_line(uint8_t line) {
}
}
uint8_t
display_text_width
(
void
)
{
return
text_width
;
}
uint8_t
display_text_height
(
void
)
{
return
text_height
;
}
...
...
@@ -144,12 +146,6 @@ void display_flush(void) {
int
i
=
0
;
uint8_t
cursor
=
0
;
for
(
uint8_t
y
=
0
;
y
<
text_height
;
y
++
)
{
if
(
y
<
text_roll
)
{
// skip row
for
(
uint8_t
x
=
0
;
x
<
DisplayWidth
;
x
++
)
oled_render
(
0
);
continue
;
}
for
(
uint8_t
row
=
0
;
row
<
stride
;
row
++
)
{
// back up if we're drawing the later row of a tall font
if
(
row
>
0
)
cursor
-=
text_width
;
...
...
@@ -167,17 +163,15 @@ void display_flush(void) {
}
for
(
uint8_t
pad
=
0
;
pad
<
x_offset
;
pad
++
)
framebuffer
[
i
++
]
=
0
;
}
if
(
text_roll
==
1
&&
text_font
->
height
>
8
)
{
// skip row
for
(
uint8_t
x
=
0
;
x
<
DisplayWidth
;
x
++
)
oled_render
(
0
);
}
render
();
text_dirty
=
false
;
}
void
display_bitmap
(
const
uint8_t
*
data
)
{
memmove
(
framebuffer
,
data
,
sizeof
(
framebuffer
));
void
display_bitmap
(
uint16_t
offset
,
const
uint8_t
*
data
,
uint16_t
len
)
{
uint16_t
max_len
=
sizeof
(
framebuffer
)
-
offset
;
if
(
len
>
max_len
)
len
=
max_len
;
memmove
(
framebuffer
+
offset
,
data
,
len
);
render
();
}
...
...
@@ -188,24 +182,49 @@ static void check_effect(int i) {
render
();
}
void
display_packed_bitmap
(
const
uint8_t
*
data
,
bool
cursor_effect
)
{
int
i
=
0
;
while
(
true
)
{
uint8_t
header
=
pgm_read_byte
(
data
++
);
if
(
header
==
0
)
break
;
static
uint8_t
data_read_byte
(
const
uint8_t
*
p
)
{
return
*
p
;
}
static
uint8_t
code_read_byte
(
const
uint8_t
*
p
)
{
return
pgm_read_byte
(
p
);
}
static
void
_display_packed_bitmap
(
uint8_t
(
*
reader
)(
const
uint8_t
*
p
),
uint16_t
offset
,
const
uint8_t
*
data
,
uint16_t
len
,
bool
cursor_effect
)
{
int
i
=
offset
;
const
uint8_t
*
end
=
data
+
len
;
while
(
i
<
sizeof
(
framebuffer
)
&&
data
<
end
)
{
uint8_t
header
=
reader
(
data
++
);
if
(
header
==
0
||
data
>=
end
)
break
;
uint8_t
n
=
header
&
0x7f
;
if
(
header
&
0x80
)
{
uint8_t
repeat
=
pgm_read_byte
(
data
++
);
uint8_t
repeat
=
reader
(
data
++
);
for
(
int
j
=
0
;
j
<
n
;
j
++
)
{
if
(
i
>=
sizeof
(
framebuffer
))
break
;
framebuffer
[
i
++
]
=
repeat
;
if
(
cursor_effect
)
check_effect
(
i
);
}
}
else
{
for
(
int
j
=
0
;
j
<
n
;
j
++
)
{
framebuffer
[
i
++
]
=
pgm_read_byte
(
data
++
);
if
(
i
>=
sizeof
(
framebuffer
)
||
data
>=
end
)
break
;
framebuffer
[
i
++
]
=
reader
(
data
++
);
if
(
cursor_effect
)
check_effect
(
i
);
}
}
}
render
();
}
void
display_packed_bitmap
(
uint16_t
offset
,
const
uint8_t
*
data
,
uint16_t
len
)
{
_display_packed_bitmap
(
data_read_byte
,
offset
,
data
,
len
,
false
);
}
void
display_packed_bitmap_pgm
(
uint16_t
offset
,
const
uint8_t
*
data
,
uint16_t
len
,
bool
cursor_effect
)
{
_display_packed_bitmap
(
code_read_byte
,
offset
,
data
,
len
,
cursor_effect
);
}
reform2-keyboard-fw/display.h
View file @
63eaf98a
...
...
@@ -32,6 +32,7 @@ void display_init(const monospace_font_t *font);
void
display_clear
(
void
);
void
display_clear_line
(
uint8_t
line
);
void
display_invert_line
(
uint8_t
line
);
uint8_t
display_text_width
(
void
);
uint8_t
display_text_height
(
void
);
void
display_scroll
(
void
);
void
display_putc
(
uint8_t
c
);
...
...
@@ -40,4 +41,6 @@ void display_write(const char *text);
void
display_move
(
uint8_t
x
,
uint8_t
y
);
void
display_invert
(
bool
invert
);
void
display_flush
(
void
);
void
display_packed_bitmap
(
const
uint8_t
*
data
,
bool
cursor_effect
);
void
display_bitmap
(
uint16_t
offset
,
const
uint8_t
*
data
,
uint16_t
len
);
void
display_packed_bitmap
(
uint16_t
offset
,
const
uint8_t
*
data
,
uint16_t
len
);
void
display_packed_bitmap_pgm
(
uint16_t
offset
,
const
uint8_t
*
data
,
uint16_t
len
,
bool
cursor_effect
);
reform2-keyboard-fw/menu.c
View file @
63eaf98a
...
...
@@ -18,10 +18,20 @@ static uint8_t scroll_top = 0;
static
void
render
(
void
)
{
display_clear
();
for
(
int
y
=
0
;
y
<
display_text_height
()
&&
items
[
scroll_top
+
y
].
label
!=
NULL
;
y
++
)
{
uint8_t
row
=
scroll_top
;
for
(
int
y
=
0
;
y
<
display_text_height
();
y
++
)
{
// a blank description is a "hidden" menu item, accessible only via its key
while
(
items
[
row
].
label
!=
NULL
&&
items
[
row
].
label
[
0
]
==
0
)
row
++
;
if
(
items
[
row
].
label
==
NULL
)
break
;
// end of menu
display_move
(
0
,
y
);
display_write
(
items
[
scroll_top
+
y
].
label
);
if
(
scroll_top
+
y
==
current
)
display_invert_line
(
y
);
display_write
(
items
[
row
].
label
);
if
(
items
[
row
].
key_label
!=
NULL
)
{
display_move
(
display_text_width
()
-
strlen
(
items
[
row
].
key_label
),
y
);
display_write
(
items
[
row
].
key_label
);
}
if
(
row
==
current
)
display_invert_line
(
y
);
row
++
;
}
display_flush
();
}
...
...
@@ -37,6 +47,10 @@ void menu_stop(void) {
items
=
NULL
;
}
bool
menu_is_active
(
void
)
{
return
items
!=
NULL
;
}
static
bool
menu_action
(
uint8_t
index
)
{
if
(
!
items
[
index
].
action
)
{
// no action = exit menu
...
...
@@ -46,7 +60,8 @@ static bool menu_action(uint8_t index) {
return
false
;
}
if
(
!
items
[
index
].
action
())
{
items
[
index
].
action
();
if
(
items
[
index
].
terminate_menu
)
{
// don't clear the screen: might have been a display request
menu_stop
();
return
false
;
...
...
@@ -56,16 +71,22 @@ static bool menu_action(uint8_t index) {
// returns true to stay in menu mode
bool
menu_key
(
uint8_t
key
)
{
uint8_t
prev_row
=
current
;
// navigation?
switch
(
key
)
{
case
HID_KEYBOARD_SC
_UP_ARROW
:
case
KEY
_UP_ARROW
:
if
(
current
>
0
)
current
--
;
if
(
current
<
scroll_top
)
scroll_top
--
;
while
(
current
>
0
&&
items
[
current
].
label
[
0
]
==
0
)
current
--
;
if
(
current
==
0
&&
items
[
current
].
label
[
0
]
==
0
)
current
=
prev_row
;
while
(
current
<
scroll_top
)
scroll_top
--
;
render
();
return
true
;
case
HID_KEYBOARD_SC_DOWN_ARROW
:
if
(
items
[
current
+
1
].
label
!=
NULL
)
current
++
;
if
(
current
>=
scroll_top
+
display_text_height
())
scroll_top
++
;
case
KEY_DOWN_ARROW
:
current
++
;
while
(
items
[
current
].
label
!=
NULL
&&
items
[
current
].
label
[
0
]
==
0
)
current
++
;
if
(
items
[
current
].
label
==
NULL
)
current
=
prev_row
;
while
(
current
>=
scroll_top
+
display_text_height
())
scroll_top
++
;
render
();
return
true
;
case
KEY_ENTER
:
...
...
reform2-keyboard-fw/menu.h
View file @
63eaf98a
...
...
@@ -10,12 +10,15 @@
#include
<stdint.h>
typedef
struct
{
const
char
*
label
;
const
char
*
label
;
// left side of screen
const
char
*
key_label
;
// right side of screen
uint8_t
keycode
;
bool
(
*
action
)(
void
);
// return true to stay in menu mode
bool
terminate_menu
;
// if false, we stay in menu mode afterwards
void
(
*
action
)(
void
);
}
menu_item_t
;
#define MENU_END { NULL,
0
, NULL }
#define MENU_END { NULL,
NULL, 0, false
, NULL }
void
menu_start
(
const
menu_item_t
*
menu
);
void
menu_stop
(
void
);
bool
menu_is_active
(
void
);
bool
menu_key
(
uint8_t
key
);
reform2-keyboard-fw/ssd1306.c
View file @
63eaf98a
...
...
@@ -2,7 +2,6 @@
#include
"i2c.h"
#include
<string.h>
#include
<avr/pgmspace.h>
#include
"gfx/font.c"
// in case you want to rotate the screen 180 degrees (half-tau)
#define ROTATE 0
...
...
@@ -105,185 +104,3 @@ void oled_start_render(void) {
void
oled_finish_render
(
void
)
{
i2c_master_stop
();
}
struct
CharacterMatrix
display
;
bool
gfx_off
(
void
)
{
bool
success
=
false
;
//send_cmd1(InvertDisplay);
send_cmd1
(
DisplayOff
);
success
=
true
;
done:
return
success
;
}
bool
gfx_on
(
void
)
{
bool
success
=
false
;
send_cmd1
(
NormalDisplay
);
send_cmd1
(
DisplayOn
);
success
=
true
;
done:
return
success
;
}
void
gfx_contrast
(
int
c
)
{
send_cmd2
(
SetContrast
,
c
);
done:
return
;
}
void
matrix_write_char_inner
(
struct
CharacterMatrix
*
matrix
,
uint8_t
c
)
{
*
matrix
->
cursor
=
c
;
++
matrix
->
cursor
;
if
(
matrix
->
cursor
-
&
matrix
->
display
[
0
][
0
]
==
sizeof
(
matrix
->
display
))
{
// We went off the end; scroll the display upwards by one line
memmove
(
&
matrix
->
display
[
0
],
&
matrix
->
display
[
1
],
MatrixCols
*
(
MatrixRows
-
1
));
matrix
->
cursor
=
&
matrix
->
display
[
MatrixRows
-
1
][
0
];
memset
(
matrix
->
cursor
,
' '
,
MatrixCols
);
}
}
void
matrix_write_char
(
struct
CharacterMatrix
*
matrix
,
uint8_t
c
)
{
matrix
->
dirty
=
true
;
if
(
c
==
'\n'
)
{
// Clear to end of line from the cursor and then move to the
// start of the next line
uint8_t
cursor_col
=
(
matrix
->
cursor
-
&
matrix
->
display
[
0
][
0
])
%
MatrixCols
;
while
(
cursor_col
++
<
MatrixCols
)
{
matrix_write_char_inner
(
matrix
,
' '
);
}
return
;
}
matrix_write_char_inner
(
matrix
,
c
);
}
void
gfx_poke
(
uint8_t
x
,
uint8_t
y
,
uint8_t
c
)
{
display
.
display
[
y
][
x
]
=
c
;
}
void
gfx_poke_str
(
uint8_t
x
,
uint8_t
y
,
char
*
str
)
{
int
len
=
strlen
(
str
);
if
(
len
>
21
)
len
=
21
;
// clip
if
(
y
<
0
||
y
>
3
)
return
;
for
(
int
xx
=
x
;
xx
<
x
+
len
&&
xx
<
21
;
xx
++
)
{
if
(
xx
>=
0
&&
xx
<
21
)
{
display
.
display
[
y
][
xx
]
=
(
uint8_t
)
str
[
xx
-
x
];
}
}
}
void
gfx_write_char
(
uint8_t
c
)
{
matrix_write_char
(
&
display
,
c
);
}