Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:04

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Display driver for HCMS29xx.
0005  *
0006  * This file contains the SPI based driver for a HCMS29xx 4 digit
0007  * alphanumeric LED display.
0008  */
0009 
0010 /*
0011  * Copyright (c) 2008 embedded brains GmbH & Co. KG
0012  *
0013  * Redistribution and use in source and binary forms, with or without
0014  * modification, are permitted provided that the following conditions
0015  * are met:
0016  * 1. Redistributions of source code must retain the above copyright
0017  *    notice, this list of conditions and the following disclaimer.
0018  * 2. Redistributions in binary form must reproduce the above copyright
0019  *    notice, this list of conditions and the following disclaimer in the
0020  *    documentation and/or other materials provided with the distribution.
0021  *
0022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0023  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0025  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0026  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0027  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0028  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0029  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0030  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0032  * POSSIBILITY OF SUCH DAMAGE.
0033  */
0034 
0035 #include <string.h>
0036 #include <stdlib.h>
0037 
0038 #include <rtems.h>
0039 #include <rtems/libio.h>
0040 #include <rtems/score/assert.h>
0041 #include <bsp.h>
0042 #include <rtems/libi2c.h>
0043 #include <libchip/disp_hcms29xx.h>
0044 #include "font_hcms29xx.h"
0045 #define FONT_BASE font_hcms29xx_base
0046 
0047 
0048 #define DISP_HCMS29XX_DIGIT_CNT (4)
0049 #define DISP_HCMS29XX_SEMA_NAME      rtems_build_name('D','4','I','Q')
0050 #define DISP_HCMS29XX_TRNS_SEMA_NAME rtems_build_name('D','4','T','R')
0051 #define DISP_HCMS29XX_TIMER_NAME     rtems_build_name('D','4','T','M')
0052 #define DISP_HCMS29XX_TASK_NAME      rtems_build_name('D','4','T','A')
0053 
0054 #define DISP_HCMS29XX_EVENT_TIMER  RTEMS_EVENT_1
0055 #define DISP_HCMS29XX_EVENT_NEWSTR RTEMS_EVENT_2
0056 
0057 
0058 static disp_font_t disp_hcms29xx_font_normal;
0059 static disp_font_t disp_hcms29xx_font_rotate;
0060 const rtems_libi2c_tfr_mode_t spi_disphcms29xx_tfr_mode = {
0061   .baudrate = 1000000,
0062   .bits_per_char = 8,
0063   .lsb_first = true,
0064   .clock_inv = true,
0065   .clock_phs = true,
0066   .idle_char = 0
0067 };
0068 
0069 static disp_hcms29xx_drv_t disp_hcms29xx_drv_tbl;
0070 
0071 /*=========================================
0072  * font management functions
0073  */
0074 
0075 /*=========================================================================*\
0076 | Function:                                                                 |
0077 \*-------------------------------------------------------------------------*/
0078 static rtems_status_code disp_hcms29xx_font_struct_size
0079   (
0080 /*-------------------------------------------------------------------------*\
0081 | Purpose:                                                                  |
0082 |   compute size of font data structure tree                                |
0083 +---------------------------------------------------------------------------+
0084 | Input Parameters:                                                         |
0085 \*-------------------------------------------------------------------------*/
0086   disp_font_t            src,           /* source font                     */
0087   size_t                *dst_size       /* destination: size of font struct*/
0088 )
0089 /*-------------------------------------------------------------------------*\
0090 | Return Value:                                                             |
0091 |    rtems_status_code                                                      |
0092 \*=========================================================================*/
0093 {
0094 
0095   rtems_status_code rc = RTEMS_SUCCESSFUL;
0096   size_t font_size = 0;
0097   size_t glyph_idx;
0098   /*
0099    * check parameters
0100    */
0101   if ((rc == RTEMS_SUCCESSFUL) &&
0102       (src == NULL)) {
0103     rc = RTEMS_INVALID_ADDRESS;
0104   }
0105   if (rc == RTEMS_SUCCESSFUL) {
0106     font_size =
0107       sizeof(*src);                      /* font_base structure       */
0108   }
0109   glyph_idx = 0;
0110   while ((rc == RTEMS_SUCCESSFUL) &&
0111      (glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0])))) {
0112     if (src->latin1[glyph_idx] != NULL) {
0113       font_size += sizeof(*(src->latin1[glyph_idx]))
0114     + (size_t) src->latin1[glyph_idx]->bb.w;
0115     }
0116     glyph_idx++;
0117   }
0118   *dst_size = font_size;
0119 
0120   return rc;
0121 }
0122 
0123 /*=========================================================================*\
0124 | Function:                                                                 |
0125 \*-------------------------------------------------------------------------*/
0126 static inline unsigned char disp_hcms29xx_bitswap
0127   (
0128 /*-------------------------------------------------------------------------*\
0129 | Purpose:                                                                  |
0130 |   swap data bits in byte (7<->0 , 6<->1 etc)                              |
0131 +---------------------------------------------------------------------------+
0132 | Input Parameters:                                                         |
0133 \*-------------------------------------------------------------------------*/
0134   unsigned char byte
0135 )
0136 /*-------------------------------------------------------------------------*\
0137 | Return Value:                                                             |
0138 |    rtems_status_code                                                      |
0139 \*=========================================================================*/
0140 {
0141   unsigned char result = 0;
0142   int smsk,dmsk;
0143   for (smsk =  0x01,dmsk=0x80;
0144        smsk < 0x100;
0145        smsk<<=1   ,dmsk>>=1) {
0146     if ((byte & smsk) != 0) {
0147       result |= (unsigned char) dmsk;
0148     }
0149   }
0150   return result;
0151 }
0152 
0153 /*=========================================================================*\
0154 | Function:                                                                 |
0155 \*-------------------------------------------------------------------------*/
0156 static rtems_status_code disp_hcms29xx_copy_font
0157   (
0158 /*-------------------------------------------------------------------------*\
0159 | Purpose:                                                                  |
0160 |   copy font data from source to dest font structure                       |
0161 +---------------------------------------------------------------------------+
0162 | Input Parameters:                                                         |
0163 \*-------------------------------------------------------------------------*/
0164   disp_font_t src,                      /* source font                     */
0165   struct disp_font_base *dst,           /* ptr to destination font         */
0166   int shift_cnt,                        /* shift count for font            */
0167   bool do_rotate                        /* rotate font, if true            */
0168 )
0169 /*-------------------------------------------------------------------------*\
0170 | Return Value:                                                             |
0171 |    rtems_status_code                                                      |
0172 \*=========================================================================*/
0173 {
0174 
0175   rtems_status_code rc = RTEMS_SUCCESSFUL;
0176   char *alloc_next = (char *)dst;
0177   size_t glyph_idx = 0;
0178   int glyph_size;
0179   unsigned char byte;
0180   int bcnt;
0181 
0182   /*
0183    * check parameters
0184    */
0185   if ((rc == RTEMS_SUCCESSFUL) &&
0186       ((src == NULL) ||
0187        (dst == NULL))) {
0188     rc = RTEMS_INVALID_ADDRESS;
0189   }
0190   /*
0191    * copy font_base structure
0192    */
0193   if (rc == RTEMS_SUCCESSFUL) {
0194     *dst = *src;
0195     alloc_next += sizeof(*dst);
0196   }
0197   /*
0198    * for all glyphs: assign own glyph memory
0199    */
0200   glyph_idx = 0;
0201   while ((rc == RTEMS_SUCCESSFUL) &&
0202      glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0]))) {
0203     if (src->latin1[glyph_idx] != NULL) {
0204       /*
0205        * allocate space for glyph
0206        */
0207       dst->latin1[glyph_idx] = (struct disp_font_glyph *)alloc_next;
0208       alloc_next += sizeof(*(dst->latin1[glyph_idx]));
0209       /*
0210        * copy source values.
0211        * Note: bitmap will be reassigned later
0212        */
0213       *(struct disp_font_glyph *)(dst->latin1[glyph_idx]) =
0214     *(src->latin1[glyph_idx]);
0215     }
0216     else {
0217       dst->latin1[glyph_idx] = NULL;
0218     }
0219     glyph_idx++;
0220   }
0221 
0222   /*
0223    * for all glyphs: reassign bitmap
0224    */
0225   glyph_idx = 0;
0226   while ((rc == RTEMS_SUCCESSFUL) &&
0227      glyph_idx < (sizeof(src->latin1)/sizeof(src->latin1[0]))) {
0228     if (src->latin1[glyph_idx] != NULL) {
0229       glyph_size = src->latin1[glyph_idx]->bb.w;
0230       /*
0231        * allocate space for glyph_bitmap
0232        */
0233       dst->latin1[glyph_idx]->bitmap = (const unsigned char *) alloc_next;
0234       alloc_next += glyph_size;
0235       /*
0236        * copy/transform bitmap
0237        */
0238       for (bcnt = 0;bcnt < glyph_size;bcnt++) {
0239     if (do_rotate) {
0240       byte = src->latin1[glyph_idx]->bitmap[glyph_size - 1 - bcnt];
0241       byte = disp_hcms29xx_bitswap(byte);
0242     }
0243     else {
0244       byte = src->latin1[glyph_idx]->bitmap[bcnt];
0245     }
0246     if (shift_cnt < 0) {
0247       byte = byte << -shift_cnt;
0248     }
0249     else if (shift_cnt > 0) {
0250       byte = byte >> shift_cnt;
0251     }
0252     ((unsigned char *)(dst->latin1[glyph_idx]->bitmap))[bcnt] = byte;
0253       }
0254     }
0255     glyph_idx++;
0256   }
0257   return rc;
0258 }
0259 
0260 /*=========================================================================*\
0261 | Function:                                                                 |
0262 \*-------------------------------------------------------------------------*/
0263 static rtems_status_code disp_hcms29xx_alloc_copy_font
0264   (
0265 /*-------------------------------------------------------------------------*\
0266 | Purpose:                                                                  |
0267 |   copy font data from source to dest font structure, alloc all data       |
0268 +---------------------------------------------------------------------------+
0269 | Input Parameters:                                                         |
0270 \*-------------------------------------------------------------------------*/
0271   const disp_font_t src,                /* source font                     */
0272   disp_font_t *dst,                     /* ptr to destination font         */
0273   int shift_cnt,                        /* shift count for font            */
0274   bool do_rotate                        /* rotate font, if true            */
0275 )
0276 /*-------------------------------------------------------------------------*\
0277 | Return Value:                                                             |
0278 |    rtems_status_code                                                      |
0279 \*=========================================================================*/
0280 {
0281 
0282   rtems_status_code rc = RTEMS_SUCCESSFUL;
0283   size_t src_size = 0;
0284   /*
0285    * check parameters
0286    */
0287   if ((rc == RTEMS_SUCCESSFUL) &&
0288       ((src == NULL)
0289        || (dst == NULL))) {
0290     rc = RTEMS_INVALID_ADDRESS;
0291   }
0292   /*
0293    * determine size of source data
0294    */
0295   if (rc == RTEMS_SUCCESSFUL) {
0296     rc = disp_hcms29xx_font_struct_size(src,&src_size);
0297   }
0298   /*
0299    * allocate proper data area
0300    */
0301   if (rc == RTEMS_SUCCESSFUL) {
0302     *dst = malloc(src_size);
0303     if (*dst == NULL) {
0304       rc = RTEMS_UNSATISFIED;
0305     }
0306   }
0307   /*
0308    * scan through source data, copy to dest
0309    */
0310   if (rc == RTEMS_SUCCESSFUL) {
0311     rc = disp_hcms29xx_copy_font(src,*dst,shift_cnt,do_rotate);
0312   }
0313   return rc;
0314 }
0315 
0316 /*=========================================
0317  * SPI communication functions
0318  */
0319 
0320 /*=========================================================================*\
0321 | Function:                                                                 |
0322 \*-------------------------------------------------------------------------*/
0323 static rtems_status_code disp_hcms29xx_send_to_display
0324   (
0325 /*-------------------------------------------------------------------------*\
0326 | Purpose:                                                                  |
0327 |   request access semaphore to SPI, prepare buffer descriptors, start      |
0328 |   transfer via SPI to display                                             |
0329 +---------------------------------------------------------------------------+
0330 | Input Parameters:                                                         |
0331 \*-------------------------------------------------------------------------*/
0332    disp_hcms29xx_drv_t *softc_ptr,
0333    const volatile char *disp_buffer /* start of chars to display (4 chars or 'til \0)*/
0334 )
0335 /*-------------------------------------------------------------------------*\
0336 | Return Value:                                                             |
0337 |    rtems_status_code                                                      |
0338 \*=========================================================================*/
0339 {
0340   rtems_status_code rc = RTEMS_SUCCESSFUL;
0341   bool char_avail;
0342   const struct disp_font_glyph *glyph_ptr;
0343   disp_font_t curr_font;
0344   int i, ret_cnt;
0345   unsigned char c;
0346 
0347   /*
0348    * select device, set transfer mode, address device
0349    */
0350   if (rc == RTEMS_SUCCESSFUL) {
0351     rc = rtems_libi2c_send_start(softc_ptr->disp_param.minor);
0352   }
0353   /*
0354    * set transfer mode
0355    */
0356   if (rc == RTEMS_SUCCESSFUL) {
0357     rc = -rtems_libi2c_ioctl(softc_ptr->disp_param.minor,
0358                  RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
0359                  &spi_disphcms29xx_tfr_mode);
0360   }
0361 
0362   /*
0363    * address device
0364    */
0365   if (rc == RTEMS_SUCCESSFUL) {
0366     rc = rtems_libi2c_send_addr(softc_ptr->disp_param.minor,true);
0367   }
0368 
0369   /*
0370    * send data
0371    */
0372   if (rc == RTEMS_SUCCESSFUL) {
0373     curr_font =
0374       softc_ptr->disp_param.rotate
0375       ? disp_hcms29xx_font_rotate
0376       : disp_hcms29xx_font_normal;
0377 
0378     char_avail = true;
0379     /*
0380      * FIXME: for rotated display, write last character first...
0381      * maybe we should copy everything to a common buffer and use
0382      * ONE SPI transfer?
0383      */
0384     for (i = 0;
0385      ((rc == RTEMS_SUCCESSFUL) &&
0386       (i < DISP_HCMS29XX_DIGIT_CNT));
0387       i++) {
0388       /* test for end of string... */
0389       c = disp_buffer[i]; /* perform consistent read of disp_buffer */
0390       if (char_avail && (c == '\0')) {
0391     char_avail = false;
0392       }
0393       glyph_ptr = (char_avail
0394            ? curr_font->latin1[c]
0395            : NULL);
0396       if (glyph_ptr == NULL) {
0397     glyph_ptr = curr_font->latin1[' '];
0398       }
0399 
0400       /*
0401        * send 5 bytes from (char *)glyph_ptr->bitmap to SPI
0402        */
0403       if (rc == RTEMS_SUCCESSFUL) {
0404     ret_cnt = rtems_libi2c_write_bytes(softc_ptr->disp_param.minor,
0405                        glyph_ptr->bitmap,5);
0406     if (ret_cnt < 0) {
0407       rc = -ret_cnt;
0408     }
0409       }
0410     }
0411   }
0412   /*
0413    * finish transfer
0414    */
0415   if (rc == RTEMS_SUCCESSFUL) {
0416     rc = rtems_libi2c_send_stop(softc_ptr->disp_param.minor);
0417   }
0418 
0419   return rc;
0420 }
0421 
0422 /*=========================================================================*\
0423 | Function:                                                                 |
0424 \*-------------------------------------------------------------------------*/
0425 static rtems_status_code disp_hcms29xx_send_to_control
0426   (
0427 /*-------------------------------------------------------------------------*\
0428 | Purpose:                                                                  |
0429 |   request access semaphore to SPI, prepare buffer descriptors, start      |
0430 |   transfer via SPI to display                                             |
0431 +---------------------------------------------------------------------------+
0432 | Input Parameters:                                                         |
0433 \*-------------------------------------------------------------------------*/
0434    disp_hcms29xx_drv_t *softc_ptr,
0435    int pwm,   /* value for pwm of LEDs, 0..15 */
0436    int peak,  /* value for peak current for LEDs, 0..3 */
0437    int sleep, /* value to make display "sleep" (0..1 */
0438    int div,   /* divider for external osc input, unused here */
0439    int chain  /* mode to drive other displays, unused here */
0440 )
0441 /*-------------------------------------------------------------------------*\
0442 | Return Value:                                                             |
0443 |    rtems_status_code                                                      |
0444 \*=========================================================================*/
0445 {
0446   rtems_status_code rc = RTEMS_SUCCESSFUL;
0447   int run, ret_cnt;
0448   uint8_t ctrl_buffer;
0449 
0450   /* two accesses, control word 0 and 1 */
0451   for (run = 0;
0452        ((rc == RTEMS_SUCCESSFUL) && (run <= 1));
0453        run++) {
0454     if (rc == RTEMS_SUCCESSFUL) {
0455       if (run == 0) {
0456     ctrl_buffer =
0457       (0              << 7) |
0458       ((sleep & 0x01) << 6) |
0459       ((peak  & 0x03) << 4) |
0460       ((pwm & 0x0f)   << 0);
0461       }
0462       else {
0463     ctrl_buffer =
0464       (1              << 7) |
0465       ((div   & 0x01) << 1) |
0466       ((chain & 0x01) << 0);
0467       }
0468       /*
0469        * select device, set transfer mode, address device
0470        */
0471       if (rc == RTEMS_SUCCESSFUL) {
0472     rc = rtems_libi2c_send_start(softc_ptr->disp_param.minor);
0473       }
0474       /*
0475        * set transfer mode
0476        */
0477       if (rc == RTEMS_SUCCESSFUL) {
0478     rc = -rtems_libi2c_ioctl(softc_ptr->disp_param.minor,
0479                  RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
0480                  &spi_disphcms29xx_tfr_mode);
0481       }
0482 
0483       /*
0484        * address device
0485        */
0486       if (rc == RTEMS_SUCCESSFUL) {
0487     rc = rtems_libi2c_send_addr(softc_ptr->disp_param.minor,true);
0488       }
0489 
0490       /*
0491        * send 1 byte from ctrl_buffer
0492        */
0493       if (rc == RTEMS_SUCCESSFUL) {
0494     ret_cnt = rtems_libi2c_write_bytes(softc_ptr->disp_param.minor,
0495                        &ctrl_buffer,1);
0496     if (ret_cnt < 0) {
0497       rc = -ret_cnt;
0498     }
0499       }
0500     }
0501   } /* next run ... */
0502 
0503   /*
0504    * finish transfer
0505    */
0506   if (rc == RTEMS_SUCCESSFUL) {
0507     rc = rtems_libi2c_send_stop(softc_ptr->disp_param.minor);
0508   }
0509 
0510   return rc;
0511 }
0512 
0513 /*=========================================================================*\
0514 | Function:                                                                 |
0515 \*-------------------------------------------------------------------------*/
0516 static rtems_timer_service_routine disp_hcms29xx_timer_sr
0517 /*-------------------------------------------------------------------------*\
0518 | Purpose:                                                                  |
0519 |   this task updates the string in the display                             |
0520 +---------------------------------------------------------------------------+
0521 | Input Parameters:                                                         |
0522 \*-------------------------------------------------------------------------*/
0523 (
0524  rtems_id id, /* ID of timer, not used  */
0525  void * arg   /* calling arg: softc_ptr */
0526 )
0527 /*-------------------------------------------------------------------------*\
0528 | Return Value:                                                             |
0529 |    <none used>                                                            |
0530 \*=========================================================================*/
0531 {
0532   disp_hcms29xx_drv_t *softc_ptr = arg;
0533 
0534   rtems_event_send(softc_ptr->disp_param.task_id, DISP_HCMS29XX_EVENT_TIMER);
0535 }
0536 
0537 /*=========================================================================*\
0538 | Function:                                                                 |
0539 \*-------------------------------------------------------------------------*/
0540 static rtems_task disp_hcms29xx_update_task
0541   (
0542 /*-------------------------------------------------------------------------*\
0543 | Purpose:                                                                  |
0544 |   this task updates the string in the display                             |
0545 +---------------------------------------------------------------------------+
0546 | Input Parameters:                                                         |
0547 \*-------------------------------------------------------------------------*/
0548    rtems_task_argument argument 
0549 )
0550 /*-------------------------------------------------------------------------*\
0551 | Return Value:                                                             |
0552 |    <never exits>                                                          |
0553 \*=========================================================================*/
0554 {
0555   rtems_event_set  my_events;
0556   rtems_status_code rc = RTEMS_SUCCESSFUL;
0557   int disp_offset = 0;
0558   rtems_id disp_hcms29xx_timer_id;
0559   disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
0560 
0561   /*
0562    * initialize display:
0563    */
0564   /*
0565    * set control attributes for display
0566    * maximum brightness...
0567    */
0568   if (rc == RTEMS_SUCCESSFUL) {
0569     rc = disp_hcms29xx_send_to_control(softc_ptr,
0570                        14,3,1,0,0);/* pwm/peak/nosleep/div/chain */
0571   }
0572 
0573   /*
0574    * set display to blank
0575    */
0576   if (rc == RTEMS_SUCCESSFUL) {
0577     rc = disp_hcms29xx_send_to_display(softc_ptr,
0578                        "");
0579   }
0580 
0581   /*
0582    * create timer for scrolling
0583    */
0584   if (rc == RTEMS_SUCCESSFUL) {
0585     rc = rtems_timer_create(DISP_HCMS29XX_TIMER_NAME,
0586                 &disp_hcms29xx_timer_id);
0587   }
0588 
0589   while (rc == RTEMS_SUCCESSFUL) {
0590     /*
0591      * wait for any event
0592      */
0593     rc = rtems_event_receive(DISP_HCMS29XX_EVENT_NEWSTR |
0594                  DISP_HCMS29XX_EVENT_TIMER ,
0595                  RTEMS_WAIT | RTEMS_EVENT_ANY,
0596                  RTEMS_NO_TIMEOUT,
0597                  &my_events);
0598     if (my_events & DISP_HCMS29XX_EVENT_NEWSTR) {
0599       /*
0600        * fetch new string consistently into local buffer
0601        */
0602       if (rc == RTEMS_SUCCESSFUL) {
0603     rc = rtems_semaphore_obtain(softc_ptr->disp_param.trns_sema_id,
0604                     RTEMS_WAIT,RTEMS_NO_TIMEOUT);
0605       }
0606       if (rc == RTEMS_SUCCESSFUL) {
0607         strlcpy(softc_ptr->disp_param.disp_buffer,
0608                 softc_ptr->disp_param.trns_buffer,
0609                 sizeof(softc_ptr->disp_param.disp_buffer));
0610     softc_ptr->disp_param.disp_buf_cnt =
0611       (int) strlen(softc_ptr->disp_param.disp_buffer);
0612       }
0613       if (rc == RTEMS_SUCCESSFUL) {
0614         rc = rtems_semaphore_release(softc_ptr->disp_param.trns_sema_id);
0615         _Assert_Unused_variable_equals(rc, RTEMS_SUCCESSFUL);
0616       }
0617       /*
0618        * set initial offset to negative value
0619        * to make string static for some ticks
0620        */
0621       disp_offset = -4;
0622     }
0623     if (my_events & DISP_HCMS29XX_EVENT_TIMER) {
0624       /*
0625        * increase disp_offset, if possible, otherwise reset it
0626        */
0627       if ((disp_offset < 0) ||
0628       (disp_offset < softc_ptr->disp_param.disp_buf_cnt-
0629        DISP_HCMS29XX_DIGIT_CNT/2)) {
0630     disp_offset++;
0631       }
0632       else {
0633     disp_offset = -4;
0634       }
0635     }
0636     /*
0637      * display string, starting from disp_offset
0638      */
0639     if (disp_offset < 0) {
0640       rc = disp_hcms29xx_send_to_display(softc_ptr,
0641                      softc_ptr->disp_param.disp_buffer);
0642     }
0643     else if (disp_offset
0644          < (softc_ptr->disp_param.disp_buf_cnt - DISP_HCMS29XX_DIGIT_CNT)) {
0645       rc = disp_hcms29xx_send_to_display(softc_ptr,
0646                      softc_ptr->disp_param.disp_buffer+disp_offset);
0647     }
0648     else {
0649       rc = disp_hcms29xx_send_to_display(softc_ptr,
0650                      softc_ptr->disp_param.disp_buffer
0651                      + softc_ptr->disp_param.disp_buf_cnt
0652                      - DISP_HCMS29XX_DIGIT_CNT);
0653     }
0654     /*
0655      * activate timer, if needed
0656      */
0657     if (rc == RTEMS_SUCCESSFUL) {
0658       if (softc_ptr->disp_param.disp_buf_cnt > DISP_HCMS29XX_DIGIT_CNT) {
0659     rc = rtems_timer_fire_after(disp_hcms29xx_timer_id,
0660                     50,
0661                     disp_hcms29xx_timer_sr,
0662                     NULL);
0663       }
0664       else {
0665     rc = rtems_timer_cancel(disp_hcms29xx_timer_id);
0666       }
0667     }
0668   }
0669   /*
0670    * FIXME: display task is dead...
0671    */
0672 }
0673 
0674 /*=========================================================================*\
0675 | Function:                                                                 |
0676 \*-------------------------------------------------------------------------*/
0677 static rtems_status_code disp_hcms29xx_update
0678   (
0679 /*-------------------------------------------------------------------------*\
0680 | Purpose:                                                                  |
0681 |   move given string to display task                                       |
0682 +---------------------------------------------------------------------------+
0683 | Input Parameters:                                                         |
0684 \*-------------------------------------------------------------------------*/
0685    disp_hcms29xx_drv_t *softc_ptr,
0686    const char *src
0687 )
0688 /*-------------------------------------------------------------------------*\
0689 | Return Value:                                                             |
0690 |    rtems_status_code                                                      |
0691 \*=========================================================================*/
0692 {
0693   rtems_status_code rc = RTEMS_SUCCESSFUL;
0694 
0695   /*
0696    * obtain trns semaphore
0697    */
0698   if (rc == RTEMS_SUCCESSFUL) {
0699     rc = rtems_semaphore_obtain(softc_ptr->disp_param.trns_sema_id,
0700                 RTEMS_WAIT,RTEMS_NO_TIMEOUT);
0701   }
0702   /*
0703    * copy string...
0704    */
0705   strncpy(softc_ptr->disp_param.trns_buffer,src,
0706       sizeof(softc_ptr->disp_param.trns_buffer));
0707   softc_ptr->disp_param.trns_buffer[sizeof(softc_ptr->disp_param.trns_buffer)-1] = '\0';
0708 
0709   /*
0710    * release trns semaphore
0711    */
0712   if (rc == RTEMS_SUCCESSFUL) {
0713     rc = rtems_semaphore_release(softc_ptr->disp_param.trns_sema_id);
0714   }
0715 
0716   /*
0717    * send event to task
0718    */
0719   if (rc == RTEMS_SUCCESSFUL) {
0720     rc = rtems_event_send(softc_ptr->disp_param.task_id,
0721               DISP_HCMS29XX_EVENT_NEWSTR);
0722   }
0723 
0724   return rc;
0725 }
0726 
0727 /*=========================================================================*\
0728 | Function:                                                                 |
0729 \*-------------------------------------------------------------------------*/
0730 rtems_device_driver disp_hcms29xx_dev_initialize
0731   (
0732 /*-------------------------------------------------------------------------*\
0733 | Purpose:                                                                  |
0734 |   prepare the display device driver to accept write calls                 |
0735 |   register device with its name                                           |
0736 +---------------------------------------------------------------------------+
0737 | Input Parameters:                                                         |
0738 \*-------------------------------------------------------------------------*/
0739   rtems_device_major_number  major,
0740   rtems_device_minor_number  minor,
0741   void                      *arg
0742 )
0743 /*-------------------------------------------------------------------------*\
0744 | Return Value:                                                             |
0745 |    rtems_status_code                                                      |
0746 \*=========================================================================*/
0747 /*
0748  * Initialize and register the device
0749  */
0750 {
0751   rtems_status_code rc = RTEMS_SUCCESSFUL;
0752   disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
0753 
0754   /*
0755    * initialize font management
0756    * FIXME: check, that default glyph exists
0757    * FIXME: check font size to be 5x7
0758    */
0759   /*
0760    * translate font according to direction/baseline
0761    */
0762   if (rc == RTEMS_SUCCESSFUL) {
0763     rc = disp_hcms29xx_alloc_copy_font(
0764                    &FONT_BASE,
0765                    &disp_hcms29xx_font_normal,
0766                    FONT_BASE.descent, /* shift to visibility... */
0767                    FALSE); /* do not rotate */
0768   }
0769   /* FIXME: translate font for rotation */
0770   if (rc == RTEMS_SUCCESSFUL) {
0771     rc = disp_hcms29xx_alloc_copy_font(&FONT_BASE,
0772                    &disp_hcms29xx_font_rotate,
0773                    0, /* do not shift */
0774                    true); /* rotate font */
0775   }
0776   /*
0777    * create the trns_buffer semaphore
0778    */
0779   if (rc == RTEMS_SUCCESSFUL) {
0780     rc = rtems_semaphore_create (DISP_HCMS29XX_TRNS_SEMA_NAME,1,
0781                      RTEMS_PRIORITY
0782                      |RTEMS_BINARY_SEMAPHORE
0783                      |RTEMS_INHERIT_PRIORITY
0784                      |RTEMS_NO_PRIORITY_CEILING
0785                      |RTEMS_LOCAL,
0786                      0,
0787                      &softc_ptr->disp_param.trns_sema_id);
0788   }
0789 
0790   /*
0791    * create and start display task
0792    */
0793   if (rc == RTEMS_SUCCESSFUL) {
0794     rc = rtems_task_create(DISP_HCMS29XX_TASK_NAME,
0795                20,
0796                RTEMS_MINIMUM_STACK_SIZE,
0797                RTEMS_INTERRUPT_LEVEL(0) | RTEMS_TIMESLICE,
0798                RTEMS_DEFAULT_ATTRIBUTES,
0799                &softc_ptr->disp_param.task_id);
0800   }
0801   if (rc == RTEMS_SUCCESSFUL) {
0802     rc = rtems_task_start(softc_ptr->disp_param.task_id,
0803               disp_hcms29xx_update_task,0);
0804   }
0805   return rc;
0806 }
0807 
0808 /*=========================================================================*\
0809 | Function:                                                                 |
0810 \*-------------------------------------------------------------------------*/
0811 rtems_device_driver disp_hcms29xx_dev_open
0812 (
0813 /*-------------------------------------------------------------------------*\
0814 | Purpose:                                                                  |
0815 |   open the display device                                                 |
0816 +---------------------------------------------------------------------------+
0817 | Input Parameters:                                                         |
0818 \*-------------------------------------------------------------------------*/
0819   rtems_device_major_number  major,
0820   rtems_device_minor_number  minor,
0821   void                      *arg
0822 )
0823 /*-------------------------------------------------------------------------*\
0824 | Return Value:                                                             |
0825 |    rtems_status_code                                                      |
0826 \*=========================================================================*/
0827 {
0828   disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
0829   /*
0830    * ensure, that disp_hcms29xx device is assumed to be empty
0831    */
0832   softc_ptr->disp_param.dev_buf_cnt = 0;
0833 
0834   return RTEMS_SUCCESSFUL;
0835 }
0836 
0837 /*=========================================================================*\
0838 | Function:                                                                 |
0839 \*-------------------------------------------------------------------------*/
0840 rtems_device_driver disp_hcms29xx_dev_write
0841 (
0842 /*-------------------------------------------------------------------------*\
0843 | Purpose:                                                                  |
0844 |   write to display device                                                 |
0845 +---------------------------------------------------------------------------+
0846 | Input Parameters:                                                         |
0847 \*-------------------------------------------------------------------------*/
0848   rtems_device_major_number  major,
0849   rtems_device_minor_number  minor,
0850   void                      *arg
0851 )
0852 /*-------------------------------------------------------------------------*\
0853 | Return Value:                                                             |
0854 |    rtems_status_code                                                      |
0855 \*=========================================================================*/
0856 {
0857   rtems_libio_rw_args_t *args = arg;
0858   uint32_t cnt;
0859   disp_hcms29xx_drv_t *softc_ptr = &disp_hcms29xx_drv_tbl;
0860 
0861   for (cnt = 0;cnt < args->count;cnt++) {
0862     /*
0863      * accumulate characters written into display dev buffer
0864      */
0865     if (((softc_ptr->disp_param.dev_buf_cnt > 0)
0866     &&((args->buffer[cnt] == '\n')
0867        || (args->buffer[cnt] == '\0'))
0868      )
0869     ||( softc_ptr->disp_param.dev_buf_cnt >=
0870         (int) sizeof(softc_ptr->disp_param.dev_buffer) - 1)) {
0871       softc_ptr->disp_param.dev_buffer[softc_ptr->disp_param.dev_buf_cnt] = '\0';
0872       /*
0873        * transfer string to display string, redisplay it...
0874        */
0875       disp_hcms29xx_update(softc_ptr,softc_ptr->disp_param.dev_buffer);
0876       softc_ptr->disp_param.dev_buf_cnt = 0;
0877     }
0878     /*
0879      * write to dev_buf, if '\n' occured or display device buffer is full
0880      */
0881     if ((args->buffer[cnt] != '\n') &&
0882     (args->buffer[cnt] != '\0')) {
0883       softc_ptr->disp_param.dev_buffer[softc_ptr->disp_param.dev_buf_cnt++] =
0884     args->buffer[cnt];
0885     }
0886   }
0887   args->bytes_moved = args->count;
0888 
0889   return RTEMS_SUCCESSFUL;
0890 }
0891 
0892 /*=========================================================================*\
0893 | Function:                                                                 |
0894 \*-------------------------------------------------------------------------*/
0895 rtems_device_driver disp_hcms29xx_dev_close
0896 (
0897 /*-------------------------------------------------------------------------*\
0898 | Purpose:                                                                  |
0899 |   close the display device                                                |
0900 +---------------------------------------------------------------------------+
0901 | Input Parameters:                                                         |
0902 \*-------------------------------------------------------------------------*/
0903   rtems_device_major_number  major,
0904   rtems_device_minor_number  minor,
0905   void                      *arg
0906 )
0907 /*-------------------------------------------------------------------------*\
0908 | Return Value:                                                             |
0909 |    rtems_status_code                                                      |
0910 \*=========================================================================*/
0911 {
0912 
0913   return RTEMS_SUCCESSFUL;
0914 }
0915 
0916 /*
0917  * driver operation tables
0918  */
0919 static rtems_driver_address_table disp_hcms29xx_ops = {
0920   .initialization_entry = disp_hcms29xx_dev_initialize,
0921   .open_entry =           disp_hcms29xx_dev_open,
0922   .write_entry =          disp_hcms29xx_dev_write,
0923   .close_entry =          disp_hcms29xx_dev_close
0924 };
0925 
0926 
0927 static disp_hcms29xx_drv_t disp_hcms29xx_drv_tbl = {
0928   {/* public fields */
0929     .ops =         &disp_hcms29xx_ops, 
0930     .size =        sizeof (disp_hcms29xx_drv_t),
0931   },
0932   { /* our private fields */
0933     0,
0934     { 0 },
0935     0,
0936     { 0 },
0937     { 0 },
0938     0,
0939     0,
0940     0,
0941     false
0942   }
0943 };
0944 
0945 rtems_libi2c_drv_t *disp_hcms29xx_driver_descriptor = 
0946   &disp_hcms29xx_drv_tbl.libi2c_drv_entry;
0947