drivers: display: mb_display: Unify image and string APIs

Both the string and image rendering may want to take advantage of
scrolling and sequential display capabilities. Consolidate the APIs so
that there's a single one for images (mb_display_image) and a single
one for strings (mb_display_print). Both take a duration parameter for
the per-frame duration as well as a mode parameter which specifies
sequential vs scrolling behavior as well as an optional looping flag.

Change-Id: Ia092d771e3f1b94afd494c7544dab988161c539e
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2017-04-05 18:36:36 +03:00 committed by Anas Nashif
commit d7a189d2ec
5 changed files with 291 additions and 124 deletions

View file

@ -29,21 +29,11 @@ config MICROBIT_DISPLAY_PIN_GRANULARITY
config MICROBIT_DISPLAY_STR_MAX
int "Maximum length of strings that can be shown on the display"
range 3 1024
range 3 255
default 40
help
This value specifies the maximum length of strings that can
be displayed using the mb_display_string() and mb_display_print()
APIs.
config MICROBIT_DISPLAY_SCROLL_STEP
int "Duration between two string scrolling steps (in milliseconds)"
range 20 2000
default 80
help
This value specifies the time between two scrolling steps of the
string scrolling functionality. Smaller values mean faster
scrolling whereas bigger values mean slower scrolling. It is
usually best to leave this at its default value (80ms).
endif # MICROBIT_DISPLAY

View file

