BeRTOS
|
00001 00039 #include "lcd_text.h" 00040 #include "lcd_hd44.h" 00041 00042 #include <cfg/macros.h> // BV() 00043 #include <cfg/debug.h> 00044 00045 #include <drv/timer.h> // timer_delay() 00046 00047 #include <mware/formatwr.h> // _formatted_write() 00048 #include <struct/list.h> // LIST_EMPTY() 00049 00050 #include <string.h> // strlen() 00051 00052 00054 #define LCD_LAYERS 6 00055 00056 #if CONFIG_KERN 00057 #include <kern/sem.h> 00059 static struct Semaphore lcd_semaphore; 00060 #define LOCK_LCD sem_obtain(&lcd_semaphore) 00061 #define UNLOCK_LCD sem_release(&lcd_semaphore) 00062 #else /* !CONFIG_KERN */ 00063 #define LOCK_LCD do {} while (0) 00064 #define UNLOCK_LCD do {} while (0) 00065 #endif /* !CONFIG_KERN */ 00066 00067 DECLARE_LIST_TYPE(Layer); 00068 00069 Layer *lcd_DefLayer; 00070 static Layer lcd_LayersPool[LCD_LAYERS]; 00071 static LIST_TYPE(Layer) lcd_Layers; 00072 static LIST_TYPE(Layer) lcd_FreeLayers; 00073 00079 static uint8_t lcd_CursorStatus; 00080 00082 static lcdpos_t lcd_CursorAddr; 00083 00084 00085 void lcd_setAddr(Layer *layer, lcdpos_t addr) 00086 { 00087 /* Sanity check: wrap around to display limits */ 00088 while (addr >= CONFIG_LCD_ROWS * CONFIG_LCD_COLS) 00089 addr -= CONFIG_LCD_ROWS * CONFIG_LCD_COLS; 00090 00091 layer->addr = addr; 00092 } 00093 00094 #if CONFIG_KERN 00095 00096 void lcd_lock(void) 00097 { 00098 LOCK_LCD; 00099 } 00100 00101 00102 void lcd_unlock(void) 00103 { 00104 UNLOCK_LCD; 00105 } 00106 00107 #endif /* CONFIG_KERN */ 00108 00109 00118 static void lcd_putCharUnlocked(char c, Layer *layer) 00119 { 00120 Layer *l2; 00121 lcdpos_t addr = layer->addr; 00122 00123 /* Store character in layer buffer */ 00124 layer->buf[addr] = c; 00125 00126 /* Move to next character */ 00127 if (++layer->addr >= CONFIG_LCD_COLS * CONFIG_LCD_ROWS) 00128 layer->addr = 0; 00129 00130 /* Do not write on LCD if layer is hidden. */ 00131 if (layer->pri == LAYER_HIDDEN) 00132 return; 00133 00134 /* 00135 * Check if this location is obscured by 00136 * other layers above us. 00137 */ 00138 for (l2 = layer->pred; l2->pred; l2 = l2->pred) 00139 { 00140 if (l2->buf[addr]) 00141 { 00142 /* DB(kprintf("layer %04x obs %04x at %d\n", l2, layer, addr);) */ 00143 return; 00144 } 00145 } 00146 00147 /* Write character */ 00148 if (c) 00149 lcd_putc(addr, c); 00150 else 00151 /* FIXME: should look for layers beneath! */ 00152 lcd_putc(addr, ' '); 00153 } 00154 00155 00156 void lcd_putChar(char c, Layer *layer) 00157 { 00158 LOCK_LCD; 00159 lcd_putCharUnlocked(c, layer); 00160 UNLOCK_LCD; 00161 } 00162 00163 void lcd_layerSet(Layer *layer, char c) 00164 { 00165 int i; 00166 00167 LOCK_LCD; 00168 lcd_setAddr(layer, 0); 00169 for (i = 0; i < CONFIG_LCD_COLS * CONFIG_LCD_ROWS; i++) 00170 lcd_putCharUnlocked(c, layer); 00171 UNLOCK_LCD; 00172 } 00173 00174 00175 void lcd_clear(Layer *layer) 00176 { 00177 lcd_layerSet(layer, 0); 00178 } 00179 00180 00181 void lcd_clearLine(Layer *layer, int y) 00182 { 00183 int i; 00184 00185 LOCK_LCD; 00186 lcd_setAddr(layer, LCD_POS(0, y)); 00187 for (i = 0; i < CONFIG_LCD_COLS; i++) 00188 lcd_putCharUnlocked(0, layer); 00189 UNLOCK_LCD; 00190 } 00191 00192 00193 void lcd_moveCursor(lcdpos_t addr) 00194 { 00195 LOCK_LCD; 00196 lcd_moveTo(addr); 00197 UNLOCK_LCD; 00198 } 00199 00200 00201 char lcd_setCursor(char mode) 00202 { 00203 static const char cursor_cmd[3] = 00204 { 00205 LCD_CMD_CURSOR_OFF, LCD_CMD_CURSOR_BLOCK, LCD_CMD_CURSOR_LINE 00206 }; 00207 char oldmode = lcd_CursorStatus; 00208 00209 LOCK_LCD; 00210 lcd_CursorStatus = mode; 00211 lcd_setReg(cursor_cmd[(int)mode]); 00212 if (mode) 00213 lcd_moveCursor(lcd_CursorAddr); 00214 UNLOCK_LCD; 00215 00216 return oldmode; 00217 } 00218 00219 00220 int lcd_vprintf(Layer *layer, lcdpos_t addr, uint8_t mode, const char *format, va_list ap) 00221 { 00222 int len; 00223 00224 LOCK_LCD; 00225 00226 /* 00227 * Se il cursore era acceso, spegnilo durante 00228 * l'output per evitare che salti alla posizione 00229 * in cui si scrive. 00230 */ 00231 if (lcd_CursorStatus) 00232 lcd_setReg(LCD_CMD_CURSOR_OFF); 00233 00234 /* Spostamento del cursore */ 00235 lcd_setAddr(layer, addr); 00236 00237 if (mode & LCD_CENTER) 00238 { 00239 int pad; 00240 00241 /* 00242 * NOTE: calculating the string lenght BEFORE it gets 00243 * printf()-formatted. Real lenght may differ. 00244 */ 00245 pad = (CONFIG_LCD_COLS - strlen(format)) / 2; 00246 while (pad--) 00247 lcd_putCharUnlocked(' ', layer); 00248 } 00249 00250 len = _formatted_write(format, (void (*)(char, void *))lcd_putCharUnlocked, layer, ap); 00251 00252 if (mode & (LCD_FILL | LCD_CENTER)) 00253 while (layer->addr % CONFIG_LCD_COLS) 00254 lcd_putCharUnlocked(' ', layer); 00255 00256 /* 00257 * Riaccendi il cursore e riportalo alla 00258 * vecchia posizione 00259 */ 00260 if (lcd_CursorStatus) 00261 lcd_setCursor(lcd_CursorStatus); 00262 00263 UNLOCK_LCD; 00264 00265 return len; 00266 } 00267 00268 00269 int lcd_printf(Layer *layer, lcdpos_t addr, uint8_t mode, const char *format, ...) 00270 { 00271 int len; 00272 va_list ap; 00273 00274 va_start(ap, format); 00275 len = lcd_vprintf(layer, addr, mode, format, ap); 00276 va_end(ap); 00277 00278 return len; 00279 } 00280 00281 00288 static void lcd_enqueueLayer(Layer *layer, char pri) 00289 { 00290 Layer *l2; 00291 00292 /* Remove layer from whatever list it was in before */ 00293 REMOVE(layer); 00294 00295 layer->pri = pri; 00296 00297 /* 00298 * Search for the first layer whose priority 00299 * is less or equal to the layer we are adding. 00300 */ 00301 FOREACH_NODE(l2, &lcd_Layers) 00302 if (l2->pri <= pri) 00303 break; 00304 00305 /* Enqueue layer */ 00306 INSERT_BEFORE(layer, l2); 00307 } 00308 00309 Layer *lcd_newLayer(char pri) 00310 { 00311 Layer *layer; 00312 00313 LOCK_LCD; 00314 00315 if (LIST_EMPTY(&lcd_FreeLayers)) 00316 { 00317 UNLOCK_LCD; 00318 //ASSERT(false); 00319 return NULL; 00320 } 00321 00322 layer = (Layer *)LIST_HEAD(&lcd_FreeLayers); 00323 layer->addr = 0; 00324 memset(layer->buf, 0, CONFIG_LCD_ROWS * CONFIG_LCD_COLS); 00325 00326 lcd_enqueueLayer(layer, pri); 00327 00328 UNLOCK_LCD; 00329 return layer; 00330 } 00331 00337 static void lcd_refresh(void) 00338 { 00339 lcdpos_t addr; 00340 Layer *l; 00341 00342 for (addr = 0; addr < CONFIG_LCD_ROWS * CONFIG_LCD_COLS; ++addr) 00343 { 00344 FOREACH_NODE(l, &lcd_Layers) 00345 { 00346 //kprintf("%d %x %p\n", addr, l->buf[0], l); 00347 if (l->pri == LAYER_HIDDEN) 00348 break; 00349 00350 if (l->buf[addr]) 00351 { 00352 /* Refresh location */ 00353 lcd_putc(addr, l->buf[addr]); 00354 goto done; 00355 } 00356 } 00357 00358 /* Draw background */ 00359 lcd_putc(addr, ' '); 00360 done: 00361 ; 00362 } 00363 } 00364 00370 void lcd_setLayerDepth(Layer *layer, char pri) 00371 { 00372 if (pri != layer->pri) 00373 { 00374 LOCK_LCD; 00375 lcd_enqueueLayer(layer, pri); 00376 /* Vile but simple */ 00377 lcd_refresh(); 00378 UNLOCK_LCD; 00379 } 00380 } 00381 00382 void lcd_deleteLayer(Layer *layer) 00383 { 00384 LOCK_LCD; 00385 00386 /* We use lcd_refresh() instead. Much simpler than this mess, but slower. */ 00387 #if 0 00388 Layer *l2; 00389 lcdpos_t addr; 00390 00391 /* Repair damage on underlaying layers */ 00392 for (addr = 0; addr < CONFIG_LCD_ROWS * CONFIG_LCD_COLS; ++addr) 00393 { 00394 /* If location was covered by us */ 00395 if (layer->buf[addr]) 00396 { 00397 /* ...and it wasn't covered by others above us... */ 00398 for (l2 = layer->pred; l2->pred; l2 = l2->pred) 00399 if (l2->buf[addr]) 00400 /* can't just break here! */ 00401 goto not_visible; 00402 00403 /* ...scan underlaying layers to repair damage */ 00404 for (l2 = layer->succ; l2->succ; l2 = l2->succ) 00405 if (l2->buf[addr]) 00406 { 00407 /* Refresh character */ 00408 lcd_putc(addr, l2->buf[addr]); 00409 00410 /* No need to search on deeper layers */ 00411 break; 00412 } 00413 00414 not_visible: 00415 ; 00416 } 00417 } 00418 #endif 00419 00420 // Remove layer from lcd_Layers list. 00421 REMOVE(layer); 00422 00423 /* Put layer back into free list */ 00424 ADDHEAD(&lcd_FreeLayers, layer); 00425 00426 lcd_refresh(); 00427 00428 UNLOCK_LCD; 00429 } 00430 00431 00432 static void lcd_setDefLayer(Layer *layer) 00433 { 00434 lcd_DefLayer = layer; 00435 } 00436 00437 #include <cfg/debug.h> 00438 void lcd_init(void) 00439 { 00440 #if CONFIG_KERN 00441 sem_init(&lcd_semaphore); 00442 #endif 00443 00444 int i; 00445 00446 LIST_INIT(&lcd_Layers); 00447 LIST_INIT(&lcd_FreeLayers); 00448 for (i = 0; i < LCD_LAYERS; ++i) 00449 ADDHEAD(&lcd_FreeLayers, &lcd_LayersPool[i]); 00450 00451 lcd_setDefLayer(lcd_newLayer(0)); 00452 00453 lcd_hw_init(); 00454 00455 lcd_setCursor(0); 00456 } 00457 00458