├── autogen.sh ├── Makefile.am ├── libsureelec.pc.in ├── .gitignore ├── configure.ac ├── README.md ├── examples ├── map_chars.c ├── sureelec_test2.c └── sureelec_test.c ├── LICENCE ├── libsureelec.h └── libsureelec.c /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | aclocal --install -I m4 && 4 | autoreconf --force --install && 5 | ./configure "$@" 6 | 7 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | LIBSUREELEC_LIBRARY_VERSION=0:1:0 2 | pkgconfigdir=$(libdir)/pkgconfig 3 | pkgconfig_DATA=libsureelec.pc 4 | lib_LTLIBRARIES=libsureelec.la 5 | libsureelec_la_SOURCES=libsureelec.c 6 | include_HEADERS=libsureelec.h 7 | libsureelec_la_LDFLAGS=-version-info $(LIBSUREELEC_LIBRARY_VERSION) 8 | 9 | -------------------------------------------------------------------------------- /libsureelec.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libsureelec 7 | Description: A library to drive Sure Electronics LCD displays. 8 | Version: @PACKAGE_VERSION@ 9 | Libs: -L${libdir} -lsureelec 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .lock-wafbuild 2 | .waf* 3 | build/ 4 | *.o 5 | autom4te.cache 6 | aclocal.m4 7 | compile 8 | configure 9 | depcomp 10 | install-sh 11 | missing 12 | config.log 13 | config.status 14 | Makefile 15 | Makefile.in 16 | config.h 17 | config.h.in 18 | stamp-h1 19 | config.guess 20 | ltmain.sh 21 | m4/ 22 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([libsureelec],[0.1.0],[michael@no-surprises.co.uk],[libsureelec],[https://github.com/mgdm/libsureelec]) 2 | AC_CONFIG_MACRO_DIR([m4]) 3 | AM_INIT_AUTOMAKE([1.9 foreign]) 4 | LT_PREREQ([2.2]) 5 | LT_INIT 6 | 7 | AC_PROG_CC 8 | AC_PROG_INSTALL 9 | 10 | AC_CONFIG_FILES([Makefile libsureelec.pc]) 11 | 12 | AC_OUTPUT 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libsureelec 2 | 3 | This is a library intended to drive the Sure Electronics series of LCD 4 | displays. Currently it will successfully drive a DE-LD023 device, but I suspect 5 | it should work for the DE-LD021. too. It ought to detect the available device 6 | features. 7 | 8 | It uses waf as the build system. To install: 9 | 10 | ./waf configure 11 | ./waf build 12 | ./waf install # as root, probably 13 | 14 | There is an example program in sureelec_test.c which prints some system information 15 | to the device. This will be compiled as build/sureelec_test. To run, use a 16 | command like: 17 | 18 | ./build/sureelec_test /dev/ttyUSB0 19 | 20 | There's another example in sureelec_test2.c which accepts input using a readline 21 | interface, which will then be sent straight to the device. It is run similarly: 22 | 23 | ./build/sureelec_test2 /dev/ttyUSB0 -------------------------------------------------------------------------------- /examples/map_chars.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "libsureelec.h" 5 | 6 | libsureelec_ctx *display; 7 | 8 | int main(int argc, char **argv) { 9 | int page, line, character; 10 | unsigned char base; 11 | char chars[20]; 12 | 13 | if (argc < 2) { 14 | fprintf(stderr, "Need device name\n"); 15 | return -1; 16 | } 17 | 18 | display = libsureelec_create(argv[1], 0); 19 | 20 | if (display == NULL) { 21 | fprintf(stderr, "Failed to open display\n"); 22 | } 23 | 24 | libsureelec_set_contrast(display, 1); 25 | libsureelec_set_brightness(display, 255); 26 | 27 | base = 32; 28 | for (page = 1; page < 5; page++) { 29 | printf("Page %d - characters %u to %u\n", page, base, base + 40); 30 | libsureelec_clear_display(display); 31 | 32 | for (line = 1; line <= 4; line++) { 33 | for (character = 0; character < 20; character++) { 34 | chars[character] = base; 35 | base++; 36 | } 37 | 38 | libsureelec_display_line(display, line, chars); 39 | } 40 | 41 | sleep(5); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/sureelec_test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "libsureelec.h" 5 | 6 | libsureelec_ctx *ctx; 7 | 8 | void print_usage(char *bin_name) { 9 | printf("Usage: %s DEVICE\n", bin_name); 10 | } 11 | 12 | int main(int argc, char **argv) { 13 | if (argc < 2) { 14 | print_usage(argv[0]); 15 | return -1; 16 | } 17 | 18 | ctx = libsureelec_create(argv[1], 0); 19 | 20 | if (ctx == NULL) { 21 | printf("Failed to connect to device %s\n", argv[1]); 22 | return -1; 23 | } 24 | 25 | libsureelec_set_contrast(ctx, 1); 26 | libsureelec_set_brightness(ctx, 254); 27 | libsureelec_clear_display(ctx); 28 | 29 | int current = 0; 30 | int scroll = 0; 31 | char buf[20]; 32 | while (1) { 33 | char *input = readline("> "); 34 | size_t len; 35 | if (!input) { 36 | break; 37 | } 38 | 39 | memset(buf, ' ', 20); 40 | len = strlen(input); 41 | memcpy(buf, input, (len > 20) ? 20 : len); 42 | 43 | if (scroll == 1) { 44 | libsureelec_scroll_vert(ctx, 0, LIBSUREELEC_UP, 1, 0); 45 | } 46 | 47 | libsureelec_display_line(ctx, current + 1, buf); 48 | 49 | current++; 50 | 51 | if (current == 4) { 52 | scroll = 1; 53 | current = 3; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Michael Maclean 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /libsureelec.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSUREELEC_H 2 | #define LIBSUREELEC_H 3 | 4 | #if defined(__GNUC__) && __GNUC__ >= 4 5 | # define LIBSUREELEC_EXPORT __attribute__ ((visibility("default"))) 6 | #else 7 | # define LIBSUREELEC_EXPORT 8 | #endif 9 | 10 | #ifdef __APPLE__ 11 | #include 12 | #include 13 | /* Mac OS X don't have strndup even if _GNU_SOURCE is defined */ 14 | char *strndup (const char *s, size_t n) 15 | { 16 | size_t len = strlen (s); 17 | char *ret; 18 | 19 | if (len <= n) 20 | return strdup (s); 21 | 22 | ret = malloc(n + 1); 23 | strncpy(ret, s, n); 24 | ret[n] = '\0'; 25 | return ret; 26 | } 27 | #endif 28 | 29 | typedef struct libsureelec_device_info { 30 | int width; 31 | int height; 32 | int rom_size; 33 | int has_rx8025; 34 | int has_light_sensor; 35 | int has_thermal_sensor; 36 | } libsureelec_device_info; 37 | 38 | typedef struct libsureelec_ctx { 39 | int fd; /* Serial port file handle */ 40 | libsureelec_device_info device_info; 41 | char *framebuffer; 42 | int framebuffer_size; 43 | int display_state; 44 | int contrast; 45 | int brightness; 46 | } libsureelec_ctx; 47 | 48 | #define LIBSUREELEC_TEMP_OUT_OF_RANGE -999 49 | #define LIBSUREELEC_NO_TEMP_SENSOR -998 50 | 51 | #define LIBSUREELEC_UP 0 52 | #define LIBSUREELEC_DOWN 1 53 | #define LIBSUREELEC_LEFT 2 54 | #define LIBSUREELEC_RIGHT 3 55 | 56 | LIBSUREELEC_EXPORT libsureelec_ctx* libsureelec_create(const char *device, int debug); 57 | LIBSUREELEC_EXPORT void libsureelec_destroy(libsureelec_ctx *ctx); 58 | LIBSUREELEC_EXPORT void libsureelec_clear_display(libsureelec_ctx *ctx); 59 | LIBSUREELEC_EXPORT int libsureelec_display_line(libsureelec_ctx *ctx, int line, const char *data); 60 | LIBSUREELEC_EXPORT int libsureelec_get_device_info(libsureelec_ctx *ctx, libsureelec_device_info *device_info); 61 | LIBSUREELEC_EXPORT void libsureelec_toggle_display(libsureelec_ctx *ctx); 62 | LIBSUREELEC_EXPORT void libsureelec_set_contrast(libsureelec_ctx *ctx, int contrast); 63 | LIBSUREELEC_EXPORT void libsureelec_set_brightness(libsureelec_ctx *ctx, int brightness); 64 | LIBSUREELEC_EXPORT int libsureelec_get_temperature(libsureelec_ctx *ctx); 65 | LIBSUREELEC_EXPORT int libsureelec_get_contrast(libsureelec_ctx *ctx); 66 | LIBSUREELEC_EXPORT int libsureelec_get_brightness(libsureelec_ctx *ctx); 67 | LIBSUREELEC_EXPORT void libsureelec_refresh(libsureelec_ctx *ctx); 68 | LIBSUREELEC_EXPORT void libsureelec_scroll_vert(libsureelec_ctx *ctx, int line, int direction, int distance, int wrap); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /examples/sureelec_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifdef __linux__ 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | #include "libsureelec.h" 13 | 14 | 15 | void print_usage(const char *bin_name) { 16 | printf("Usage: %s DEVICE DAEMON\n", bin_name); 17 | printf("If DAEMON is the character 1, the program will go into the background.\n"); 18 | } 19 | 20 | char *print_uptime(long up_secs, char *retval) { 21 | long days, hours, mins, secs; 22 | if (retval == NULL) { 23 | retval = malloc(20 * sizeof(char)); 24 | } 25 | 26 | mins = up_secs / 60; 27 | hours = mins / 60; 28 | hours = hours % 24; 29 | 30 | days = up_secs / (60 * 60 * 24); 31 | 32 | mins = (int) up_secs / 60; 33 | hours = mins / 60; 34 | hours = hours % 24; 35 | mins = mins % 60; 36 | secs = up_secs % 60; 37 | 38 | snprintf(retval, 20, "Up %ldd, %02ld:%02ld:%02ld", days, hours, mins, secs); 39 | return retval; 40 | } 41 | 42 | int main(int argc, char **argv) { 43 | libsureelec_ctx *ctx; 44 | int hostname_len; 45 | 46 | #ifdef __linux__ 47 | struct sysinfo sys_info; 48 | #endif 49 | 50 | char hostname[20]; 51 | char *string, *uptime_string, *time_string; 52 | 53 | if (argc < 2) { 54 | print_usage(argv[0]); 55 | return -1; 56 | } 57 | 58 | ctx = libsureelec_create(argv[1], 0); 59 | 60 | if (ctx == NULL) { 61 | printf("Failed to initialize context\n"); 62 | return -1; 63 | } 64 | 65 | if (argc > 2 && *argv[2] == '1') { 66 | if (daemon(0, 0) == -1) { 67 | printf("Daemonizing failed.\n"); 68 | return -1; 69 | } 70 | } 71 | 72 | libsureelec_set_contrast(ctx, 1); 73 | libsureelec_set_brightness(ctx, 254); 74 | libsureelec_clear_display(ctx); 75 | 76 | gethostname(hostname, 11); 77 | hostname_len = strlen(hostname); 78 | if (hostname_len > 11) { 79 | hostname_len = 11; 80 | } 81 | 82 | string = (char *) calloc(20, sizeof(char)); 83 | uptime_string = (char *) calloc(20, sizeof(char)); 84 | time_string = (char *) calloc(20, sizeof(char)); 85 | time_t current_time; 86 | struct tm *tmp; 87 | 88 | while(1) { 89 | long foo = libsureelec_get_temperature(ctx); 90 | memset(time_string, ' ', 20); 91 | current_time = time(NULL); 92 | tmp = localtime(¤t_time); 93 | strftime(time_string + 12, 9, "%H:%M:%S", tmp); 94 | memcpy(time_string, hostname, hostname_len); 95 | memcpy(time_string + hostname_len, " ", 11 - hostname_len); 96 | libsureelec_display_line(ctx, 1, time_string); 97 | 98 | snprintf(string, 20, "Temp is %ld deg C", foo); 99 | libsureelec_display_line(ctx, 2, string); 100 | 101 | #ifdef __linux__ 102 | sysinfo(&sys_info); 103 | uptime_string = print_uptime(sys_info.uptime, uptime_string); 104 | libsureelec_display_line(ctx, 3, uptime_string); 105 | 106 | snprintf(string, 20, "Load %.2lf %.2lf %.2lf", 107 | sys_info.loads[0] / 65536.0, 108 | sys_info.loads[1] / 65536.0, 109 | sys_info.loads[2] / 65536.0); 110 | libsureelec_display_line(ctx, 4, string); 111 | #endif 112 | 113 | usleep(50000); 114 | } 115 | 116 | libsureelec_destroy(ctx); 117 | } 118 | -------------------------------------------------------------------------------- /libsureelec.c: -------------------------------------------------------------------------------- 1 | /* libsureelec.c 2 | * Driver for SureElec LCD modules 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "libsureelec.h" 17 | 18 | static int libsureelec_debug_mode = 0; 19 | 20 | static void libsureelec_log(const char *format, ...) { 21 | if (libsureelec_debug_mode) { 22 | va_list ap; 23 | va_start(ap, format); /* measure the required size (the number of elements of format) */ 24 | 25 | fprintf( stderr, "libsureelec: " ); 26 | vfprintf( stderr, format, ap ); 27 | fprintf( stderr, "\n" ); 28 | } 29 | } 30 | 31 | static int libsureelec_read(libsureelec_ctx *ctx, void *buf, size_t count) { 32 | fd_set rfds; 33 | struct timeval tv; 34 | int read_count; 35 | 36 | /* Watch fd to see when it has input. */ 37 | FD_ZERO(&rfds); 38 | FD_SET(ctx->fd, &rfds); 39 | 40 | read_count = 0; 41 | while (read_count < count) { 42 | int retval; 43 | 44 | /* 45 | * For compatibility, better to reset the timeout delay (may 46 | * be modified in select() call). 47 | */ 48 | tv.tv_sec = 1; /* seconds */ 49 | tv.tv_usec = 0; /* microseconds */ 50 | 51 | retval = select(ctx->fd + 1, &rfds, NULL, NULL, &tv); 52 | if (retval) { 53 | int read_result = read(ctx->fd, ((char *)buf) + read_count, count - read_count); 54 | if (read_result < 0) { 55 | libsureelec_log("Got no response: %s", strerror(errno)); 56 | return -1; 57 | } else { 58 | read_count += read_result; 59 | libsureelec_log("Got %d bytes, up to %d", read_result, read_count); 60 | } 61 | } else { 62 | libsureelec_log("No answer from device"); 63 | return -1; 64 | } 65 | } 66 | return read_count; 67 | } 68 | 69 | static int libsureelec_write(libsureelec_ctx *ctx, const char *seq, int count) { 70 | int written, written_count = 0; 71 | while (written_count < count) { 72 | written = write(ctx->fd, seq, count - written_count); 73 | if (written == -1) { 74 | libsureelec_log("Cannot write to port: %s", strerror(errno)); 75 | return -1; 76 | } 77 | written_count += written; 78 | } 79 | 80 | struct timespec ts; 81 | ts.tv_sec = 0; 82 | ts.tv_nsec = 25000000; 83 | nanosleep(&ts, NULL); 84 | return written_count; 85 | } 86 | 87 | static int libsureelec_write_char(libsureelec_ctx *ctx, const char seq) { 88 | int written = 0; 89 | 90 | written = write(ctx->fd, &seq, 1); 91 | if (written == -1) { 92 | libsureelec_log("Cannot write to port: %s", strerror(errno)); 93 | return -1; 94 | } 95 | 96 | return 1; 97 | } 98 | 99 | LIBSUREELEC_EXPORT libsureelec_ctx* libsureelec_create(const char *device, int debug) { 100 | char init_seq[5] = {'\xFE', 'S', 'u', 'r', 'e'}; 101 | libsureelec_ctx *ctx = (libsureelec_ctx *) calloc(1, sizeof(libsureelec_ctx)); 102 | ctx->fd = -1; 103 | struct termios port_config; 104 | 105 | if (debug > 0) { 106 | libsureelec_debug_mode = 1; 107 | } else { 108 | libsureelec_debug_mode = 0; 109 | } 110 | 111 | ctx->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); 112 | if (ctx->fd == -1) { 113 | libsureelec_log("Failed to open port %s: ", device, strerror(errno)); 114 | return NULL; 115 | } 116 | 117 | if (!isatty(ctx->fd)) { 118 | libsureelec_log("Device %s is not a TTY", device); 119 | return NULL; 120 | } 121 | 122 | tcgetattr(ctx->fd, &port_config); 123 | 124 | port_config.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP 125 | | INLCR | IGNCR | ICRNL | IXON); 126 | port_config.c_oflag &= ~OPOST; 127 | // port_config.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 128 | port_config.c_cflag &= ~(CSIZE | PARENB | CRTSCTS | CSTOPB); 129 | port_config.c_cflag |= CS8 | CREAD | CLOCAL; 130 | port_config.c_cc[VMIN] = 1; 131 | port_config.c_cc[VTIME] = 0; 132 | 133 | port_config.c_lflag = 0; 134 | 135 | if(cfsetispeed(&port_config, B9600) < 0 || cfsetospeed(&port_config, B9600) < 0) { 136 | libsureelec_log("Failed to set port speed"); 137 | return NULL; 138 | } 139 | 140 | if(tcsetattr(ctx->fd, TCSANOW, &port_config) < 0) { 141 | libsureelec_log("Failed to apply port configuration to device %s", device); 142 | return NULL; 143 | } 144 | 145 | /* LCD is on */ 146 | ctx->display_state = 1; 147 | 148 | /* Send init sequence */ 149 | libsureelec_log("Sending init sequence to %s", device); 150 | libsureelec_write(ctx, init_seq, sizeof(init_seq)); 151 | 152 | libsureelec_get_device_info(ctx, &ctx->device_info); 153 | /* Set up framebuffer */ 154 | ctx->framebuffer_size = ctx->device_info.width * ctx->device_info.height; 155 | ctx->framebuffer = malloc(ctx->framebuffer_size * sizeof(char)); 156 | libsureelec_log("Framebuffer size is %d chars\n", ctx->framebuffer_size); 157 | 158 | memset(ctx->framebuffer, ' ', ctx->framebuffer_size); 159 | return ctx; 160 | } 161 | 162 | LIBSUREELEC_EXPORT void libsureelec_destroy(libsureelec_ctx *ctx) { 163 | if (ctx->fd != -1) { 164 | close(ctx->fd); 165 | } 166 | 167 | if (ctx->framebuffer != NULL) { 168 | free(ctx->framebuffer); 169 | } 170 | 171 | free(ctx); 172 | } 173 | 174 | LIBSUREELEC_EXPORT void libsureelec_clear_display(libsureelec_ctx *ctx) { 175 | int line; 176 | memset(ctx->framebuffer, ' ', ctx->framebuffer_size); 177 | 178 | for (line = 0; line < ctx->device_info.height; line++) { 179 | libsureelec_display_line(ctx, line + 1, ctx->framebuffer + (ctx->device_info.width * line)); 180 | } 181 | } 182 | 183 | LIBSUREELEC_EXPORT int libsureelec_display_line(libsureelec_ctx *ctx, int line, const char *data) { 184 | 185 | int data_size; 186 | char cmd[4] = {'\xFE', '\x47', '\x01', 0}; 187 | char *dest; 188 | 189 | if (line < 1 || line > ctx->device_info.height) { 190 | return -1; 191 | } 192 | 193 | if (data == NULL) { 194 | /* We're just refreshing the display, so write what's in the framebuffer */ 195 | dest = &ctx->framebuffer[(line - 1) * ctx->device_info.width]; 196 | } else { 197 | data_size = strlen(data); 198 | if (data_size > ctx->device_info.width) { 199 | data_size = ctx->device_info.width; 200 | } 201 | 202 | dest = ctx->framebuffer + (ctx->device_info.width * (line - 1)); 203 | memset(dest, ' ', ctx->device_info.width); 204 | dest = memcpy(dest, data, data_size); 205 | } 206 | 207 | cmd[3] = line; 208 | libsureelec_write(ctx, cmd, sizeof(cmd)); 209 | libsureelec_write(ctx, dest, ctx->device_info.width); 210 | return 0; 211 | } 212 | 213 | LIBSUREELEC_EXPORT int libsureelec_get_device_info(libsureelec_ctx *ctx, libsureelec_device_info *device_info) { 214 | const char cmd[2] = { '\xFE', '\x76' }; 215 | char buf[11], temp[4]; 216 | char *end_ptr; 217 | 218 | libsureelec_write(ctx, cmd, sizeof(cmd)); 219 | libsureelec_read(ctx, &buf, sizeof(buf)); 220 | 221 | errno = 0; 222 | memset(temp, '\0', sizeof(temp)); 223 | memcpy(temp, buf, 2); 224 | device_info->width = strtol(temp, &end_ptr, 10); 225 | if (errno != 0 || *end_ptr != 0 || end_ptr == (char *) buf) { 226 | libsureelec_log("Failed to get device info"); 227 | return -1; 228 | } 229 | 230 | errno = 0; 231 | memset(temp, '\0', sizeof(temp)); 232 | memcpy(temp, buf + 2, 2); 233 | device_info->height = strtol(temp, &end_ptr, 10); 234 | if (errno != 0 || *end_ptr != 0 || end_ptr == (char *) buf) { 235 | libsureelec_log("Failed to get device info"); 236 | return -1; 237 | } 238 | 239 | if (buf[4] == 1) { 240 | device_info->has_rx8025 = 1; 241 | } else { 242 | device_info->has_rx8025 = 0; 243 | } 244 | libsureelec_log("ROM size: %d", buf[5] - 48); 245 | device_info->rom_size = 2 << (buf[5] - 49); 246 | 247 | if (buf[6] == '1') { 248 | device_info->has_light_sensor = 1; 249 | } else { 250 | device_info->has_light_sensor = 0; 251 | } 252 | 253 | if (buf[7] == '1' || buf[7] == '2') { 254 | device_info->has_thermal_sensor = 1; 255 | } else { 256 | device_info->has_thermal_sensor = 0; 257 | } 258 | 259 | libsureelec_log("Found %dx%d device with %dKbit ROM", device_info->width, device_info->height, device_info->rom_size); 260 | if (device_info->has_thermal_sensor) { 261 | libsureelec_log("with thermal sensor"); 262 | } 263 | 264 | if (device_info->has_light_sensor) { 265 | libsureelec_log("with light sensor"); 266 | } 267 | 268 | return 0; 269 | } 270 | 271 | LIBSUREELEC_EXPORT void libsureelec_toggle_display(libsureelec_ctx *ctx) { 272 | const char cmd[2] = { '\xFE', '\x64' }; 273 | libsureelec_write(ctx, cmd, sizeof(cmd)); 274 | } 275 | 276 | LIBSUREELEC_EXPORT void libsureelec_set_contrast(libsureelec_ctx *ctx, int contrast) { 277 | char cmd[3] = { '\xFE', '\x50', 0 }; 278 | if (contrast > 255) { 279 | contrast = 255; 280 | } else if (contrast < 1) { 281 | contrast = 1; 282 | } 283 | 284 | cmd[2] = contrast; 285 | libsureelec_write(ctx, cmd, sizeof(cmd)); 286 | ctx->contrast = contrast; 287 | } 288 | 289 | LIBSUREELEC_EXPORT void libsureelec_set_brightness(libsureelec_ctx *ctx, int brightness) { 290 | char cmd[3] = { '\xFE', '\x98', 0 }; 291 | if (brightness > 255) { 292 | brightness = 255; 293 | } else if (brightness < 1) { 294 | brightness = 1; 295 | } 296 | 297 | cmd[2] = brightness; 298 | libsureelec_write(ctx, cmd, sizeof(cmd)); 299 | ctx->brightness = brightness; 300 | } 301 | 302 | LIBSUREELEC_EXPORT int libsureelec_get_temperature(libsureelec_ctx *ctx) { 303 | const char cmd[2] = { '\xFE', '\x77' }; 304 | char buf[5]; 305 | char *p; 306 | int retval; 307 | 308 | if (ctx->device_info.has_thermal_sensor != 1) { 309 | return LIBSUREELEC_NO_TEMP_SENSOR; 310 | } 311 | 312 | memset(buf, ' ', sizeof(buf)); 313 | libsureelec_write(ctx, cmd, sizeof(cmd)); 314 | libsureelec_read(ctx, buf, 5); 315 | 316 | if (buf[0] == 'T') { 317 | return LIBSUREELEC_TEMP_OUT_OF_RANGE; 318 | } 319 | 320 | if (buf[4] == 'C') { 321 | libsureelec_log("Temperature is in degrees C."); 322 | } else { 323 | libsureelec_log("Temperature is in degrees F."); 324 | } 325 | 326 | buf[3] = '\0'; 327 | errno = 0; 328 | retval = strtol(buf, &p, 10); 329 | if (errno != 0 || *p != 0 || p == (char *) buf) { 330 | libsureelec_log("Failed to convert temperature"); 331 | return LIBSUREELEC_TEMP_OUT_OF_RANGE; 332 | } 333 | 334 | return(retval); 335 | } 336 | 337 | LIBSUREELEC_EXPORT int libsureelec_get_contrast(libsureelec_ctx *ctx) { 338 | const char cmd[2] = { '\xFE', '\x63' }; 339 | char buf[5]; 340 | char *p; 341 | int retval; 342 | 343 | memset(buf, ' ', sizeof(buf)); 344 | libsureelec_write(ctx, cmd, sizeof(cmd)); 345 | libsureelec_read(ctx, buf, 5); 346 | 347 | libsureelec_log("Contrast buffer: %s", buf); 348 | 349 | errno = 0; 350 | retval = strtol(buf + 2, &p, 10); 351 | if (errno != 0 || *p != 0 || p == (char *) buf) { 352 | libsureelec_log("Failed to convert contrast"); 353 | return -1; 354 | } 355 | 356 | return(retval); 357 | } 358 | 359 | LIBSUREELEC_EXPORT int libsureelec_get_brightness(libsureelec_ctx *ctx) { 360 | const char cmd[2] = { '\xFE', '\x62' }; 361 | char buf[7]; 362 | char *p; 363 | int retval; 364 | 365 | memset(buf, ' ', sizeof(buf)); 366 | libsureelec_write(ctx, cmd, sizeof(cmd)); 367 | libsureelec_read(ctx, buf, 7); 368 | 369 | libsureelec_log("Brightness buffer: %s", buf); 370 | 371 | errno = 0; 372 | retval = strtol(buf + 4, &p, 10); 373 | if (errno != 0 || *p != 0 || p == (char *) buf) { 374 | libsureelec_log("Failed to convert brightness"); 375 | return -1; 376 | } 377 | 378 | return(retval); 379 | } 380 | 381 | LIBSUREELEC_EXPORT void libsureelec_refresh(libsureelec_ctx *ctx) { 382 | int i; 383 | for (i = 1; i <= ctx->device_info.height; i++) { 384 | libsureelec_display_line(ctx, i, NULL); 385 | } 386 | } 387 | 388 | LIBSUREELEC_EXPORT void libsureelec_scroll_vert(libsureelec_ctx *ctx, int line, int direction, int distance, int wrap) { 389 | switch (direction) { 390 | case LIBSUREELEC_UP: 391 | if (distance > 4) { 392 | distance = 4; 393 | } 394 | char *src = &ctx->framebuffer[(distance) * ctx->device_info.width]; 395 | memmove(ctx->framebuffer, src, (ctx->device_info.height - distance) * ctx->device_info.width); 396 | libsureelec_refresh(ctx); 397 | break; 398 | case LIBSUREELEC_DOWN: 399 | if (distance > 4) { 400 | distance = 4; 401 | } 402 | char *dest = &ctx->framebuffer[(distance) * ctx->device_info.width]; 403 | memmove(dest, ctx->framebuffer, (ctx->device_info.height - distance) * ctx->device_info.width); 404 | libsureelec_refresh(ctx); 405 | break; 406 | } 407 | } 408 | --------------------------------------------------------------------------------