Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
François Revol
firmware
Commits
c3bcca29
Commit
c3bcca29
authored
Jul 04, 2019
by
Gerd
Browse files
module(display): initial support
parent
c2876eb8
Changes
13
Hide whitespace changes
Inline
Side-by-side
Documentation/conf.py
View file @
c3bcca29
...
...
@@ -87,6 +87,7 @@ html_context = {
# -- Options for Auto-Doc ---------------------------------------------------- {{{
autodoc_mock_imports
=
[
"sys_display"
,
"ucollections"
,
"urandom"
,
"utime"
,
...
...
Documentation/index.rst
View file @
c3bcca29
...
...
@@ -24,6 +24,7 @@ Last but not least, if you want to start hacking the lower-level firmware, the
pycardium/color
pycardium/leds
pycardium/vibra
pycardium/display
.. toctree::
:maxdepth: 1
...
...
Documentation/pycardium/display.rst
0 → 100644
View file @
c3bcca29
``display`` - Display
=====================
.. automodule:: display
:members:
epicardium/epicardium.h
View file @
c3bcca29
...
...
@@ -22,6 +22,14 @@
#define API_INTERRUPT_ENABLE 0x7
#define API_INTERRUPT_DISABLE 0x8
#define API_DISP_OPEN 0x10
#define API_DISP_CLOSE 0x11
#define API_DISP_PRINT 0x12
#define API_DISP_CLEAR 0x13
#define API_DISP_UPDATE 0x14
#define API_DISP_LINE 0x15
#define API_DISP_RECT 0x16
#define API_DISP_CIRC 0x17
/* clang-format on */
/**
...
...
@@ -164,5 +172,146 @@ API(API_INTERRUPT_ENABLE, int epic_interrupt_enable(api_int_id_t int_id));
* :param int_id: The interrupt to be disabled
*/
API
(
API_INTERRUPT_DISABLE
,
int
epic_interrupt_disable
(
api_int_id_t
int_id
));
/**
* Display
* =======
*/
/**
*
*/
enum
linestyle_t
{
LINESTYLE_FULL
=
0
,
LINESTYLE_DOTTED
=
1
};
/**
*
*/
enum
fillstyle_t
{
FILLSTYLE_EMPTY
=
0
,
FILLSTYLE_FILLED
=
1
};
/**
* Locks the display.
*
* :return: ``0`` on success or a negative value in case of an error:
* - ``-EBUSY``: Display was already locked from another task.
*/
API
(
API_DISP_OPEN
,
int
epic_disp_open
());
/**
* Unlocks the display again.
*
* :return: ``0`` on success or a negative value in case of an error:
* - ``-EBUSY``: Display was already locked from another task.
*/
API
(
API_DISP_CLOSE
,
int
epic_disp_close
());
/**
* Causes the changes that have been written to the framebuffer
* to be shown on the display
*/
API
(
API_DISP_UPDATE
,
int
epic_disp_update
());
/**
* Prints a string into the display framebuffer
*
* :param posx: x position to print to. 0 <= x <= 160
* :param posy: y position to print to. 0 <= y <= 80
* :param pString: string to print
* :param fg: foreground color in rgb565
* :param bg: background color in rgb565
* :return: ``0`` on success or a negative value in case of an error:
* - ``-EBUSY``: Display was already locked from another task.
*/
API
(
API_DISP_PRINT
,
int
epic_disp_print
(
uint16_t
posx
,
uint16_t
posy
,
const
char
*
pString
,
uint16_t
fg
,
uint16_t
bg
)
);
/**
* Fills the whole screen with one color
*
* :param color: fill color in rgb565
* :return: ``0`` on success or a negative value in case of an error:
* - ``-EBUSY``: Display was already locked from another task.
*/
API
(
API_DISP_CLEAR
,
int
epic_disp_clear
(
uint16_t
color
));
/**
* Draws a line on the display
*
* :param xstart: x starting position; 0 <= x <= 160
* :param ystart: y starting position; 0 <= y <= 80
* :param xend: x ending position; 0 <= x <= 160
* :param yend: y ending position; 0 <= y <= 80
* :param color: line color in rgb565
* :param linestyle: 0 for solid, 1 for dottet (almost no visual difference)
* :param pixelsize: thickness of the line; 1 <= pixelsize <= 8
* :return: ``0`` on success or a negative value in case of an error:
* - ``-EBUSY``: Display was already locked from another task.
*/
API
(
API_DISP_LINE
,
int
epic_disp_line
(
uint16_t
xstart
,
uint16_t
ystart
,
uint16_t
xend
,
uint16_t
yend
,
uint16_t
color
,
enum
linestyle_t
linestyle
,
uint16_t
pixelsize
)
);
/**
* Draws a rectangle on the display
*
* :param xstart: x coordinate of top left corner; 0 <= x <= 160
* :param ystart: y coordinate of top left corner; 0 <= y <= 80
* :param xend: x coordinate of bottom right corner; 0 <= x <= 160
* :param yend: y coordinate of bottom right corner; 0 <= y <= 80
* :param color: line color in rgb565
* :param fillstyle: 0 for empty, 1 for filled
* :param pixelsize: thickness of the rectangle outline; 1 <= pixelsize <= 8
* :return: ``0`` on success or a negative value in case of an error:
* - ``-EBUSY``: Display was already locked from another task.
*/
API
(
API_DISP_RECT
,
int
epic_disp_rect
(
uint16_t
xstart
,
uint16_t
ystart
,
uint16_t
xend
,
uint16_t
yend
,
uint16_t
color
,
enum
fillstyle_t
fillstyle
,
uint16_t
pixelsize
)
);
/**
* Draws a circle on the display
*
* :param x: x coordinate of the center; 0 <= x <= 160
* :param y: y coordinate of the center; 0 <= y <= 80
* :param rad: radius of the circle
* :param color: fill and outline color of the circle (rgb565)
* :param fillstyle: 0 for empty, 1 for filled
* :param pixelsize: thickness of the circle outline; 1 <= pixelsize <= 8
* :return: ``0`` on success or a negative value in case of an error:
* - ``-EBUSY``: Display was already locked from another task.
*/
API
(
API_DISP_CIRC
,
int
epic_disp_circ
(
uint16_t
x
,
uint16_t
y
,
uint16_t
rad
,
uint16_t
color
,
enum
fillstyle_t
fillstyle
,
uint16_t
pixelsize
)
);
#endif
/* _EPICARDIUM_H */
epicardium/modules/display.c
0 → 100644
View file @
c3bcca29
#include
"epicardium.h"
#include
"tmr_utils.h"
#include
"gpio.h"
#include
"GUI_DEV/GUI_Paint.h"
#include
"Fonts/fonts.h"
#include
"tmr.h"
#include
"FreeRTOS.h"
#include
"task.h"
static
TaskHandle_t
lock
=
NULL
;
static
int
check_lock
()
{
TaskHandle_t
task
=
xTaskGetCurrentTaskHandle
();
if
(
task
!=
lock
)
{
return
-
EBUSY
;
}
else
{
return
0
;
}
}
int
epic_disp_print
(
uint16_t
posx
,
uint16_t
posy
,
const
char
*
pString
,
uint16_t
fg
,
uint16_t
bg
)
{
int
cl
=
check_lock
();
if
(
cl
<
0
)
{
return
cl
;
}
else
{
Paint_DrawString_EN
(
posx
,
posy
,
pString
,
&
Font20
,
bg
,
fg
);
return
0
;
}
}
int
epic_disp_clear
(
uint16_t
color
)
{
int
cl
=
check_lock
();
if
(
cl
<
0
)
{
return
cl
;
}
else
{
LCD_Clear
(
color
);
return
0
;
}
}
int
epic_disp_line
(
uint16_t
xstart
,
uint16_t
ystart
,
uint16_t
xend
,
uint16_t
yend
,
uint16_t
color
,
enum
linestyle_t
linestyle
,
uint16_t
pixelsize
)
{
int
cl
=
check_lock
();
if
(
cl
<
0
)
{
return
cl
;
}
else
{
Paint_DrawLine
(
xstart
,
ystart
,
xend
,
yend
,
color
,
linestyle
,
pixelsize
);
return
0
;
}
}
int
epic_disp_rect
(
uint16_t
xstart
,
uint16_t
ystart
,
uint16_t
xend
,
uint16_t
yend
,
uint16_t
color
,
enum
fillstyle_t
fillstyle
,
uint16_t
pixelsize
)
{
int
cl
=
check_lock
();
if
(
cl
<
0
)
{
return
cl
;
}
else
{
Paint_DrawRectangle
(
xstart
,
ystart
,
xend
,
yend
,
color
,
fillstyle
,
pixelsize
);
return
0
;
}
}
int
epic_disp_circ
(
uint16_t
x
,
uint16_t
y
,
uint16_t
rad
,
uint16_t
color
,
enum
fillstyle_t
fillstyle
,
uint16_t
pixelsize
)
{
int
cl
=
check_lock
();
if
(
cl
<
0
)
{
return
cl
;
}
else
{
Paint_DrawCircle
(
x
,
y
,
rad
,
color
,
fillstyle
,
pixelsize
);
return
0
;
}
}
int
epic_disp_update
()
{
int
cl
=
check_lock
();
if
(
cl
<
0
)
{
return
cl
;
}
else
{
LCD_Update
();
return
0
;
}
}
int
epic_disp_open
()
{
TaskHandle_t
task
=
xTaskGetCurrentTaskHandle
();
if
(
lock
==
task
)
{
return
0
;
}
else
if
(
lock
==
NULL
)
{
lock
=
task
;
return
0
;
}
else
{
return
-
EBUSY
;
}
}
int
epic_disp_close
()
{
if
(
check_lock
()
<
0
&&
lock
!=
NULL
)
{
return
-
EBUSY
;
}
else
{
lock
=
NULL
;
return
0
;
}
}
void
disp_forcelock
()
{
TaskHandle_t
task
=
xTaskGetCurrentTaskHandle
();
lock
=
task
;
}
epicardium/modules/meson.build
View file @
c3bcca29
module_sources
=
files
(
'display.c'
,
'fatfs.c'
,
'leds.c'
,
'log.c'
,
...
...
epicardium/modules/modules.h
View file @
c3bcca29
...
...
@@ -14,4 +14,7 @@ void vSerialTask(void *pvParameters);
#define PMIC_PRESS_POWEROFF 40
void
vPmicTask
(
void
*
pvParameters
);
// Forces an unlock of the display. Only to be used in epicardium
void
disp_forcelock
();
#endif
/* MODULES_H */
pycardium/meson.build
View file @
c3bcca29
name
=
'pycardium'
modsrc
=
files
(
'modules/
utime
.c'
,
'modules/
interrupt
.c'
,
'modules/leds.c'
,
'modules/sys_display.c'
,
'modules/utime.c'
,
'modules/vibra.c'
,
'modules/interrupt.c'
,
)
#################################
...
...
pycardium/modules/py/display.py
0 → 100644
View file @
c3bcca29
import
sys_display
import
color
class
Display
:
"""
The display class provides methods to allow the lcd display
in card10 to be used in a safe way. All draw methods return
the display object so that it is possible to chain calls.
It is recommended to use a context manager as following:
.. code-block:: python
import display
with display.open() as disp:
disp.clear().update()
"""
def
__enter__
(
self
):
return
self
def
__exit__
(
self
,
_et
,
_ev
,
_t
):
self
.
close
()
@
classmethod
def
open
(
cls
):
"""
Opens the display. Will fail the display can't be locked
"""
sys_display
.
open
()
return
cls
()
def
close
(
self
):
"""
Closes and unlocks the display. To be able to use it again,
it is necessary to open and lock it again with Display.open()
"""
sys_display
.
close
()
def
update
(
self
):
"""
Updates the display based on the changes previously made by
various draw functions
"""
sys_display
.
update
()
def
clear
(
self
,
col
=
None
):
"""
Clears the display using the color provided, or the default
color black
:param col: Clearing color (expects RGB triple)
"""
col
=
col
or
color
.
BLACK
sys_display
.
clear
(
col
)
return
self
def
print
(
self
,
text
,
*
,
fg
=
None
,
bg
=
None
,
posx
=
0
,
posy
=
0
):
"""
Prints a string on the display. Font size is locked to 20px
:param text: Text to print
:param fg: Foreground color (expects RGB triple)
:param bg: Background color (expects RGB triple)
:param posx: X-Position of the first character, 0 <= posx <= 160
:param posy: Y-Position of the first character, 0 <= posy <= 80
"""
fg
=
fg
or
color
.
WHITE
bg
=
bg
or
color
.
BLACK
sys_display
.
print
(
text
,
posx
,
posy
,
fg
,
bg
)
return
self
def
line
(
self
,
xs
,
ys
,
xe
,
ye
,
*
,
col
=
None
,
dotted
=
False
,
size
=
1
):
"""
Draws a line on the display.
:param xs: X start coordinate, 0 <= xs <= 160
:param ys: Y start coordinate, 0 <= ys <= 80
:param xe: X end coordinate, 0 <= xe <= 160
:param ye: Y end coordinate, 0 <= ye <= 80
:param col: color of the line (expects RGB triple)
:param dotted: whether the line should be dotted or not
(questionable implementation: draws every other pixel white, draws
white squares at higher pixel sizes)
:param size: size of the individual pixels, ranges from 1 to 8
"""
col
=
col
or
color
.
WHITE
sys_display
.
line
(
xs
,
ys
,
xe
,
ye
,
col
,
dotted
,
size
)
return
self
def
rect
(
self
,
xs
,
ys
,
xe
,
ye
,
*
,
col
=
None
,
filled
=
True
,
size
=
1
):
"""
Draws a rectangle on the display.
:param xs: X start coordinate, 0 <= xs <= 160
:param ys: Y start coordinate, 0 <= ys <= 80
:param xe: X end coordinate, 0 <= xe <= 160
:param ye: Y end coordinate, 0 <= ye <= 80
:param col: color of the outline and fill (expects RGB triple)
:param filled: whether the rectangle should be filled or not
:param size: size of the individual pixels, ranges from 1 to 8
"""
col
=
col
or
color
.
WHITE
sys_display
.
rect
(
xs
,
ys
,
xe
,
ye
,
col
,
filled
,
size
)
return
self
def
circ
(
self
,
x
,
y
,
rad
,
*
,
col
=
None
,
filled
=
True
,
size
=
1
):
"""
Draws a circle on the display.
:param x: center x coordinate, 0 <= x <= 160
:param y: center y coordinate, 0 <= y <= 80
:param rad: radius
:param col: color of the outline and fill (expects RGB triple)
:param filled: whether the rectangle should be filled or not
:param size: size of the individual pixels, ranges from 1 to 8
"""
col
=
col
or
color
.
WHITE
sys_display
.
circ
(
x
,
y
,
rad
,
col
,
filled
,
size
)
return
self
open
=
Display
.
open
pycardium/modules/py/meson.build
View file @
c3bcca29
python_modules
=
files
(
'color.py'
,
'htmlcolor.py'
,
'display.py'
,
)
frozen_modules
=
mpy_cross
.
process
(
python_modules
)
pycardium/modules/qstrdefs.h
View file @
c3bcca29
...
...
@@ -30,3 +30,12 @@ Q(set_callback)
Q
(
enable_callback
)
Q
(
disable_callback
)
Q
(
BHI160
)
/* display */
Q
(
sys_display
)
Q
(
display
)
Q
(
print
)
Q
(
line
)
Q
(
rect
)
Q
(
circ
)
Q
(
clear
)
pycardium/modules/sys_display.c
0 → 100644
View file @
c3bcca29
#include
"py/obj.h"
#include
"py/objstr.h"
#include
"py/objint.h"
#include
"py/runtime.h"
#include
"epicardium.h"
#include
<stdio.h>
static
uint16_t
rgb888_to_rgb565
(
uint8_t
*
bytes
)
{
return
((
bytes
[
0
]
&
0
b11111000
)
<<
8
)
|
((
bytes
[
1
]
&
0
b11111100
)
<<
3
)
|
(
bytes
[
2
]
>>
3
);
}
static
uint16_t
get_color
(
mp_obj_t
color_in
)
{
if
(
mp_obj_get_int
(
mp_obj_len
(
color_in
))
<
3
)
{
mp_raise_ValueError
(
"color must have 3 elements"
);
}
uint8_t
red
=
mp_obj_get_int
(
mp_obj_subscr
(
color_in
,
mp_obj_new_int
(
0
),
MP_OBJ_SENTINEL
)
);
uint8_t
green
=
mp_obj_get_int
(
mp_obj_subscr
(
color_in
,
mp_obj_new_int
(
1
),
MP_OBJ_SENTINEL
)
);
uint8_t
blue
=
mp_obj_get_int
(
mp_obj_subscr
(
color_in
,
mp_obj_new_int
(
2
),
MP_OBJ_SENTINEL
)
);
uint8_t
colors
[
3
]
=
{
red
,
green
,
blue
};
return
rgb888_to_rgb565
(
colors
);
}
/* print something on the display */
static
mp_obj_t
mp_display_print
(
size_t
n_args
,
const
mp_obj_t
*
args
)
{
if
(
!
mp_obj_is_str_or_bytes
(
args
[
0
]))
{
mp_raise_TypeError
(
"input text must be a string"
);
}
GET_STR_DATA_LEN
(
args
[
0
],
print
,
print_len
);
uint32_t
posx
=
mp_obj_get_int
(
args
[
1
]);
uint32_t
posy
=
mp_obj_get_int
(
args
[
2
]);
uint32_t
fg
=
get_color
(
args
[
3
]);
uint32_t
bg
=
get_color
(
args
[
4
]);
int
res
=
epic_disp_print
(
posx
,
posy
,
(
const
char
*
)
print
,
fg
,
bg
);
if
(
res
<
0
)
{
mp_raise_OSError
(
-
res
);
}
return
mp_const_none
;
}
/* draw line on the display */
static
mp_obj_t
mp_display_line
(
size_t
n_args
,
const
mp_obj_t
*
args
)
{
uint16_t
xs
=
mp_obj_get_int
(
args
[
0
]);
uint16_t
ys
=
mp_obj_get_int
(
args
[
1
]);
uint16_t
xe
=
mp_obj_get_int
(
args
[
2
]);
uint16_t
ye
=
mp_obj_get_int
(
args
[
3
]);
uint16_t
col
=
get_color
(
args
[
4
]);
uint16_t
ls
=
mp_obj_get_int
(
args
[
5
]);
uint16_t
ps
=
mp_obj_get_int
(
args
[
6
]);
//TODO: Move sanity checks to epicardium
if
(
xs
>
160
||
xs
<
0
||
xe
>
160
||
xe
<
0
)
{
mp_raise_ValueError
(
"X-Coords have to be 0 < x < 160"
);
}
if
(
ys
>
80
||
ys
<
0
||
ye
>
80
||
ye
<
0
)
{
mp_raise_ValueError
(
"Y-Coords have to be 0 < x < 80"
);
}
if
(
ls
>
1
||
ls
<
0
)
{
mp_raise_ValueError
(
"Line style has to be 0 or 1"
);
}
int
res
=
epic_disp_line
(
xs
,
ys
,
xe
,
ye
,
col
,
ls
,
ps
);
if
(
res
<
0
)
{
mp_raise_OSError
(
-
res
);
}
return
mp_const_none
;
}
/* draw rectangle on the display */
static
mp_obj_t
mp_display_rect
(
size_t
n_args
,
const
mp_obj_t
*
args
)
{
uint16_t
xs
=
mp_obj_get_int
(
args
[
0
]);
uint16_t
ys
=
mp_obj_get_int
(
args
[
1
]);
uint16_t
xe
=
mp_obj_get_int
(
args
[
2
]);
uint16_t
ye
=
mp_obj_get_int
(
args
[
3
]);
uint16_t
col
=
get_color
(
args
[
4
]);
uint16_t
fs
=
mp_obj_get_int
(
args
[
5
]);
uint16_t
ps
=
mp_obj_get_int
(
args
[
6
]);
//TODO: Move sanity checks to epicardium
if
(
xs
>
160
||
xs
<
0
||
xe
>
160
||
xe
<
0
)
{
mp_raise_ValueError
(
"X-Coords have to be 0 < x < 160"
);
}
if
(
ys
>
80
||
ys
<
0
||
ye
>
80
||
ye
<
0
)
{
mp_raise_ValueError
(
"Y-Coords have to be 0 < x < 80"
);
}
if
(
fs
>
1
||
fs
<
0
)
{
mp_raise_ValueError
(
"Fill style has to be 0 or 1"
);
}
int
res
=
epic_disp_rect
(
xs
,
ys
,
xe
,
ye
,
col
,
fs
,
ps
);
if
(
res
<
0
)
{
mp_raise_OSError
(
-
res
);
}
return
mp_const_none
;