graphlcd-base/glcddrivers/serdisp.c
author root@rika
Wed, 06 Feb 2008 17:32:55 +0000
changeset 4 df6a40031aa5
permissions -rw-r--r--
added graphlcd-base
     1 /*
     2  * GraphLCD driver library
     3  *
     4  * serdisp.h  -  include support for displays supported by serdisplib (if library is installed)
     5  *               http://serdisplib.sourceforge.net
     6  *
     7  * This file is released under the GNU General Public License. Refer
     8  * to the COPYING file distributed with this package.
     9  *
    10  * (c) 2003-2005 Wolfgang Astleitner <mrwastl AT users.sourceforge.net>
    11  */
    12 
    13 #include <stdio.h>
    14 #include <stdlib.h>
    15 #include <syslog.h>
    16 #include <dlfcn.h>
    17 
    18 #include "common.h"
    19 #include "config.h"
    20 #include "serdisp.h"
    21 
    22 #define SERDISP_VERSION(a,b) ((long)(((a) << 8) + (b)))
    23 #define SERDISP_VERSION_GET_MAJOR(_c)  ((int)( (_c) >> 8 ))
    24 #define SERDISP_VERSION_GET_MINOR(_c)  ((int)( (_c) & 0xFF ))
    25 
    26 // taken from serdisp_control.h
    27 #define FEATURE_CONTRAST  0x01
    28 #define FEATURE_REVERSE   0x02
    29 #define FEATURE_BACKLIGHT 0x03
    30 #define FEATURE_ROTATE    0x04
    31 
    32 #define SD_COL_BLACK      0xFF000000
    33 
    34 namespace GLCD
    35 {
    36 
    37 cDriverSerDisp::cDriverSerDisp(cDriverConfig * config)
    38 :   config(config)
    39 {
    40     oldConfig = new cDriverConfig(*config);
    41 
    42     dd = (void *) NULL;
    43 }
    44 
    45 cDriverSerDisp::~cDriverSerDisp(void)
    46 {
    47     delete oldConfig;
    48 }
    49 
    50 int cDriverSerDisp::Init(void)
    51 {
    52     char* errmsg; // error message returned by dlerror()
    53 
    54     std::string controller;
    55     std::string optionstring = "";
    56     std::string wiringstring;
    57 
    58 
    59     // dynamically load serdisplib using dlopen() & co.
    60 
    61     sdhnd = dlopen("libserdisp.so", RTLD_LAZY);
    62     if (!sdhnd) { // try /usr/local/lib
    63         sdhnd = dlopen("/usr/local/lib/libserdisp.so", RTLD_LAZY);
    64     }
    65 
    66     if (!sdhnd) { // serdisplib seems not to be installed
    67         syslog(LOG_ERR, "%s: error: unable to dynamically load library '%s'. Err: %s (cDriver::Init)\n",
    68         config->name.c_str(), "libserdisp.so", "not found");
    69         return -1;
    70     }
    71 
    72     dlerror(); // clear error code
    73 
    74     /* pre-init some flags, function pointers, ... */
    75     supports_options = 0;
    76     fg_colour = 1;
    77     bg_colour = -1;
    78 
    79     // get serdisp version
    80     fp_serdisp_getversioncode = (long int (*)()) dlsym(sdhnd, "serdisp_getversioncode");
    81 
    82     if (dlerror()) { // no serdisp_getversioncode() -> version of serdisplib is < 1.95
    83         syslog(LOG_DEBUG, "%s: INFO: symbol serdisp_getversioncode unknown: autodetecting pre 1.95 serdisplib version (cDriver::Init)\n",
    84         config->name.c_str());
    85 
    86         fp_SDCONN_open = (void*(*)(const char*)) dlsym(sdhnd, "SDCONN_open");
    87         if (dlerror()) { // no SDCONN_open() -> version of serdisplib is < 1.93
    88             serdisp_version = SERDISP_VERSION(1,92);
    89             syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version <= 1.92 (cDriver::Init)\n", config->name.c_str());
    90 
    91             fp_PP_open = (void*(*)(const char*))dlsym(sdhnd, "PP_open");
    92             if ( (errmsg = dlerror()) != NULL  ) { // should not happen
    93                 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
    94                     config->name.c_str(), "PP_open", errmsg);
    95                 return -1;
    96             }
    97             fp_PP_close = (void*(*)(void*))dlsym(sdhnd, "PP_close");
    98             if ( (errmsg = dlerror()) != NULL  ) { // should not happen
    99                 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   100                     config->name.c_str(), "PP_close", errmsg);
   101                 return -1;
   102             }
   103         } else {
   104             serdisp_version = SERDISP_VERSION(1,94);  // no serdisp_getversioncode, but SDCONN_open: 1.93 or 1.94
   105             syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version 1.93 or 1.94 (cDriver::Init)\n", config->name.c_str());
   106 
   107             fp_serdisp_quit = (void (*)(void*)) dlsym(sdhnd, "serdisp_quit");
   108             if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   109                 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   110                     config->name.c_str(), "serdisp_quit", errmsg);
   111                 return -1;
   112             }
   113         }
   114 
   115         fp_serdisp_setpixcol = (void (*)(void*, int, int, long int)) dlsym(sdhnd, "serdisp_setpixel");
   116         if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   117             syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   118                 config->name.c_str(), "serdisp_setpixel", errmsg);
   119             return -1;
   120         }
   121         fg_colour = 1; /* set foreground to 'pixel on' */
   122 
   123     } else {  // serdisp version >= 1.95
   124         serdisp_version = fp_serdisp_getversioncode();
   125         syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version %d.%d (cDriver::Init)\n",
   126             config->name.c_str(), SERDISP_VERSION_GET_MAJOR(serdisp_version), SERDISP_VERSION_GET_MINOR(serdisp_version));
   127 
   128 
   129         fp_SDCONN_open = (void*(*)(const char*)) dlsym(sdhnd, "SDCONN_open");
   130         if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   131             syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   132                 config->name.c_str(), "SDCONN_open", errmsg);
   133             return -1;
   134         }
   135         fp_serdisp_quit = (void (*)(void*)) dlsym(sdhnd, "serdisp_quit");
   136         if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   137             syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   138                 config->name.c_str(), "serdisp_quit", errmsg);
   139             return -1;
   140         }
   141         fp_serdisp_setpixcol = (void (*)(void*, int, int, long int)) dlsym(sdhnd, "serdisp_setcolour");
   142         if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   143             syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   144                 config->name.c_str(), "serdisp_setcolour", errmsg);
   145             return -1;
   146         }
   147         fg_colour = SD_COL_BLACK; /* set foreground colour to black */
   148 
   149         if (serdisp_version >= SERDISP_VERSION(1,96) ) {
   150             supports_options = 1;
   151 
   152             fp_serdisp_isoption = (int (*)(void*, const char*)) dlsym(sdhnd, "serdisp_isoption");
   153             if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   154                 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   155                     config->name.c_str(), "serdisp_isoption", errmsg);
   156                 return -1;
   157             }
   158             fp_serdisp_setoption = (void (*)(void*, const char*, long int)) dlsym(sdhnd, "serdisp_setoption");
   159             if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   160                 syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   161                     config->name.c_str(), "serdisp_setoption", errmsg);
   162                 return -1;
   163             }
   164         } /* >= 1.96 */
   165     }
   166 
   167     // load other symbols that will be required
   168     fp_serdisp_init = (void*(*)(void*, const char*, const char*)) dlsym(sdhnd, "serdisp_init");
   169     if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   170         syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   171             config->name.c_str(), "serdisp_init", errmsg);
   172         return -1;
   173     }
   174 
   175     fp_serdisp_rewrite = (void (*)(void*)) dlsym(sdhnd, "serdisp_rewrite");
   176     if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   177         syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   178             config->name.c_str(), "serdisp_rewrite", errmsg);
   179         return -1;
   180     }
   181 
   182     fp_serdisp_update = (void (*)(void*)) dlsym(sdhnd, "serdisp_update");
   183     if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   184         syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   185             config->name.c_str(), "serdisp_update", errmsg);
   186         return -1;
   187     }
   188 
   189     fp_serdisp_clearbuffer = (void (*)(void*)) dlsym(sdhnd, "serdisp_clearbuffer");
   190     if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   191         syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   192             config->name.c_str(), "serdisp_clearbuffer", errmsg);
   193         return -1;
   194     }
   195 
   196     fp_serdisp_feature = (int (*)(void*, int, int)) dlsym(sdhnd, "serdisp_feature");
   197     if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   198         syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   199             config->name.c_str(), "serdisp_feature", errmsg);
   200         return -1;
   201     }
   202 
   203     fp_serdisp_close = (void (*)(void*))dlsym(sdhnd, "serdisp_close");
   204     if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   205         syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   206             config->name.c_str(), "serdisp_close", errmsg);
   207         return -1;
   208     }
   209 
   210     fp_serdisp_getwidth = (int (*)(void*)) dlsym(sdhnd, "serdisp_getwidth");
   211     if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   212         syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   213             config->name.c_str(), "serdisp_getwidth", errmsg);
   214         return -1;
   215     }
   216 
   217     fp_serdisp_getheight = (int (*)(void*)) dlsym(sdhnd, "serdisp_getheight");
   218     if ( (errmsg = dlerror()) != NULL  ) { // should not happen
   219         syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n",
   220             config->name.c_str(), "serdisp_getheight", errmsg);
   221         return -1;
   222     }
   223 
   224     // done loading all required symbols
   225 
   226 
   227     // setting up the display
   228     width = 0;
   229     height = 0;
   230 
   231     for (unsigned int i = 0; i < config->options.size(); i++)
   232     {
   233         if (config->options[i].name == "Controller") {
   234             controller = config->options[i].value;
   235         } else if (config->options[i].name == "Options") {
   236             optionstring = config->options[i].value;
   237         } else if (config->options[i].name == "Wiring") {
   238             wiringstring = config->options[i].value;
   239         } else if (config->options[i].name == "FGColour") {
   240             fg_colour = strtoul(config->options[i].value.c_str(), (char **)NULL, 0);
   241             fg_colour |= 0xFF000000L;  /* force alpha to 0xFF */
   242         } else if (config->options[i].name == "BGColour") {
   243             bg_colour = strtoul(config->options[i].value.c_str(), (char **)NULL, 0);
   244             bg_colour |= 0xFF000000L;  /* force alpha to 0xFF */
   245         }
   246     }
   247 
   248     if (wiringstring.length()) {
   249         optionstring = "WIRING=" + wiringstring + ((optionstring != "") ? ";" + optionstring : "");
   250     }
   251 
   252     if (controller == "")
   253     {
   254         syslog(LOG_ERR, "%s error: no controller given!\n", config->name.c_str());
   255         return -1;
   256     }
   257 
   258 
   259     if (config->device == "")
   260     {
   261         // use DirectIO
   262 
   263         // neither device nor port is set
   264         if (config->port == 0)
   265             return -1;
   266 
   267         char temp[10];
   268         snprintf(temp, 8, "0x%x", config->port);
   269 
   270         if (serdisp_version < SERDISP_VERSION(1,93) ) {
   271             sdcd = fp_PP_open(temp);
   272         } else {
   273             sdcd = fp_SDCONN_open(temp);
   274         }
   275 
   276         if (sdcd == 0) {
   277             syslog(LOG_ERR, "%s: error: unable to open port 0x%x for display %s. (cDriver::Init)\n",
   278                 config->name.c_str(), config->port, controller.c_str());
   279             return -1;
   280         }
   281 
   282         uSleep(10);
   283     }
   284     else
   285     {
   286         // use ppdev
   287         if (serdisp_version < SERDISP_VERSION(1,93) ) {
   288             sdcd = fp_PP_open(config->device.c_str());
   289         } else {
   290             sdcd = fp_SDCONN_open(config->device.c_str());
   291         }
   292 
   293         if (sdcd == 0) {
   294             syslog(LOG_ERR, "%s: error: unable to open device %s for display %s. (cDriver::Init)\n",
   295                 config->name.c_str(), config->device.c_str(), controller.c_str());
   296             return -1;
   297         }
   298     }
   299 
   300     if (serdisp_version < SERDISP_VERSION(1,95) )
   301         dd = fp_serdisp_init(sdcd, controller.c_str(), "");
   302     else
   303         dd = fp_serdisp_init(sdcd, controller.c_str(), optionstring.c_str());
   304 
   305     if (!dd)
   306     {
   307         syslog(LOG_ERR, "%s: error: cannot open display %s. Err:%s (cDriver::Init)\n",
   308             config->name.c_str(), controller.c_str(), "no handle");
   309         return -1;
   310     }
   311 
   312     width = config->width;
   313     if (width <= 0)
   314         width = fp_serdisp_getwidth(dd);
   315     height = config->height;
   316     if (height <= 0)
   317         height = fp_serdisp_getheight(dd);
   318 
   319     if (serdisp_version < SERDISP_VERSION(1,96) ) {
   320         fp_serdisp_feature(dd, FEATURE_ROTATE, config->upsideDown);
   321         fp_serdisp_feature(dd, FEATURE_CONTRAST, config->contrast);
   322         fp_serdisp_feature(dd, FEATURE_BACKLIGHT, config->backlight);
   323         fp_serdisp_feature(dd, FEATURE_REVERSE, config->invert);
   324     } else {
   325         /* standard options */
   326         fp_serdisp_setoption(dd, "ROTATE", config->upsideDown);
   327         fp_serdisp_setoption(dd, "CONTRAST", config->contrast);
   328         fp_serdisp_setoption(dd, "BACKLIGHT", config->backlight);
   329         fp_serdisp_setoption(dd, "INVERT", config->invert);
   330 
   331         /* driver dependend options */
   332         for (unsigned int i = 0; i < config->options.size(); i++) {
   333             std::string optionname = config->options[i].name;
   334             if (optionname != "UpsideDown" && optionname != "Contrast" &&
   335                 optionname != "Backlight" && optionname != "Invert") {
   336 
   337                 if ( fp_serdisp_isoption(dd, optionname.c_str()) == 1 )  /* if == 1: option is existing AND r/w */
   338                     fp_serdisp_setoption(dd, optionname.c_str(), strtol(config->options[i].value.c_str(), NULL, 0));
   339             }
   340         }
   341 
   342     }
   343 
   344     *oldConfig = *config;
   345 
   346     // clear display
   347     Clear();
   348 
   349     syslog(LOG_INFO, "%s: SerDisp with %s initialized.\n", config->name.c_str(), controller.c_str());
   350     return 0;
   351 }
   352 
   353 int cDriverSerDisp::DeInit(void)
   354 {
   355     if (serdisp_version < SERDISP_VERSION(1,93) ) {
   356         fp_serdisp_close(dd);
   357         fp_PP_close(sdcd);
   358         sdcd = NULL;
   359     } else {
   360         //fp_serdisp_quit(dd);
   361         /* use serdisp_close instead of serdisp_quit so that showpic and showtext are usable together with serdisplib */
   362         fp_serdisp_close(dd);
   363     }
   364     (int) dlclose(sdhnd);
   365     sdhnd = NULL;
   366 
   367     return 0;
   368 }
   369 
   370 int cDriverSerDisp::CheckSetup()
   371 {
   372     bool update = false;
   373 
   374     if (config->device != oldConfig->device ||
   375         config->port != oldConfig->port ||
   376         config->width != oldConfig->width ||
   377         config->height != oldConfig->height)
   378     {
   379         DeInit();
   380         Init();
   381         return 0;
   382     }
   383 
   384     if (config->contrast != oldConfig->contrast)
   385     {
   386         fp_serdisp_feature(dd, FEATURE_CONTRAST, config->contrast);
   387         oldConfig->contrast = config->contrast;
   388         update = true;
   389     }
   390     if (config->backlight != oldConfig->backlight)
   391     {
   392         fp_serdisp_feature(dd, FEATURE_BACKLIGHT, config->backlight);
   393         oldConfig->backlight = config->backlight;
   394         update = true;
   395     }
   396     if (config->upsideDown != oldConfig->upsideDown)
   397     {
   398         fp_serdisp_feature(dd, FEATURE_ROTATE, config->upsideDown);
   399         oldConfig->upsideDown = config->upsideDown;
   400         update = true;
   401     }
   402     if (config->invert != oldConfig->invert)
   403     {
   404         fp_serdisp_feature(dd, FEATURE_REVERSE, config->invert);
   405         oldConfig->invert = config->invert;
   406         update = true;
   407     }
   408 
   409     /* driver dependend options */
   410     for (unsigned int i = 0; i < config->options.size(); i++) {
   411         std::string optionname = config->options[i].name;
   412         if (optionname != "UpsideDown" && optionname != "Contrast" &&
   413             optionname != "Backlight" && optionname != "Invert") {
   414 
   415             if ( fp_serdisp_isoption(dd, optionname.c_str()) == 1 )  /* if == 1: option is existing AND r/w */
   416                 fp_serdisp_setoption(dd, optionname.c_str(), strtol(config->options[i].value.c_str(), NULL, 0));
   417             oldConfig->options[i] = config->options[i];
   418             update = true;
   419         }
   420     }
   421 
   422 
   423     if (update)
   424         return 1;
   425     return 0;
   426 }
   427 
   428 void cDriverSerDisp::Clear(void)
   429 {
   430     if (bg_colour == -1)
   431         fp_serdisp_clearbuffer(dd);
   432     else {  /* if bg_colour is set, draw background 'by hand' */
   433         int x,y;
   434         for (y = 0; y < fp_serdisp_getheight(dd); y++)
   435             for (x = 0; x < fp_serdisp_getwidth(dd); x++)
   436                 fp_serdisp_setpixcol(dd, x, y, bg_colour);   /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */
   437     }
   438 }
   439 
   440 void cDriverSerDisp::Set8Pixels(int x, int y, unsigned char data) {
   441     int i, start, pixel;
   442 
   443     data = ReverseBits(data);
   444 
   445     start = (x >> 3) << 3;
   446 
   447     for (i = 0; i < 8; i++) {
   448         pixel = data & (1 << i);
   449         if (pixel)
   450             fp_serdisp_setpixcol(dd, start + i, y, fg_colour);   /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */
   451         else if (!pixel && bg_colour != -1)  /* if bg_colour is set: use it if pixel is not set */
   452             fp_serdisp_setpixcol(dd, start + i, y, bg_colour);   /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */
   453     }
   454 }
   455 
   456 void cDriverSerDisp::Refresh(bool refreshAll)
   457 {
   458     if (CheckSetup() == 1)
   459         refreshAll = true;
   460 
   461     if (refreshAll)
   462         fp_serdisp_rewrite(dd);
   463     else
   464         fp_serdisp_update(dd);
   465 }
   466 
   467 } // end of namespace