forked from Imagelibrary/rtems
933 lines
32 KiB
C
933 lines
32 KiB
C
/*===============================================================*\
|
|
| Project: display driver for HCMS29xx |
|
|
+-----------------------------------------------------------------+
|
|
| File: disp_hcms29xx.c |
|
|
+-----------------------------------------------------------------+
|
|
| Copyright (c) 2008 |
|
|
| Embedded Brains GmbH |
|
|
| Obere Lagerstr. 30 |
|
|
| D-82178 Puchheim |
|
|
| Germany |
|
|
| rtems@embedded-brains.de |
|
|
+-----------------------------------------------------------------+
|
|
| The license and distribution terms for this file may be |
|
|
| found in the file LICENSE in this distribution or at |
|
|
| http://www.rtems.org/license/LICENSE. |
|
|
+-----------------------------------------------------------------+
|
|
| this file contains the SPI based driver for a HCMS29xx 4 digit |
|
|
| alphanumeric LED display |
|
|
\*===============================================================*/
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <rtems.h>
|
|
#include <rtems/libio.h>
|
|
#include <bsp.h>
|
|
#include <rtems/libi2c.h>
|
|
#include <libchip/disp_hcms29xx.h>
|
|
#include "font_hcms29xx.h"
|
|
#define FONT_BASE font_hcms29xx_base
|
|
|
|
|
|
#define DISP_HCMS29XX_DIGIT_CNT (4)
|
|
#define DISP_HCMS29XX_SEMA_NAME rtems_build_name('D','4','I','Q')
|
|
#define DISP_HCMS29XX_TRNS_SEMA_NAME rtems_build_name('D','4','T','R')
|
|
#define DISP_HCMS29XX_TIMER_NAME rtems_build_name('D','4','T','M')
|
|
#define DISP_HCMS29XX_TASK_NAME rtems_build_name('D','4','T','A')
|
|
|
|
#define DISP_HCMS29XX_EVENT_TIMER RTEMS_EVENT_1
|
|
#define DISP_HCMS29XX_EVENT_NEWSTR RTEMS_EVENT_2
|
|
|
|
|
|
static disp_font_t disp_hcms29xx_font_normal;
|
|
static disp_font_t disp_hcms29xx_font_rotate;
|
|
const rtems_libi2c_tfr_mode_t spi_disphcms29xx_tfr_mode = {
|
|
.baudrate = 1000000,
|
|
.bits_per_char = 8,
|
|
.lsb_first = true,
|
|
.clock_inv = true,
|
|
.clock_phs = true,
|
|
.idle_char = 0
|
|
};
|
|
|
|
static disp_hcms29xx_drv_t disp_hcms29xx_drv_tbl;
|
|
|
|
/*=========================================
|
|
* font management functions
|
|
*/
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
static rtems_status_code disp_hcms29xx_font_struct_size
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| compute size of font data structure tree |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
disp_font_t src, /* source font */
|
|
size_t *dst_size /* destination: size of font struct*/
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
{
|
|
|
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
size_t font_size = 0;
|
|
size_t glyph_idx;
|
|
/*
|
|
* check parameters
|
|
*/
|
|
if ((rc == RTEMS_SUCCESSFUL) &&
|
|
(src == NULL)) {
|
|
rc = RTEMS_INVALID_ADDRESS;
|
|
}
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
font_size =
|
|
sizeof(*src); /* font_base structure */
|
|
}
|
|
glyph_idx = 0;
|
|
while ((rc == RTEMS_SUCCESSFUL) &&
|
|
(glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0])))) {
|
|
if (src->latin1[glyph_idx] != NULL) {
|
|
font_size += sizeof(*(src->latin1[glyph_idx]))
|
|
+ (size_t) src->latin1[glyph_idx]->bb.w;
|
|
}
|
|
glyph_idx++;
|
|
}
|
|
*dst_size = font_size;
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
static inline unsigned char disp_hcms29xx_bitswap
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| swap data bits in byte (7<->0 , 6<->1 etc) |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
unsigned char byte
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
{
|
|
unsigned char result = 0;
|
|
int smsk,dmsk;
|
|
for (smsk = 0x01,dmsk=0x80;
|
|
smsk < 0x100;
|
|
smsk<<=1 ,dmsk>>=1) {
|
|
if ((byte & smsk) != 0) {
|
|
result |= (unsigned char) dmsk;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
static rtems_status_code disp_hcms29xx_copy_font
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| copy font data from source to dest font structure |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
disp_font_t src, /* source font */
|
|
struct disp_font_base *dst, /* ptr to destination font */
|
|
int shift_cnt, /* shift count for font */
|
|
bool do_rotate /* rotate font, if true */
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
{
|
|
|
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
char *alloc_next = (char *)dst;
|
|
size_t glyph_idx = 0;
|
|
int glyph_size;
|
|
unsigned char byte;
|
|
int bcnt;
|
|
|
|
/*
|
|
* check parameters
|
|
*/
|
|
if ((rc == RTEMS_SUCCESSFUL) &&
|
|
((src == NULL) ||
|
|
(dst == NULL))) {
|
|
rc = RTEMS_INVALID_ADDRESS;
|
|
}
|
|
/*
|
|
* copy font_base structure
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
*dst = *src;
|
|
alloc_next += sizeof(*dst);
|
|
}
|
|
/*
|
|
* for all glyphs: assign own glyph memory
|
|
*/
|
|
glyph_idx = 0;
|
|
while ((rc == RTEMS_SUCCESSFUL) &&
|
|
glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0]))) {
|
|
if (src->latin1[glyph_idx] != NULL) {
|
|
/*
|
|
* allocate space for glyph
|
|
*/
|
|
dst->latin1[glyph_idx] = (struct disp_font_glyph *)alloc_next;
|
|
alloc_next += sizeof(*(dst->latin1[glyph_idx]));
|
|
/*
|
|
* copy source values.
|
|
* Note: bitmap will be reassigned later
|
|
*/
|
|
*(struct disp_font_glyph *)(dst->latin1[glyph_idx]) =
|
|
*(src->latin1[glyph_idx]);
|
|
}
|
|
else {
|
|
dst->latin1[glyph_idx] = NULL;
|
|
}
|
|
glyph_idx++;
|
|
}
|
|
|
|
/*
|
|
* for all glyphs: reassign bitmap
|
|
*/
|
|
glyph_idx = 0;
|
|
while ((rc == RTEMS_SUCCESSFUL) &&
|
|
glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0]))) {
|
|
if (src->latin1[glyph_idx] != NULL) {
|
|
glyph_size = src->latin1[glyph_idx]->bb.w;
|
|
/*
|
|
* allocate space for glyph_bitmap
|
|
*/
|
|
dst->latin1[glyph_idx]->bitmap = (const unsigned char *) alloc_next;
|
|
alloc_next += glyph_size;
|
|
/*
|
|
* copy/transform bitmap
|
|
*/
|
|
for (bcnt = 0;bcnt < glyph_size;bcnt++) {
|
|
if (do_rotate) {
|
|
byte = src->latin1[glyph_idx]->bitmap[glyph_size - 1 - bcnt];
|
|
byte = disp_hcms29xx_bitswap(byte);
|
|
}
|
|
else {
|
|
byte = src->latin1[glyph_idx]->bitmap[bcnt];
|
|
}
|
|
if (shift_cnt < 0) {
|
|
byte = byte >> shift_cnt;
|
|
}
|
|
else if (shift_cnt > 0) {
|
|
byte = byte >> shift_cnt;
|
|
}
|
|
((unsigned char *)(dst->latin1[glyph_idx]->bitmap))[bcnt] = byte;
|
|
}
|
|
}
|
|
glyph_idx++;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
static rtems_status_code disp_hcms29xx_alloc_copy_font
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| copy font data from source to dest font structure, alloc all data |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
const disp_font_t src, /* source font */
|
|
disp_font_t *dst, /* ptr to destination font */
|
|
int shift_cnt, /* shift count for font */
|
|
bool do_rotate /* rotate font, if true */
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
{
|
|
|
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
size_t src_size = 0;
|
|
/*
|
|
* check parameters
|
|
*/
|
|
if ((rc == RTEMS_SUCCESSFUL) &&
|
|
((src == NULL)
|
|
|| (dst == NULL))) {
|
|
rc = RTEMS_INVALID_ADDRESS;
|
|
}
|
|
/*
|
|
* determine size of source data
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = disp_hcms29xx_font_struct_size(src,&src_size);
|
|
}
|
|
/*
|
|
* allocate proper data area
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
*dst = malloc(src_size);
|
|
if (*dst == NULL) {
|
|
rc = RTEMS_UNSATISFIED;
|
|
}
|
|
}
|
|
/*
|
|
* scan through source data, copy to dest
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = disp_hcms29xx_copy_font(src,*dst,shift_cnt,do_rotate);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*=========================================
|
|
* SPI communication functions
|
|
*/
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
static rtems_status_code disp_hcms29xx_send_to_display
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| request access semaphore to SPI, prepare buffer descriptors, start |
|
|
| transfer via SPI to display |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
disp_hcms29xx_drv_t *softc_ptr,
|
|
const volatile char *disp_buffer /* start of chars to display (4 chars or 'til \0)*/
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
{
|
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
bool char_avail;
|
|
const struct disp_font_glyph *glyph_ptr;
|
|
disp_font_t curr_font;
|
|
int i, ret_cnt;
|
|
unsigned char c;
|
|
|
|
/*
|
|
* select device, set transfer mode, address device
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_libi2c_send_start(softc_ptr->disp_param.minor);
|
|
}
|
|
/*
|
|
* set transfer mode
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = -rtems_libi2c_ioctl(softc_ptr->disp_param.minor,
|
|
RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
|
|
&spi_disphcms29xx_tfr_mode);
|
|
}
|
|
|
|
/*
|
|
* address device
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_libi2c_send_addr(softc_ptr->disp_param.minor,true);
|
|
}
|
|
|
|
/*
|
|
* send data
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
curr_font =
|
|
softc_ptr->disp_param.rotate
|
|
? disp_hcms29xx_font_rotate
|
|
: disp_hcms29xx_font_normal;
|
|
|
|
char_avail = true;
|
|
/*
|
|
* FIXME: for rotated display, write last character first...
|
|
* maybe we should copy everything to a common buffer and use
|
|
* ONE SPI transfer?
|
|
*/
|
|
for (i = 0;
|
|
((rc == RTEMS_SUCCESSFUL) &&
|
|
(i < DISP_HCMS29XX_DIGIT_CNT));
|
|
i++) {
|
|
/* test for end of string... */
|
|
c = disp_buffer[i]; /* perform consistent read of disp_buffer */
|
|
if (char_avail && (c == '\0')) {
|
|
char_avail = false;
|
|
}
|
|
glyph_ptr = (char_avail
|
|
? curr_font->latin1[c]
|
|
: NULL);
|
|
if (glyph_ptr == NULL) {
|
|
glyph_ptr = curr_font->latin1[' '];
|
|
}
|
|
|
|
/*
|
|
* send 5 bytes from (char *)glyph_ptr->bitmap to SPI
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
ret_cnt = rtems_libi2c_write_bytes(softc_ptr->disp_param.minor,
|
|
glyph_ptr->bitmap,5);
|
|
if (ret_cnt < 0) {
|
|
rc = -ret_cnt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* finish transfer
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_libi2c_send_stop(softc_ptr->disp_param.minor);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
static rtems_status_code disp_hcms29xx_send_to_control
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| request access semaphore to SPI, prepare buffer descriptors, start |
|
|
| transfer via SPI to display |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
disp_hcms29xx_drv_t *softc_ptr,
|
|
int pwm, /* value for pwm of LEDs, 0..15 */
|
|
int peak, /* value for peak current for LEDs, 0..3 */
|
|
int sleep, /* value to make display "sleep" (0..1 */
|
|
int div, /* divider for external osc input, unused here */
|
|
int chain /* mode to drive other displays, unused here */
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
{
|
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
int run, ret_cnt;
|
|
uint8_t ctrl_buffer;
|
|
|
|
/* two accesses, control word 0 and 1 */
|
|
for (run = 0;
|
|
((rc == RTEMS_SUCCESSFUL) && (run <= 1));
|
|
run++) {
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
if (run == 0) {
|
|
ctrl_buffer =
|
|
(0 << 7) |
|
|
((sleep & 0x01) << 6) |
|
|
((peak & 0x03) << 4) |
|
|
((pwm & 0x0f) << 0);
|
|
}
|
|
else {
|
|
ctrl_buffer =
|
|
(1 << 7) |
|
|
((div & 0x01) << 1) |
|
|
((chain & 0x01) << 0);
|
|
}
|
|
/*
|
|
* select device, set transfer mode, address device
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_libi2c_send_start(softc_ptr->disp_param.minor);
|
|
}
|
|
/*
|
|
* set transfer mode
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = -rtems_libi2c_ioctl(softc_ptr->disp_param.minor,
|
|
RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
|
|
&spi_disphcms29xx_tfr_mode);
|
|
}
|
|
|
|
/*
|
|
* address device
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_libi2c_send_addr(softc_ptr->disp_param.minor,true);
|
|
}
|
|
|
|
/*
|
|
* send 1 byte from ctrl_buffer
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
ret_cnt = rtems_libi2c_write_bytes(softc_ptr->disp_param.minor,
|
|
&ctrl_buffer,1);
|
|
if (ret_cnt < 0) {
|
|
rc = -ret_cnt;
|
|
}
|
|
}
|
|
}
|
|
} /* next run ... */
|
|
|
|
/*
|
|
* finish transfer
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_libi2c_send_stop(softc_ptr->disp_param.minor);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
static rtems_timer_service_routine disp_hcms29xx_timer_sr
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| this task updates the string in the display |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
(
|
|
rtems_id id, /* ID of timer, not used */
|
|
void * arg /* calling arg: softc_ptr */
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| <none used> |
|
|
\*=========================================================================*/
|
|
{
|
|
disp_hcms29xx_drv_t *softc_ptr = arg;
|
|
|
|
rtems_event_send(softc_ptr->disp_param.task_id, DISP_HCMS29XX_EVENT_TIMER);
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
static rtems_task disp_hcms29xx_update_task
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| this task updates the string in the display |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
rtems_task_argument argument
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| <never exits> |
|
|
\*=========================================================================*/
|
|
{
|
|
rtems_event_set my_events;
|
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
int disp_offset = 0;
|
|
rtems_id disp_hcms29xx_timer_id;
|
|
disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
|
|
|
|
/*
|
|
* initialize display:
|
|
*/
|
|
/*
|
|
* set control attributes for display
|
|
* maximum brightness...
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = disp_hcms29xx_send_to_control(softc_ptr,
|
|
14,3,1,0,0);/* pwm/peak/nosleep/div/chain */
|
|
}
|
|
|
|
/*
|
|
* set display to blank
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = disp_hcms29xx_send_to_display(softc_ptr,
|
|
"");
|
|
}
|
|
|
|
/*
|
|
* create timer for scrolling
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_timer_create(DISP_HCMS29XX_TIMER_NAME,
|
|
&disp_hcms29xx_timer_id);
|
|
}
|
|
|
|
while (rc == RTEMS_SUCCESSFUL) {
|
|
/*
|
|
* wait for any event
|
|
*/
|
|
rc = rtems_event_receive(DISP_HCMS29XX_EVENT_NEWSTR |
|
|
DISP_HCMS29XX_EVENT_TIMER ,
|
|
RTEMS_WAIT | RTEMS_EVENT_ANY,
|
|
RTEMS_NO_TIMEOUT,
|
|
&my_events);
|
|
if (my_events & DISP_HCMS29XX_EVENT_NEWSTR) {
|
|
/*
|
|
* fetch new string consistently into local buffer
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_semaphore_obtain(softc_ptr->disp_param.trns_sema_id,
|
|
RTEMS_WAIT,RTEMS_NO_TIMEOUT);
|
|
}
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
strncpy(softc_ptr->disp_param.disp_buffer,
|
|
softc_ptr->disp_param.trns_buffer,
|
|
sizeof(softc_ptr->disp_param.disp_buffer));
|
|
softc_ptr->disp_param.disp_buffer[sizeof(softc_ptr->disp_param.disp_buffer)-1] = '\0';
|
|
softc_ptr->disp_param.disp_buf_cnt =
|
|
(int) strlen(softc_ptr->disp_param.disp_buffer);
|
|
}
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_semaphore_release(softc_ptr->disp_param.trns_sema_id);
|
|
}
|
|
/*
|
|
* set initial offset to negative value
|
|
* to make string static for some ticks
|
|
*/
|
|
disp_offset = -4;
|
|
}
|
|
if (my_events & DISP_HCMS29XX_EVENT_TIMER) {
|
|
/*
|
|
* increase disp_offset, if possible, otherwise reset it
|
|
*/
|
|
if ((disp_offset < 0) ||
|
|
(disp_offset < softc_ptr->disp_param.disp_buf_cnt-
|
|
DISP_HCMS29XX_DIGIT_CNT/2)) {
|
|
disp_offset++;
|
|
}
|
|
else {
|
|
disp_offset = -4;
|
|
}
|
|
}
|
|
/*
|
|
* display string, starting from disp_offset
|
|
*/
|
|
if (disp_offset < 0) {
|
|
rc = disp_hcms29xx_send_to_display(softc_ptr,
|
|
softc_ptr->disp_param.disp_buffer);
|
|
}
|
|
else if (disp_offset
|
|
< (softc_ptr->disp_param.disp_buf_cnt - DISP_HCMS29XX_DIGIT_CNT)) {
|
|
rc = disp_hcms29xx_send_to_display(softc_ptr,
|
|
softc_ptr->disp_param.disp_buffer+disp_offset);
|
|
}
|
|
else {
|
|
rc = disp_hcms29xx_send_to_display(softc_ptr,
|
|
softc_ptr->disp_param.disp_buffer
|
|
+ softc_ptr->disp_param.disp_buf_cnt
|
|
- DISP_HCMS29XX_DIGIT_CNT);
|
|
}
|
|
/*
|
|
* activate timer, if needed
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
if (softc_ptr->disp_param.disp_buf_cnt > DISP_HCMS29XX_DIGIT_CNT) {
|
|
rc = rtems_timer_fire_after(disp_hcms29xx_timer_id,
|
|
50,
|
|
disp_hcms29xx_timer_sr,
|
|
NULL);
|
|
}
|
|
else {
|
|
rc = rtems_timer_cancel(disp_hcms29xx_timer_id);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* FIXME: display task is dead...
|
|
*/
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
static rtems_status_code disp_hcms29xx_update
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| move given string to display task |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
disp_hcms29xx_drv_t *softc_ptr,
|
|
const char *src
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
{
|
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
|
|
/*
|
|
* obtain trns semaphore
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_semaphore_obtain(softc_ptr->disp_param.trns_sema_id,
|
|
RTEMS_WAIT,RTEMS_NO_TIMEOUT);
|
|
}
|
|
/*
|
|
* copy string...
|
|
*/
|
|
strncpy(softc_ptr->disp_param.trns_buffer,src,
|
|
sizeof(softc_ptr->disp_param.trns_buffer));
|
|
softc_ptr->disp_param.trns_buffer[sizeof(softc_ptr->disp_param.trns_buffer)-1] = '\0';
|
|
|
|
/*
|
|
* release trns semaphore
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_semaphore_release(softc_ptr->disp_param.trns_sema_id);
|
|
}
|
|
|
|
/*
|
|
* send event to task
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_event_send(softc_ptr->disp_param.task_id,
|
|
DISP_HCMS29XX_EVENT_NEWSTR);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
rtems_device_driver disp_hcms29xx_dev_initialize
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| prepare the display device driver to accept write calls |
|
|
| register device with its name |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
rtems_device_major_number major,
|
|
rtems_device_minor_number minor,
|
|
void *arg
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
/*
|
|
* Initialize and register the device
|
|
*/
|
|
{
|
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
|
|
|
|
/*
|
|
* initialize font management
|
|
* FIXME: check, that default glyph exists
|
|
* FIXME: check font size to be 5x7
|
|
*/
|
|
/*
|
|
* translate font according to direction/baseline
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = disp_hcms29xx_alloc_copy_font(
|
|
&FONT_BASE,
|
|
&disp_hcms29xx_font_normal,
|
|
FONT_BASE.descent, /* shift to visibility... */
|
|
FALSE); /* do not rotate */
|
|
}
|
|
/* FIXME: translate font for rotation */
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = disp_hcms29xx_alloc_copy_font(&FONT_BASE,
|
|
&disp_hcms29xx_font_rotate,
|
|
0, /* do not shift */
|
|
true); /* rotate font */
|
|
}
|
|
/*
|
|
* create the trns_buffer semaphore
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_semaphore_create (DISP_HCMS29XX_TRNS_SEMA_NAME,1,
|
|
RTEMS_PRIORITY
|
|
|RTEMS_BINARY_SEMAPHORE
|
|
|RTEMS_INHERIT_PRIORITY
|
|
|RTEMS_NO_PRIORITY_CEILING
|
|
|RTEMS_LOCAL,
|
|
0,
|
|
&softc_ptr->disp_param.trns_sema_id);
|
|
}
|
|
|
|
/*
|
|
* create and start display task
|
|
*/
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_task_create(DISP_HCMS29XX_TASK_NAME,
|
|
20,
|
|
RTEMS_MINIMUM_STACK_SIZE,
|
|
RTEMS_INTERRUPT_LEVEL(0) | RTEMS_TIMESLICE,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&softc_ptr->disp_param.task_id);
|
|
}
|
|
if (rc == RTEMS_SUCCESSFUL) {
|
|
rc = rtems_task_start(softc_ptr->disp_param.task_id,
|
|
disp_hcms29xx_update_task,0);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
rtems_device_driver disp_hcms29xx_dev_open
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| open the display device |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
rtems_device_major_number major,
|
|
rtems_device_minor_number minor,
|
|
void *arg
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
{
|
|
disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
|
|
/*
|
|
* ensure, that disp_hcms29xx device is assumed to be empty
|
|
*/
|
|
softc_ptr->disp_param.dev_buf_cnt = 0;
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
rtems_device_driver disp_hcms29xx_dev_write
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| write to display device |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
rtems_device_major_number major,
|
|
rtems_device_minor_number minor,
|
|
void *arg
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
{
|
|
rtems_libio_rw_args_t *args = arg;
|
|
uint32_t cnt;
|
|
disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
|
|
|
|
for (cnt = 0;cnt < args->count;cnt++) {
|
|
/*
|
|
* accumulate characters written into display dev buffer
|
|
*/
|
|
if (((softc_ptr->disp_param.dev_buf_cnt > 0)
|
|
&&((args->buffer[cnt] == '\n')
|
|
|| (args->buffer[cnt] == '\0'))
|
|
)
|
|
||( softc_ptr->disp_param.dev_buf_cnt >=
|
|
(int) sizeof(softc_ptr->disp_param.dev_buffer) - 1)) {
|
|
softc_ptr->disp_param.dev_buffer[softc_ptr->disp_param.dev_buf_cnt] = '\0';
|
|
/*
|
|
* transfer string to display string, redisplay it...
|
|
*/
|
|
disp_hcms29xx_update(softc_ptr,softc_ptr->disp_param.dev_buffer);
|
|
softc_ptr->disp_param.dev_buf_cnt = 0;
|
|
}
|
|
/*
|
|
* write to dev_buf, if '\n' occured or display device buffer is full
|
|
*/
|
|
if ((args->buffer[cnt] != '\n') &&
|
|
(args->buffer[cnt] != '\0')) {
|
|
softc_ptr->disp_param.dev_buffer[softc_ptr->disp_param.dev_buf_cnt++] =
|
|
args->buffer[cnt];
|
|
}
|
|
}
|
|
args->bytes_moved = args->count;
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
/*=========================================================================*\
|
|
| Function: |
|
|
\*-------------------------------------------------------------------------*/
|
|
rtems_device_driver disp_hcms29xx_dev_close
|
|
(
|
|
/*-------------------------------------------------------------------------*\
|
|
| Purpose: |
|
|
| close the display device |
|
|
+---------------------------------------------------------------------------+
|
|
| Input Parameters: |
|
|
\*-------------------------------------------------------------------------*/
|
|
rtems_device_major_number major,
|
|
rtems_device_minor_number minor,
|
|
void *arg
|
|
)
|
|
/*-------------------------------------------------------------------------*\
|
|
| Return Value: |
|
|
| rtems_status_code |
|
|
\*=========================================================================*/
|
|
{
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
/*
|
|
* driver operation tables
|
|
*/
|
|
static rtems_driver_address_table disp_hcms29xx_ops = {
|
|
.initialization_entry = disp_hcms29xx_dev_initialize,
|
|
.open_entry = disp_hcms29xx_dev_open,
|
|
.write_entry = disp_hcms29xx_dev_write,
|
|
.close_entry = disp_hcms29xx_dev_close
|
|
};
|
|
|
|
|
|
static disp_hcms29xx_drv_t disp_hcms29xx_drv_tbl = {
|
|
{/* public fields */
|
|
.ops = &disp_hcms29xx_ops,
|
|
.size = sizeof (disp_hcms29xx_drv_t),
|
|
},
|
|
{ /* our private fields */
|
|
0,
|
|
{ 0 },
|
|
0,
|
|
{ 0 },
|
|
{ 0 },
|
|
0,
|
|
0,
|
|
0,
|
|
false
|
|
}
|
|
};
|
|
|
|
rtems_libi2c_drv_t *disp_hcms29xx_driver_descriptor =
|
|
&disp_hcms29xx_drv_tbl.libi2c_drv_entry;
|
|
|