32x64 3-color message board http://elektorembedded.blogspot.com/

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "font.h"
00003 #include "arial_8pt.h"
00004 #include "ini.h"
00005 #include <ctype.h>
00006 
00007 
00008 #define ROWS  16 /* Two rows are drawn "in parallel". */
00009 #define COLUMNS  64
00010 
00011 typedef enum
00012 {
00013   kOrange = 0,
00014   kGreen = 1,
00015   kRed = 2,
00016   kBlack = 3
00017 }
00018 color_t;
00019 
00020 typedef struct
00021 {
00022   unsigned char pixel[COLUMNS]; // Contains data for 2 rows!
00023 }
00024 row_t;
00025 
00026 typedef struct
00027 {
00028   int rows;
00029   int columns;
00030   row_t row[ROWS];
00031 }
00032 matrix_t;
00033 
00034 matrix_t Panel;
00035 
00036 DigitalOut led1(LED1);
00037 DigitalOut led2(LED2);
00038 DigitalOut led3(LED3);
00039 DigitalOut led4(LED4);
00040 
00041 DigitalOut Enable(p5); // enable
00042 DigitalOut Clock(p15); // clock per bit
00043 DigitalOut Latch(p14); // latch per line
00044 DigitalOut R1(p6); // Red upper half
00045 DigitalOut R2(p7); // Red lower half
00046 DigitalOut G1(p12); // Green upper half
00047 DigitalOut G2(p13); // Green lower half
00048 BusOut Row(p8,p9,p10,p11);
00049 
00050 DigitalIn Switch(p20); // Day selection switch.
00051 
00052 #define PANEL_ON  Enable = 0
00053 #define PANEL_OFF  Enable = 1
00054 #define CLOCK_DATA  Clock=0; Clock=1
00055 #define LATCH_DATA  Latch=0; Latch=1
00056 
00057 Serial PC(USBTX,USBRX); // USB serial port.
00058 LocalFileSystem local("local"); // File system.
00059 const char *ini_file = "/local/pages.ini";
00060 
00061 #define MAX_LINES  (4)
00062 #define MAX_LINE_LENGTH  (128) /* Use very long lines for easy scrolling, we have plenty of memory. */
00063 #define MAX_PAGES  (7)
00064 #define SCROLL_GAP  (24)  /* in pixels */
00065 
00066 
00067 typedef struct
00068 {
00069   char str[MAX_LINE_LENGTH];
00070   color_t color;
00071   int x;
00072   int y;
00073   int scroll;  // <0=left, 0=no scroll, >0=right
00074   int strlen_pixels; // String length in pixels.
00075 }
00076 line_t;
00077 
00078 typedef struct
00079 {
00080   line_t line[MAX_LINES];
00081   int hide;
00082 }
00083 page_entry_t;
00084 
00085 page_entry_t pages[MAX_PAGES];
00086 
00087 
00088 struct
00089 {
00090   float scroll_speed;
00091   float brightness;
00092 }
00093 app_data;
00094 
00095 
00096 void led_sweep();
00097 void panel_load(unsigned char *p_pixel, int nr_of_pixels);
00098 void panel_refresh_row(int nr, row_t *p_pixel_data, int nr_of_pixels);
00099 void panel_refresh(matrix_t *p_panel);
00100 void panel_init(matrix_t& panel, int rows, int columns);
00101 void panel_fill_row(row_t *p_row, unsigned char value, int count);
00102 void panel_fill_matrix(matrix_t& panel, unsigned char value);
00103 void put_pixel(matrix_t& panel, unsigned int x, unsigned int y, color_t color);
00104 int put_char_xy(matrix_t& panel, char ch, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color);
00105 int put_string_xy(matrix_t& panel, char *p_str, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color);
00106 int measure_string(char *p_str, const FONT_INFO *p_font);
00107 void clear_display(void);
00108 int is_valid_char(char ch);
00109 color_t str_to_color(const char *p_str);
00110 int ini_file_handler(void* user, const char* section, const char* name, const char* value);
00111 void page_pre_init(void);
00112 void page_post_init(const FONT_INFO *p_font);
00113 int page_next(int page);
00114 int page_show(matrix_t& panel, int p);
00115 
00116 
00117 void led_sweep()
00118 {
00119   led1 = 0;
00120   led2 = 0;
00121   led3 = 0;
00122   led4 = 0;
00123   led1 = 1;
00124   wait(0.05);
00125   led1 = 0;
00126   led2 = 1;
00127   wait(0.05);
00128   led2 = 0;
00129   led3 = 1;
00130   wait(0.05);
00131   led3 = 0;
00132   led4 = 1;
00133   wait(0.05);
00134   led4 = 0;
00135 }
00136 
00137 
00138 // Clock the data into the display.
00139 // This is where the bit-banging happens.
00140 void panel_load(unsigned char *p_pixel, int nr_of_pixels)
00141 {
00142   int i;
00143   for (i=0; i<nr_of_pixels; i++)
00144   {
00145     unsigned char pixel = p_pixel[i];
00146     R1 = pixel & 0x01;
00147     pixel >>= 1;
00148     G1 = pixel & 0x01;
00149     pixel >>= 1;
00150     R2 = pixel & 0x01;
00151     pixel >>= 1;
00152     G2 = pixel & 0x01;
00153     CLOCK_DATA;
00154   }
00155   LATCH_DATA;
00156 }
00157 
00158 
00159 void panel_refresh_row(int nr, row_t *p_pixel_data, int nr_of_pixels)
00160 {
00161   Row = nr;
00162   panel_load(p_pixel_data->pixel,nr_of_pixels);
00163   PANEL_ON;
00164   wait(app_data.brightness);
00165   PANEL_OFF;
00166 }
00167 
00168 
00169 void panel_refresh(matrix_t *p_panel)
00170 {
00171   int i;
00172   for (i=0; i<p_panel->rows; i++)
00173   {
00174     panel_refresh_row(i,&p_panel->row[i],p_panel->columns);
00175   }
00176 }
00177 
00178 
00179 void panel_init(matrix_t& panel, int rows, int columns)
00180 {
00181   CLOCK_DATA; // Init the clock line
00182   LATCH_DATA; // Reset the shift registers
00183   panel.rows = rows;
00184   panel.columns = columns;
00185   panel_fill_matrix(panel,kBlack); // Clear display.
00186 }
00187 
00188 
00189 void panel_fill_row(row_t *p_row, unsigned char value, int count)
00190 {
00191   int i;
00192   for (i=0; i<count; i++)
00193   {
00194     p_row->pixel[i] = value;
00195   }
00196 }
00197 
00198 
00199 void panel_fill_matrix(matrix_t& panel, unsigned char value)
00200 {
00201   int i;
00202   for (i=0; i<panel.rows; i++)
00203   {
00204     // Two rows are stored in one row...
00205     panel_fill_row(&panel.row[i],(value<<2)+value,panel.columns);
00206   }
00207 }
00208 
00209 
00210 void put_pixel(matrix_t& panel, unsigned int x, unsigned int y, color_t color)
00211 {
00212   unsigned char mask;
00213   unsigned char c;
00214 
00215   if (x<panel.columns && y<2*panel.rows)
00216   {
00217     mask = 0x03;
00218     c = color;
00219     if (y>=panel.rows)
00220     {
00221       // Remember: two rows are stored in one.
00222       y -= panel.rows;
00223       c <<= 2;
00224       mask <<= 2;
00225     }
00226     c |= ~mask; // Do not overwrite the other pixel.
00227     panel.row[y].pixel[x] |= mask; // Clear pixel (pixels are active low!).
00228     panel.row[y].pixel[x] &= c; // Add in the zeroes.
00229   }
00230 }
00231 
00232 
00233 int put_char_xy(matrix_t& panel, char ch, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color)
00234 {
00235   int i, h, w;
00236   if (p_font!=NULL)
00237   {
00238     i = ch - p_font->start_char;
00239     int width = p_font->p_character_descriptor[i].width;
00240     int second_byte = 0;
00241     if (width>8)
00242     {
00243       // Some wide characters are coded in two bytes.
00244       second_byte = width - 8;
00245       width = 8;
00246     }
00247     int offset = p_font->p_character_descriptor[i].offset;
00248     const uint8_t *p_char = p_font->p_character_bitmaps + offset;
00249     uint8_t mask;
00250     for (h=0; h<p_font->height; h++)
00251     {
00252       // Plot pixels for first byte.
00253       mask = 0x80;
00254       for (w=0; w<width; w++)
00255       {
00256         if ((*p_char&mask)!=0) put_pixel(panel,x+w,y+h,color);
00257         mask >>= 1;
00258       }
00259       if (second_byte>0)
00260       {
00261         // Handle 2nd byte of extra wide characters.
00262         p_char += 1;
00263         mask = 0x80;
00264         for (w=0; w<second_byte; w++)
00265         {
00266           if ((*p_char&mask)!=0) put_pixel(panel,x+w+8,y+h,color);
00267           mask >>= 1;
00268         }
00269       }
00270       p_char += 1;
00271     }
00272     return p_font->p_character_descriptor[i].width;
00273   }
00274   return 0;
00275 }
00276 
00277 
00278 int put_string_xy(matrix_t& panel, char *p_str, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color)
00279 {
00280   int _x = 0;
00281   while (*p_str!=0)
00282   {
00283     _x += put_char_xy(panel,*p_str,x+_x,y,p_font,color);
00284     _x += 1;
00285     p_str += 1;
00286   }
00287   return _x>0? _x-1 : 0;
00288 }
00289 
00290 
00291 // Return the length of a string in pixels when printed using the provided font.
00292 int measure_string(char *p_str, const FONT_INFO *p_font)
00293 {
00294   int i;
00295   int strlen_pixels = 0;
00296   if (p_font!=NULL)
00297   {
00298     while (*p_str!=0)
00299     {
00300       i = *p_str - p_font->start_char;
00301       strlen_pixels += p_font->p_character_descriptor[i].width;
00302       strlen_pixels += 1;
00303       p_str += 1;
00304     }
00305   }
00306   return strlen_pixels;
00307 }
00308 
00309 
00310 void clear_display(void)
00311 {
00312   panel_fill_matrix(Panel,kBlack);
00313 }
00314 
00315 
00316 int is_valid_char(char ch)
00317 {
00318   return (ch>=' ' && ch<='~');
00319 }
00320 
00321 #define IS_SECTION(a)  if (strcmp(p_section,(a))==0)
00322 #define IS_NAME(a)  if (strcmp(p_name,(a))==0)
00323 #define IS_VALUE(a)  if (strcmp(p_value,(a))==0)
00324 
00325 color_t str_to_color(const char *p_str)
00326 {
00327   color_t color = kGreen;
00328   if (strcmp(p_str,"green")==0) color = kGreen;
00329   else if (strcmp(p_str,"orange")==0) color = kOrange;
00330   else if (strcmp(p_str,"red")==0) color = kRed;
00331   else if (strcmp(p_str,"black")==0) color = kBlack;
00332   return color;
00333 }
00334 
00335 
00336 int ini_file_handler(void *p_user, const char *p_section, const char *p_name, const char *p_value)
00337 {
00338   // Called from ini.c
00339   
00340   int p = 0;
00341   
00342   IS_SECTION("global")
00343   {
00344     IS_NAME("brightness") app_data.brightness = atof(p_value)/10000.0;
00345     else IS_NAME("speed") app_data.scroll_speed = atof(p_value)/1000.0;
00346   }
00347   else IS_SECTION("page1") p = 0;
00348   else IS_SECTION("page2") p = 1;
00349   else IS_SECTION("page3") p = 2;
00350   else IS_SECTION("page4") p = 3;
00351   else IS_SECTION("page5") p = 4;
00352   else IS_SECTION("page6") p = 5;
00353   else IS_SECTION("page7") p = 6;
00354 
00355        IS_NAME("hide") pages[p].hide = atoi(p_value);
00356   else IS_NAME("text1") strcpy(pages[p].line[0].str,p_value);
00357   else IS_NAME("text2") strcpy(pages[p].line[1].str,p_value);
00358   else IS_NAME("text3") strcpy(pages[p].line[2].str,p_value);
00359   else IS_NAME("text4") strcpy(pages[p].line[3].str,p_value);
00360   else IS_NAME("color1") pages[p].line[0].color = str_to_color(p_value);
00361   else IS_NAME("color2") pages[p].line[1].color = str_to_color(p_value);
00362   else IS_NAME("color3") pages[p].line[2].color = str_to_color(p_value);
00363   else IS_NAME("color4") pages[p].line[3].color = str_to_color(p_value);
00364   else IS_NAME("x1") pages[p].line[0].x = atoi(p_value);
00365   else IS_NAME("x2") pages[p].line[1].x = atoi(p_value);
00366   else IS_NAME("x3") pages[p].line[2].x = atoi(p_value);
00367   else IS_NAME("x4") pages[p].line[3].x = atoi(p_value);
00368   else IS_NAME("y1") pages[p].line[0].y = atoi(p_value);
00369   else IS_NAME("y2") pages[p].line[1].y = atoi(p_value);
00370   else IS_NAME("y3") pages[p].line[2].y = atoi(p_value);
00371   else IS_NAME("y4") pages[p].line[3].y = atoi(p_value);
00372   else IS_NAME("scroll1") pages[p].line[0].scroll = atoi(p_value);
00373   else IS_NAME("scroll2") pages[p].line[1].scroll = atoi(p_value);
00374   else IS_NAME("scroll3") pages[p].line[2].scroll = atoi(p_value);
00375   else IS_NAME("scroll4") pages[p].line[3].scroll = atoi(p_value);
00376 
00377   // Return 0 on error.
00378   return 1;
00379 }
00380 
00381 
00382 void page_pre_init(void)
00383 {
00384   int i, j;
00385   int y;
00386   // Set zero default values.
00387   memset(&pages,0,sizeof(pages));
00388   for (j=0; j<MAX_PAGES; j++)
00389   {
00390     y = 0;
00391     for (i=0; i<MAX_LINES; i++)
00392     {
00393       // Set non-zero default values.
00394       pages[j].line[i].color = kBlack;
00395       pages[j].line[i].y = y;
00396       y += 8;
00397     }
00398   }
00399 }
00400 
00401 
00402 void page_post_init(const FONT_INFO *p_font)
00403 {
00404   int i, j;
00405   for (j=0; j<MAX_PAGES; j++)
00406   {
00407     for (i=0; i<MAX_LINES; i++)
00408     {
00409       // We need to know the length in pixels of each string.
00410       pages[j].line[i].strlen_pixels = measure_string(pages[j].line[i].str,p_font);
00411     }
00412   }
00413 }
00414 
00415 
00416 int page_next(int page)
00417 {
00418   page += 1;
00419   if (page<0) page = MAX_PAGES - 1;
00420   else if (page>=MAX_PAGES) page = 0;
00421   return page;
00422 }
00423 
00424 
00425 int page_show(matrix_t& panel, int p)
00426 {
00427   int i;
00428   clear_display();
00429   // Show page if not hidden.
00430   if (pages[p].hide==0)
00431   {
00432     for (i=0; i<MAX_LINES; i++)
00433     {
00434       int x = pages[p].line[i].x;
00435       // Print the string.
00436       put_string_xy(panel,pages[p].line[i].str,x,pages[p].line[i].y,&arial_8pt_font_info,pages[p].line[i].color);
00437       // Handle scrolling.
00438       if (pages[p].line[i].scroll!=0)
00439       {
00440         // Simply print the string a second time, display clipping will prevent 
00441         // artifacts when a string is partly printed off-screen.
00442         if (pages[p].line[i].scroll<0)
00443         {
00444           // Scroll to the left.
00445           x += (pages[p].line[i].strlen_pixels + SCROLL_GAP);
00446           // Reset the starting point when the string is completely off screen.
00447           if (pages[p].line[i].x+pages[p].line[i].strlen_pixels<0) pages[p].line[i].x = x;
00448         }
00449         else if (pages[p].line[i].scroll>0)
00450         {
00451           // Scroll to the right.
00452           x -= (pages[p].line[i].strlen_pixels + SCROLL_GAP);
00453           // Reset the starting point when the string is completely off screen.
00454           if (pages[p].line[i].x>=COLUMNS) pages[p].line[i].x = x;
00455         }
00456         put_string_xy(panel,pages[p].line[i].str,x,pages[p].line[i].y,&arial_8pt_font_info,pages[p].line[i].color);
00457         
00458         // Update x position.
00459         pages[p].line[i].x += pages[p].line[i].scroll;
00460       }
00461     }
00462   }
00463   else p = page_next(p); // Page is hidden, move on to the next page.
00464 
00465   return p;
00466 }
00467 
00468 
00469 int main() 
00470 {
00471   int page = 0;
00472   int debounce = 0;
00473   const FONT_INFO *p_font = &arial_8pt_font_info;
00474 
00475   PC.printf("\nmbed LED panel experiments\n");
00476   led_sweep();
00477 
00478   led1 = 0;
00479   led2 = 0;
00480   led3 = 0;
00481   led4 = 0;
00482   
00483   // Set some default values.
00484   app_data.brightness = 0.0005;
00485   app_data.scroll_speed = 0.001;
00486 
00487   // Setup display.
00488   PANEL_OFF;
00489   panel_init(Panel,ROWS,COLUMNS);
00490 
00491   // Read page data.
00492   page_pre_init();
00493   int error = false;
00494   error = ini_parse(ini_file,ini_file_handler,0);
00495   page_post_init(p_font);
00496   
00497   //sprintf(pages[0].line[0].str,"%0.3f",app_data.scroll_speed);
00498   
00499   while (1)
00500   {
00501     if (error==true)
00502     {
00503       put_string_xy(Panel,"file not found",0,0,p_font,kRed);
00504     }
00505     else
00506     {
00507       page = page_show(Panel,page);
00508     }
00509 
00510     // Handle next-page switch.
00511     if (Switch==1)
00512     {
00513       if (debounce<10) debounce += 1;
00514       else if (debounce==10)
00515       {
00516         debounce += 1;
00517         page = page_next(page);
00518         clear_display();
00519       }
00520     }
00521     else debounce = 0;
00522             
00523     /*if (PC.readable()) 
00524     {
00525       int ch;
00526       ch = PC.getc();
00527       PC.putc(ch);
00528       if (ch=='B') color = kBlack;
00529       else if (ch=='R') color = kRed;
00530       else if (ch=='O') color = kOrange;
00531       else if (ch=='G') color = kGreen;
00532       else if (ch=='x') x -= 1;
00533       else if (ch=='X') x += 1;
00534       else if (ch=='y') y -= 1;
00535       else if (ch=='Y') y += 1;
00536       PC.printf("\tx=%d, y=%d, color=%d\n",x,y,color);
00537       clear_display();
00538     }*/
00539     
00540     panel_refresh(&Panel); // Call regularly!
00541     wait(app_data.scroll_speed); // Slow down, but not too much.
00542   }
00543 }