@ -23,21 +23,30 @@
#include "mb_font.h"
#define MODE_MASK BIT_MASK(16)
#define DISPLAY_ROWS 3
#define DISPLAY_COLS 9
#define SCROLL_OFF 0
#define SCROLL_START 1
/* Time between scroll shifts */
#define SCROLL_DURATION K_MSEC(CONFIG_MICROBIT_DISPLAY_SCROLL_STEP)
#define SCROLL_DEFAULT_DURATION K_MSEC(80)
struct mb_display {
struct device *dev; /* GPIO device */
struct device *dev; /* GPIO device */
struct k_timer timer; /* Rendering timer */
struct k_timer timer; /* Rendering timer */
uint8_t scroll; /* Scroll shift */
uint8_t img_count; /* Image count */
uint8_t cur_img; /* Current image or character to show */
uint8_t scroll:3, /* Scroll shift */
first:1, /* First frame of a scroll sequence */
loop:1, /* Loop to beginning */
text:1, /* We're showing a string (not image) */
img_sep:1; /* One column image separation */
/* The following variables track the currently shown image */
uint8_t cur; /* Currently rendered row */
@ -45,7 +54,10 @@ struct mb_display {
int64_t expiry; /* When to stop showing current image */
int32_t duration; /* Duration for each shown image */
const char *str; /* String to be shown */
union {
const struct mb_image *img; /* Array of images to show */
const char *str; /* String to be shown */
};
/* Buffer for printed strings */
char str_buf[CONFIG_MICROBIT_DISPLAY_STR_MAX];
@ -131,39 +143,118 @@ static inline void update_pins(struct mb_display *disp, uint32_t val)
}
}
static void reset_display(struct mb_display *disp)
{
k_timer_stop(&disp->timer);
disp->str = NULL;
disp->cur_img = 0;
disp->img = NULL;
disp->img_count = 0;
disp->scroll = SCROLL_OFF;
}
static const struct mb_image *current_img(struct mb_display *disp)
{
if (disp->scroll && disp->first) {
return get_font(' ');
}
if (disp->text) {
return get_font(disp->str[disp->cur_img]);
} else {
return &disp->img[disp->cur_img];
}
}
static const struct mb_image *next_img(struct mb_display *disp)
{
if (disp->text) {
if (disp->first) {
return get_font(disp->str[0]);
} else if (disp->str[disp->cur_img]) {
return get_font(disp->str[disp->cur_img + 1]);
} else {
return get_font(' ');
}
} else {
if (disp->first) {
return &disp->img[0];
} else if (disp->cur_img < (disp->img_count - 1)) {
return &disp->img[disp->cur_img + 1];
} else {
return get_font(' ');
}
}
}
static inline bool last_frame(struct mb_display *disp)
{
if (disp->text) {
return (disp->str[disp->cur_img] == '\0');
} else {
return (disp->cur_img >= disp->img_count);
}
}
static inline uint8_t scroll_steps(struct mb_display *disp)
{
return 5 + disp->img_sep;
}
static void update_scroll(struct mb_display *disp)
{
if (disp->scroll < 6) {
if (disp->scroll < scroll_steps(disp)) {
struct mb_image img;
int i;
for (i = 0; i < 5; i++) {
const struct mb_image *i1 = get_font(disp->str[0]);
const struct mb_image *i2;
if (disp->str[0]) {
i2 = get_font(disp->str[1]);
} else {
i2 = get_font(' ');
}
const struct mb_image *i1 = current_img(disp);
const struct mb_image *i2 = next_img(disp);
img.row[i] = ((i1->row[i] >> disp->scroll) |
(i2->row[i] << (6 - disp->scroll)));
(i2->row[i] << (scroll_steps(disp) -
disp->scroll)));
}
disp->scroll++;
start_image(disp, &img);
} else {
if (!disp->str[1]) {
disp->scroll = SCROLL_OFF;
disp->str = NULL;
if (disp->first) {
disp->first = 0;
} else {
disp->cur_img++;
}
if (last_frame(disp)) {
if (!disp->loop) {
reset_display(disp);
return;
}
disp->cur_img = 0;
disp->first = 1;
}
disp->scroll = SCROLL_START;
start_image(disp, current_img(disp));
}
}
static void update_image(struct mb_display *disp)
{
disp->cur_img++;
if (last_frame(disp)) {
if (!disp->loop) {
reset_display(disp);
return;
}
disp->str++;
disp->scroll = SCROLL_START;
start_image(disp, get_font(disp->str[0]));
disp->cur_img = 0;
}
start_image(disp, current_img(disp));
}
static void show_row(struct k_timer *timer)
@ -177,11 +268,8 @@ static void show_row(struct k_timer *timer)
k_uptime_get() > disp->expiry) {
if (disp->scroll) {
update_scroll(disp);
} else if (disp->str && disp->str[0]) {
start_image(disp, get_font(disp->str[0]));
disp->str++;
} else {
k_timer_stop(&disp->timer);
update_image(disp);
}
}
}
@ -197,21 +285,57 @@ static struct mb_display display = {
.timer = K_TIMER_INITIALIZER(display.timer, show_row, clear_display),
};
static void reset_display(struct mb_display *disp)
static void start_scroll(struct mb_display *disp, int32_t duration)
{
k_timer_stop(&disp->timer);
/* Divide total duration by number of scrolling steps */
if (duration) {
disp->duration = duration / scroll_steps(disp);
} else {
disp->duration = SCROLL_DEFAULT_DURATION;
}
disp->str = NULL;
disp->scroll = SCROLL_OFF;
disp->scroll = SCROLL_START;
disp->first = 1;
disp->cur_img = 0;
start_image(disp, get_font(' '));
}
void mb_display_image(struct mb_display *disp, const struct mb_image *img,
int32_t duration)
static void start_single(struct mb_display *disp, int32_t duration)
{
disp->duration = duration;
if (disp->text) {
start_image(disp, get_font(disp->str[0]));
} else {
start_image(disp, disp->img);
}
}
void mb_display_image(struct mb_display *disp, uint32_t mode, int32_t duration,
const struct mb_image *img, uint8_t img_count)
{
reset_display(disp);
disp->duration = duration;
start_image(disp, img);
__ASSERT(img && img_count > 0, "Invalid parameters");
disp->text = 0;
disp->img_count = img_count;
disp->img = img;
disp->img_sep = 0;
disp->cur_img = 0;
disp->loop = !!(mode & MB_DISPLAY_FLAG_LOOP);
switch (mode & MODE_MASK) {
case MB_DISPLAY_MODE_DEFAULT:
case MB_DISPLAY_MODE_SINGLE:
start_single(disp, duration);
break;
case MB_DISPLAY_MODE_SCROLL:
start_scroll(disp, duration);
break;
default:
__ASSERT(0, "Invalid display mode");
}
}
void mb_display_stop(struct mb_display *disp)
@ -219,16 +343,13 @@ void mb_display_stop(struct mb_display *disp)
reset_display(disp);
}
void mb_display_char(struct mb_display *disp, char chr, int32_t duration)
{
mb_display_image(disp, get_font(chr), duration);
}
void mb_display_string(struct mb_display *disp, int32_t duration,
const char *fmt, ...)
void mb_display_print(struct mb_display *disp, uint32_t mode,
int32_t duration, const char *fmt, ...)
{
va_list ap;
reset_display(disp);
va_start(ap, fmt);
vsnprintk(disp->str_buf, sizeof(disp->str_buf), fmt, ap);
va_end(ap);
@ -237,39 +358,23 @@ void mb_display_string(struct mb_display *disp, int32_t duration,
return;
}
reset_display(disp);
disp->str = disp->str_buf;
disp->text = 1;
disp->img_sep = 1;
disp->cur_img = 0;
disp->loop = !!(mode & MB_DISPLAY_FLAG_LOOP);
disp->str = &disp->str_buf[1];
disp->duration = duration;
disp->scroll = SCROLL_OFF;
start_image(disp, get_font(disp->str_buf[0]));
}
void mb_display_print(struct mb_display *disp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintk(disp->str_buf, sizeof(disp->str_buf), fmt, ap);
va_end(ap);
if (disp->str_buf[0] == '\0') {
return;
switch (mode & MODE_MASK) {
case MB_DISPLAY_MODE_DEFAULT:
case MB_DISPLAY_MODE_SCROLL:
start_scroll(disp, duration);
break;
case MB_DISPLAY_MODE_SINGLE:
start_single(disp, duration);
break;
default:
__ASSERT(0, "Invalid display mode");
}
reset_display(disp);
if (disp->str_buf[1] == '\0') {
disp->str = NULL;
} else {
disp->str = disp->str_buf;
}
disp->scroll = SCROLL_START;
disp->duration = SCROLL_DURATION;
start_image(disp, get_font(disp->str[0]));
}
struct mb_display *mb_display_get(void)