4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
32 * \brief 7 segments LED displays (impl)
34 * \author Fabio Bizzi <fbizzi@bizzi.org>
36 * \addtogroup SevenSegDisplay 7 Segments LED Displays Driver
41 #include "drv/led_7seg.h"
42 #include "hw/hw_led_7seg.h"
43 #include "cfg/cfg_arch.h"
44 #include <drv/timer.h>
48 * Define the timer for the refreshing
50 static Timer sseg_trefresh;
53 * FUNCTION: sseg_refresh
55 * This is the procedure that prints the seven_seg structure'string to the display.
56 * It prints a single digit at time and does all the checks to a proper display.
57 * It is called by the wrapper function fired by the timer set in the init procedure.
59 * param SS The void pointer that holds the pointer to the data structure
62 static void sseg_refresh(SevenSeg *SS)
64 /* First Check if the structure is being edited we do a silent exit*/
65 if (SS->busyedit == true)
68 /* If we have displayed all the digits */
69 if (SS->curdigit == CONFIG_LED_7SEG_DIGIT)
72 /* And if we have to display again all the digit */
77 SS->curpos -= CONFIG_LED_7SEG_DIGIT;
79 /* Else is time to scroll the text */
82 /* If we aren't at the end of the string */
83 if (SS->curpos < SS->string_len)
85 SS->curpos -= CONFIG_LED_7SEG_DIGIT;
88 SS->curspeed = SS->speed;
90 /* Else we are at the end of the string */
93 /* Set that the string was displayed at least one time and we can accept a new text*/
95 /* If the string has to be displayed only one time we set an empty string
96 * to display till next print request*/
97 if (SS->runonce == true)
99 /* Else we reset the text to it's first character ad do again the display */
104 SS->curspeed = SS->speed;
109 /* Else We have to do a print*/
112 /* If the text doesn't have to blink we write the character to the proper disply's digit */
113 if (SS->blink == false)
114 sseg_on(SS->string[SS->curpos], SS->curdigit);
115 /* Else we do the blinking */
118 /* If bdigit == 0 we have to blink all the digits */
121 if (SS->curspeed >= (SS->speed/2))
122 sseg_on(SS->string[SS->curpos], SS->curdigit);
126 /* else we have to blink only one digit (bdigit -1) */
128 /* is this the digit to blink? */
129 if (SS->curdigit == ((unsigned int)SS->bdigit-1))
131 if (SS->curspeed >= (SS->speed/2))
132 sseg_on(SS->string[SS->curpos], SS->curdigit);
136 /* no, so let do a normal print */
138 sseg_on(SS->string[SS->curpos], SS->curdigit);
140 /* Ok, next time next char.... ;) */
147 * FUNCTION: sseg_refresh_wrapper
149 * This is a "wrapper" procedure that is called by the timer_setSoftint()
150 * with the unique purpose to call the real sseg_refresh procedure without
151 * the cast of the structure from void to SevenSeg.
153 * param VSS The void pointer that holds the pointer to the data structure
156 static void sseg_refresh_wrapper(void *VSS)
158 /* Here we cast the Structure from void to proper type */
160 SS = (SevenSeg *)VSS;
161 /* now we call the right refresh routine */
163 /* ReStart the timer */
164 timer_add(&sseg_trefresh);
168 * FUNCTION: sseg_tabcheck
170 * This function return the position of the ascii character in the hex
173 * param source The ascii char to be positioned
175 INLINE uint8_t sseg_tabcheck(char source)
177 /* If no legal character is recognized return a "space" */
181 if ((source > 47) && (source < 58))
184 /* Capital Letters */
185 if ((source > 64) && (source < 91))
189 if ((source > 96) && (source < 123))
207 * FUNCTION: sseg_digitbuild
209 * This function return the hex value of the graphic digit
210 * from a list of segments (ex. ACDP).
212 * param source The string of segments
214 INLINE uint8_t sseg_digitbuild(const char *gstring, size_t start, size_t stop)
216 /* the default "space" char returned if no "legal" segments recognized */
217 uint8_t graphdigit = SEGMENT_EMPTY;
221 for (x=start;x<=stop;x++)
227 SET_SEGMENT(graphdigit, SEGMENT_A);
231 SET_SEGMENT(graphdigit, SEGMENT_B);
235 SET_SEGMENT(graphdigit, SEGMENT_C);
239 SET_SEGMENT(graphdigit, SEGMENT_D);
243 SET_SEGMENT(graphdigit, SEGMENT_E);
247 SET_SEGMENT(graphdigit, SEGMENT_F);
251 SET_SEGMENT(graphdigit, SEGMENT_G);
255 SET_SEGMENT(graphdigit, SEGMENT_P);
263 * \brief Print a string on the display
265 * This is the procedure that fills the seven_seg structure with the translated
268 * To print a string simply call the procedure with a text string as the second parameter.
269 * Unrecognized characters are printed as a space
271 * To print "graphic" digits you have to enter them as a sequence of segments between "<>"
274 * sevenseg_print(display,"<bf>Test Graphic<bf>");
276 * This example will print "Test Graphic"
278 * This is the segments table:
288 * \param SS Pointer to the SevenSeg structure
289 * \param sstring String to be displayed
291 * \return 0 if all went well, -1 if the display is locked, -2 if the string too long -3 if the string is malformed.
293 int sevenseg_print(SevenSeg *SS, const char *sstring)
295 size_t x,y,string_lenght,dotnumber,graph_digit_num,bracket_num,startgraph,stopgraph;
296 bool dotjump = false;
299 /* Check if the display is unlocked */
300 if (SS->busyedit == false)
303 /* Check if the string is too big */
304 if (sizeof(&sstring) > (CONFIG_LED_7SEG_STRLEN-(2*CONFIG_LED_7SEG_DIGIT)))
307 /* get the string length and set the number of dots and graphic in the string to 0 */
308 string_lenght = strlen(sstring);
313 /* check if there are some dots an graphics in the string and report the number in dotnumber and graphnumber */
314 for (x=0;x<string_lenght;x++)
316 /* If the first char is a "lonely" dot it has to be counted as a character */
317 if ((sstring[x] == '.') & (x > 0))
319 /* If the previuos charachter is not a dot or a space we have a dot that
320 * has to be considered as a part of a previous character so we have to
322 if ((sstring[x-1] != '.') & (sstring[x-1] != ' '))
325 /* If we have a "<" or a ">" we have a graphic char */
326 if (sstring[x] == '<')
330 while ((sstring[x] != '>') & (x<string_lenght))
338 graph_digit_num+=bracket_num;
339 /* if graphoc is > 0 and is not pair we have a malformed string so exit with error */
345 /* Set the number of characters that compose the graphic
346 * to remove from the string, we subtract the "real" number
347 * of graphic character to display */
348 graph_digit_num-=(bracket_num/2);
351 /* If the *REAL* lenght of the string is less or equal than the number of digits */
352 if ((string_lenght-dotnumber-graph_digit_num) <= CONFIG_LED_7SEG_DIGIT)
354 /* If the *REAL* lenght of the string is less than number of digits */
355 if ((string_lenght-dotnumber-graph_digit_num) < CONFIG_LED_7SEG_DIGIT)
357 /* Fill the left side of the string with blanks */
358 for (x=0; x<(CONFIG_LED_7SEG_DIGIT-(string_lenght-dotnumber-graph_digit_num)); x++)
359 SS->string[x] = segstable[38];
364 /* Else we have the exact string length of the display */
370 /* Else we have the string length bigger than the display and we need to fill
371 * the entire left side of the string with blanks to begin the scroll from the
372 * rigthest side of the display */
373 for (x=0; x<CONFIG_LED_7SEG_DIGIT; x++)
374 SS->string[x] = segstable[38];
375 y = CONFIG_LED_7SEG_DIGIT;
377 /* Here we start to fill the string with the Hex 7seg characters values */
379 for (x=0; x<string_lenght; x++)
381 /* check if the charcter is a graphic character delimiter */
382 if (sstring[x] == '<')
385 /* set the first character of the graphic "string" to be passed to sseg_digitbuild */
387 /* if we have an empty graphic char we return an error */
388 if (sstring[x] == '>')
390 while (sstring[x] != '>')
392 /* set the last character of the graphic "string" to be passed to sseg_digitbuild */
394 /* if we have a graphic char bigger than 8 (all the segments of the digit) we return an error */
395 if (stopgraph-startgraph > 7)
397 /* fill the destination string with the graphic digit returned by sseg_digitbuild */
398 SS->string[y] = sseg_digitbuild(sstring,startgraph,stopgraph);
404 hexchar = sseg_tabcheck(sstring[x]);
405 /* do we have a dot? */
408 /* If we are at the first character of the string it has to be forced
409 * as "lonly" dot ;) */
410 if ((x > 0) & ((sstring[x-1] != '.') & (sstring[x-1] != ' ')))
412 #if CONFIG_LED_7SEG_CCAT
413 SS->string[y-1] = SS->string[y-1] | segstable[hexchar];
415 SS->string[y-1] = SS->string[y-1] & segstable[hexchar];
420 /* If the last character was a dot and we aren't at the first character of the string
421 * we have just inserted it */
424 /* Let's put the character in the structure's string */
427 SS->string[y] = segstable[hexchar];
432 /* If we have the string length bigger than the display we need to fill
433 * the entire right side of the string with blanks to end the scroll
434 * to the rigthest side of the display */
435 if ((string_lenght-dotnumber-graph_digit_num) > CONFIG_LED_7SEG_DIGIT)
437 for (x=0; x<CONFIG_LED_7SEG_DIGIT; x++)
439 SS->string[y] = segstable[38];
443 /* Let's put the total string length to the structure */
450 * \brief initialize the structure and the timer for the display
452 * This is the procedure that inits all the structures that rules the 7 segments
453 * display and set the timer for the proper print/refresh of the text.
455 * \param SS Pointer to the SevenSeg structure
457 void sevenseg_init(SevenSeg *SS)
460 * Init the 7segments string structure
464 SS->busyedit = false;
467 * Init the I/O ports and set the display OFF
472 * Define the timer for the refresh of the display
473 * The timer calls the sevenseg_refresh function
474 * every "CONFIG_LED_7SEG_RTIME" milliseconds for
475 * an acceptable persistance of a single 7 segments
479 timer_setSoftint(&sseg_trefresh, sseg_refresh_wrapper, (void *)SS);
481 timer_setDelay(&sseg_trefresh, ms_to_ticks(CONFIG_LED_7SEG_RTIME));
483 timer_add(&sseg_trefresh);
487 * \brief check if is possible to do a new print
489 * This is the procedure that check if the print of the current text is run
490 * almost one time and we're ready to print a new text.
492 * \param SS Pointer to the SevenSeg structure
494 * \return true if we can print a new text, false if we're still printing the previous text for the first time and we have to wait.
496 bool sevenseg_isReady(SevenSeg *SS)
498 return !SS->firstrun;
502 * \brief unlock the SevenSeg structure and stops the print
504 * This is the procedure that check if the print of the current text is run
505 * almost one time and then set the status of the display to "unlocked".
507 * \param SS Pointer to the SevenSeg structure
509 * \return true if the display is unlocked, false if the dispaly is still locked.
511 bool sevenseg_unlock(SevenSeg *SS)
513 if (SS->firstrun == false)
526 * \brief lock the SeveSeg structure and starts a new print
528 * This is the procedure that lock the display and permit
529 * the print of the text.
531 * \param SS Pointer to the SevenSeg structure
533 * \return true if the display is now locked, false if the display was already locked.
535 bool sevenseg_lock(SevenSeg *SS)
537 if (SS->busyedit == true)
539 /* If the string is longer than the number of the digit of the display we
540 * reset the single digit blink to zero to be sure that the display of
541 * the text is clean from previous single digit blinking settings */
542 if (SS->string_len > CONFIG_LED_7SEG_DIGIT)
544 SS->busyedit = false;
552 * \brief set the blinking of the digits of the display
554 * This is the procedure that set the blinking of the display.
555 * You can choose to blink all the display or only a single
558 * \param SS Pointer to the SevenSeg structure
559 * \param blink if true the display will blink
560 * \param digit if 0 all the digits have to blink, else the digit that has to blink
562 * \return true if the set was succesfull, false if the set was not succesfull.
564 bool sevenseg_setBlink(SevenSeg *SS, bool blink, uint8_t digit)
566 if (SS->busyedit == true)
573 if ((digit-1) <= CONFIG_LED_7SEG_DIGIT)
586 * \brief set if the text has to be displayed just one time
588 * This is the procedure that set if the text has to be displayed
591 * \param SS Pointer to the SevenSeg structure
592 * \param runonce true if the text has to be displayed only one time, false if the text has to be displayed till next print
594 * \return true if the set was succesfull, false if the set was not succesfull.
596 bool sevenseg_setRunonce(SevenSeg *SS, bool runonce)
598 if (SS->busyedit == true)
599 SS->runonce = runonce;
606 * \brief set the scrolling speed of the text
608 * This is the procedure that set the scrolling speed of the text
609 * if the text is longer than the display digits or the
610 * duration of the display if the text is smaller or equal the
611 * length of display digits.
613 * \param SS Pointer to the SevenSeg structure
614 * \param r_speed the Scrolling speed or display time
616 * \return true if the set was succesfull, false if the set was not succesfull.
618 bool sevenseg_setRunspeed(SevenSeg *SS, unsigned int r_speed)
620 if (SS->busyedit == true)
623 SS->curspeed = r_speed;
631 * \brief clear the display
633 * This is the procedure that blanks the text to be displayed
634 * and so on clear the display.
636 * \param SS Pointer to the SevenSeg structure
638 * \return true if the clear was succesfull, false if the clear was not succesfull.
640 bool sevenseg_clear(SevenSeg *SS)
642 if (SS->busyedit == true)
644 memset(((void *)&SS->string),segstable[38],sizeof(SS->string));
645 SS->string_len = CONFIG_LED_7SEG_DIGIT;
651 SS->speed = CONFIG_LED_7SEG_SSPEED;
652 SS->curspeed = CONFIG_LED_7SEG_SSPEED;
653 SS->firstrun = false;
659 /** \} */ //defgroup drivers