From: Andrey Chilikin Date: Sun, 23 Nov 2014 18:29:20 +0000 (+0000) Subject: Initial commit X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=1fdfc857e907236c3df320de49e7d29a4f6bfe24;p=corbenik%2Fbdfe.git Initial commit --- diff --git a/LICENSE b/LICENSE index 6f37840..da69a0e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014, Andrey Chilikin +Copyright (c) 2014, Andrey Chilikin https://github.com/achilikin All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b40e49d --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +CXX = g++ +CFLAGS = -Wall -Werror +CFLAGS += -g +#CFLAGS += -O3 +LIBS = + +CORE = bdfe +OBJS = main.o ossd_i2c.o pi2c.o bdf.o rterm.o +HFILES = Makefile pi2c.h ossd_i2c.h rterm.h font88.h font816.h +CFILES = ossd_i2c.c bdf.c rterm.c main.c + +all: $(CORE) + +$(CORE): $(OBJS) $(CFILES) $(HFILES) + $(CXX) $(CFLAGS) -o $(CORE) $(OBJS) $(LIBS) + +clean: + rm -f $(CORE) + rm -f *.o + +%.o: %.c $(HFILES) + $(CXX) -c $(CFLAGS) $< -o $@ + + diff --git a/README.md b/README.md index 93f3222..5768f9e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,67 @@ bdfe -==== +---- + +**bdfe** might sound like crazy alphabet mixture but actually it is short name for [Bitmap Distribution Format Exporter](http://en.wikipedia.org/wiki/Glyph_Bitmap_Distribution_Format "bdf wiki") - utility which can extract subsets or export all glyphs from .bdf font files. + +Why? I've decided to add a small oled display to my temperature/humidity station based on modded [MMR-70 FM Music Transmitter](https://github.com/achilikin/mmr70mod "MMR70 mod") but could not find any free 8x8 and 8x16 fonts in C format. There are tons of free fonts in bdf format because for years bdf has been used by UNIX X Windows. Converters available as well, but I needed very specific converter which would create fonts for SSD1306 based OLED screens. + +So here it is - bdf font converter which can export glyphs from bdf and present them as array of bytes. It also can rotate 8x8 and 8x16 glyphs CCW so they can be used on displays with SSD1306 controller. + +I'm running it with my Raspberry Pi (same RPi I use to program MMR70 ATmega) but it should run on any other Linux machine as well. + + +Command line options +-------------------- + +bdfe understands a few command line options, in plain English words or, for lazy people like me, in short single letter option which happened to be the first letter of the corresponding word. + +``` +bdfe [options] + options are: + header: print file header + verbose: add extra info to the header + line: one line per glyph + subset a-b: subset of glyphs to convert a to b, default 32-126 + all: print all glyphs, not just 32-126 + native: do not adjust font height 8 pixels + ascender H: add extra ascender of H pixels per glyph + rotate: rotate glyphs' bitmaps CCW + display A: show converted font on SSD1306 compatible display + using I2C bus 1, hexadecimal address A (default 3C) + updown: display orientation is upside down +``` + +So ```bdfe header verbose line all native file.bdf``` and ```bdfe -h -v -l -a -n file.bdf``` are the same. + +There is no output file option - just redirect bdfe output to a file: ```bdfe -h -v -l -a -n font.bdf > font.h``` + +OLED display is not needed for conversion but useful to have as you can immediately see if font is suitable with under-/over-line or inverse attributes. By default I2C slave address x3C is used, on my display this address is selected by connecting DC to GND, connecting it to Vcc switches address to x3D. If you do not know address of your SSD1306 display use ```i2cdetect + +Source code +----------- + +Source code can be split to standalone modules which might be used in other projects separately: + +```bdfe.h, bdfe.c``` - BDF file parser, single (quite big) function. +```rterm.h, rterm.c``` - raw terminal input, kind of old nice getch(). +```ossd_i2c.h, ossd_i2c.c``` - OLED SSD1306 controller interface using I2C bus. Simple text mode only with direct access to SSD1306 registers, no shadow graphics buffer - memory on MMR70 ATmega32 MCU is a precious resource and anyway MMR70 will update screen only once in a while. Currently only fonts 8 and 16 bits high are supported. Underline, overline and inverse attributes can be used. +```pi2c.h, pi2c.c``` - basic I2C wrapper for i2c-dev library, allows to write to SSD1306 connected to I2C bus. +```font8x8.h, font8x16.h``` - converted bdf files. +```main.c``` - puts all of above together and does the work. + +Examples +-------- +![bdfe screen](http://achilikin.com/github/bdfe-01.png) +Converting 7x8 font... Use ```bdfe ... | less``` to scroll exported font up and down. + +![8x8 screen](http://achilikin.com/github/font8x8.gif) ![8x16 screen](http://achilikin.com/github/font8x16.gif) ![mmr70 screen](http://achilikin.com/github/mmr70.png) + +OLED screen with 8x8 and 8x16 fonts converted and screen connected to a modded version of [MMR-70](https://github.com/achilikin/mmr70mod") with current temperature and humidity reading. +For 8x16 font command option ```ascender 1``` was used to lower glyphs 1 pixel down. + + +Licence +------- +BSD + -BDF Exporter - converts fonts from BDF files to C structures diff --git a/bdf.c b/bdf.c new file mode 100644 index 0000000..7a9d800 --- /dev/null +++ b/bdf.c @@ -0,0 +1,308 @@ +/* BSD License + Copyright (c) 2014 Andrey Chilikin https://github.com/achilikin + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + Basic BDF Exporter - converts BDF files to C structures. + Only 8 bits wide fonts are supported. +*/ +#include +#include +#include +#include +#include + +#include "bdf.h" + +// check if 'buf' starts with 'key' and store pointer to the argument +static char *key_arg(char *buf, const char *key, char **arg) +{ + char *end; + size_t len = strlen(key); + + if (strncmp(buf, key, len) == 0) { + end = buf + len; + if (*end > ' ') + return NULL; + if (arg == NULL) + return buf; + for(; *end <= ' ' && *end != '\0'; end++); + *arg = end; + return buf; + } + + return NULL; +} + +// rotate glyph bitmap CCW +static uint32_t rotate_glyph(const uint8_t *glyph, unsigned gw, int gh, uint8_t *grot) +{ + uint32_t dy = 0; + + do { + for(uint8_t n = 0; n < gw; n++) { + uint8_t out = 0; + uint8_t mask = 0x80 >> n; + for(uint8_t b = 0; b < 8; b++) { + if (glyph[b] & mask) + out |= 1 << b; + } + grot[dy++] = out; + } + glyph += 8; + } while((gh -= 8) > 0); + + return dy; +} + +bdfe_t *bdf_convert(const char *name, unsigned gmin, unsigned gmax, unsigned ascender, int flags) +{ + FILE *fp; + char *arg; + bdfe_t *font = NULL; + char buf[BUFSIZ]; + char startchar[BUFSIZ]; + + if (name == NULL || (fp = fopen(name, "r")) == NULL) + return NULL; + + memset(buf, 0, sizeof(buf)); + int mute = flags & BDF_MUTE; + + if (!mute && (flags & BDF_HEADER)) { + printf("// File generated by 'bdfe"); + if (flags & BDF_NATIVE) + printf(" -n"); + if (flags & BDF_ROTATE) + printf(" -r"); + if (ascender) + printf(" -a %d", ascender); + printf(" -s %d-%d %s'\n", gmin, gmax, basename(name)); + } + + // parse file header up to 'CHARS' keyword + unsigned nchars = 0, dx = 0, dy = 0, descent = 0; + while(fgets(buf, sizeof(buf) - 2, fp) != NULL) { + arg = strchr(buf, '\0'); + while(*arg < ' ' && arg != buf) *arg-- = '\0'; + + if (!mute && (flags & BDF_HEADER)) { + if (key_arg(buf, "FONT", &arg)) + printf("// %s\n", buf); + if (key_arg(buf, "COMMENT", &arg)) + printf("// %s\n", buf); + if (key_arg(buf, "COPYRIGHT", &arg)) + printf("// %s\n", buf); + if (key_arg(buf, "FONT_ASCENT", &arg)) + printf("// %s\n", buf); + } + + if (key_arg(buf, "FONTBOUNDINGBOX", &arg)) { + if (!mute && (flags & BDF_HEADER)) + printf("// %s\n", buf); + dx = strtoul(arg, &arg, 10); + dy = strtoul(arg, &arg, 10); + strtoul(arg, &arg, 10); + descent = -strtoul(arg, &arg, 10); + } + if (key_arg(buf, "FONT_DESCENT", &arg)) { + if (!mute && (flags & BDF_HEADER)) + printf("// %s\n", buf); + descent = strtoul(arg, &arg, 10); + } + + if (key_arg(buf, "CHARS", &arg)) { + nchars = atoi(arg); + break; + } + } + + if (dy == 0) { + fclose(fp); + return NULL; + } + + // recalculate glyphs x size as we cannot use FONTBOUNDINGBOX + // as it is for our gmin/gmax range + dx = 0; + while(fgets(buf, sizeof(buf) - 2, fp) != NULL) { + if (key_arg(buf, "STARTCHAR", &arg)) { + unsigned idx = 0, dw; + + while(fgets(buf, sizeof(buf) - 2, fp) != NULL) { + if (key_arg(buf, "ENCODING", &arg)) { + idx = atoi(arg); + if (idx < gmin || idx > gmax) + break; + } + if (key_arg(buf, "DWIDTH", &arg)) { + dw = atoi(arg); + if (dw > dx) + dx = dw; + break; + } + } + } + } + + // limit vertical size to 16 pixels or 2 lines on SSD1306 + if (dy > 16) + dy = 16; + + unsigned gh = dy, gw = dx; + // round y size to 8 pixels for SSD1306 text mode + if ((flags & BDF_ROTATE) || !(flags & BDF_NATIVE)) { + dy = (dy+7) & ~0x07; + descent += dy - gh; + gh = dy; + } + + if (!mute && (flags & BDF_HEADER)) + printf("// Converted Font Size %dx%d\n\n", dx, dy); + if (ascender > dy/2) + ascender = dy/2; + // rewind the file pointer ans start parsing glyphs + fseek(fp, 0, SEEK_SET); + + unsigned gsize = dy * ((dx + 7) / 8); + font = (bdfe_t *)malloc(sizeof(bdfe_t) + gsize*nchars); + font->chars = 0; + // glyphs output buffer + uint8_t *gout = font->font; + // glyph storage buffer, big enough to allow displacement manipulations + uint8_t *gbuf = (uint8_t *)malloc(gsize*2); + memset(gbuf, 0, gsize*2); + + while(fgets(buf, sizeof(buf) - 2, fp) != NULL) { + if (key_arg(buf, "STARTCHAR", &arg)) { + unsigned displacement = 0; + unsigned bitmap = 0, i = 0, idx = 0; + unsigned bbw = 0; + int bbox = 0, bboy = 0; + uint8_t *gin = gbuf + gsize; + + memset(gin, 0, gsize); + // store a copy in case if verbose output is on + arg = strchr(buf, '\0'); + while(*arg < ' ' && arg != buf) *arg-- = '\0'; + strcpy(startchar, buf); + + while(fgets(buf, sizeof(buf) - 2, fp) != NULL) { + arg = strchr(buf, '\0'); + while(*arg < ' ' && arg != buf) *arg-- = '\0'; + + if (key_arg(buf, "ENCODING", &arg)) { + idx = atoi(arg); + if (idx < gmin || idx > gmax) + break; + if (!mute && !(flags & BDF_GPL) && (flags & BDF_VERBOSE)) { + printf("// %s\n", startchar); + printf("// %s\n", buf); + } + } + if (key_arg(buf, "DWIDTH", &arg)) { + gw = atoi(arg); + if (gw > 8) + break; + } + if (key_arg(buf, "BBX", &arg)) { + if (!mute && !(flags & BDF_GPL) && (flags & BDF_VERBOSE)) + printf("// %s\n", buf); + bbw = strtol(arg, &arg, 10); + strtol(arg, &arg, 10); // skip bbh, we'll calculate it (i) + bbox = strtol(arg, &arg, 10); + bboy = strtol(arg, &arg, 10); + } + if (key_arg(buf, "ENDCHAR", &arg)) { + font->chars++; + // check if baseline alignment is needed + if (bboy > 0) + i += bboy; + if ((bboy < 0) && (i < dy)) { + displacement = dy - descent - i; // move BBX to origin + displacement -= bboy; + i += displacement; + } + if (i < (dy - descent)) + displacement += dy - descent - i; + gin -= displacement + ascender; + if (flags & BDF_ROTATE) { + gh = rotate_glyph(gin, dx, dy, gout); + gw = 8; + } + else + memcpy(gout, gin, dy); + + if (!mute) { + if (flags & BDF_GPL) { + printf("\t"); + for(i = 0; i < dy; i++) + printf("0x%02X,", gout[i]); + printf(" // %5d", idx); + if (isprint(idx)) + printf(" '%c'", idx); + printf("\n"); + } + else { + printf("// %5d '%c' |", idx, isprint(idx) ? idx : ' '); + for(i = 0; i < gw; i++) + printf("%d", i); + printf("|\n"); + for(i = 0; i < gh; i++) { + printf(" 0x%02X, // %2d|", gout[i], i); + for(unsigned bit = 0; bit < gw; bit++) { + if (gout[i] & (0x80 >> bit)) + printf("#"); + else + printf(" "); + } + printf("|\n"); + } + printf("\n"); + } + } + gout += gh; + break; + } + if (key_arg(buf, "BITMAP", &arg)) { + bitmap = 1; + continue; + } + if (bitmap && (i < dy)) { + gin[i] = (uint8_t)strtoul(buf, NULL, 16); + if ((bbw < 8) && (bbox > 0) && (bbox < 8)) + gin[i] = gin[i] >> bbox; + i++; + } + } + } + } + font->gw = dx; + font->bpg = gh; + + free(gbuf); + fclose(fp); + return font; +} diff --git a/bdf.h b/bdf.h new file mode 100644 index 0000000..1a45daa --- /dev/null +++ b/bdf.h @@ -0,0 +1,66 @@ +/* BSD License + Copyright (c) 2014 Andrey Chilikin https://github.com/achilikin + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __BDF_EXPORTER_H__ +#define __BDF_EXPORTER_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#if 0 +} // dummy bracket for Visual Assist +#endif +#endif + +#define BDF_NATIVE 0x01 /*< use native height, do not adjust for SSD1306 */ +#define BDF_ROTATE 0x02 /*< rotate glyphs CCW */ +#define BDF_MUTE 0x04 /*< do not print processed glyphs or header */ +#define BDF_HEADER 0x08 /*< output file header */ +#define BDF_VERBOSE 0x10 /*< verbose glyphs/header output */ +#define BDF_GPL 0x20 /*< one line per glyph */ + + +typedef struct bdfe_s +{ + unsigned gw; /*< glyph width */ + unsigned bpg; /*< bytes per glyph */ + unsigned chars; /*< number of glyphs */ + uint8_t font[]; /*< glyphs' bitmaps */ +} bdfe_t; + +/** + name - bdf font name + gmin/gmax - range of glyphs to be processed + flags - BDF_* above + ascender - extra ascender to be added, in pixels + */ +bdfe_t *bdf_convert(const char *name, unsigned gmin, unsigned gmax, unsigned ascender, int flags); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/font816.h b/font816.h new file mode 100644 index 0000000..009a3b8 --- /dev/null +++ b/font816.h @@ -0,0 +1,111 @@ +// File generated by 'bdfe -n -r -a 1 -s 32-126 zevv-peep-iso8859-1-08x16.bdf' +// FONT -zevv-peep-Medium-R-Normal--16-140-75-75-C-80-ISO8859-1 +// COMMENT - +// COMMENT http://zevv.nl/play/code/zevv-peep/ +// COMMENT Clean, avoid clutter +// COMMENT Very clear distinction between similar characters like 0/O/o, i/I/l/1/| +// COMMENT Suitable for light text on a dark background. +// COMMENT Not to densly packed to allow a good seperation between characters +// COMMENT The zevv-peep font is available under the terms of the MIT license. +// COMMENT - +// FONTBOUNDINGBOX 8 16 0 -3 +// COPYRIGHT "Zevv" +// FONT_ASCENT 13 +// FONT_DESCENT 3 +// Converted Font Size 8x16 + + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32 ' ' + 0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1B,0x00,0x00,0x00,0x00, // 33 '!' + 0x00,0x00,0x78,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 34 '"' + 0x00,0x40,0xF0,0x40,0x40,0xF0,0x40,0x00,0x00,0x02,0x0F,0x02,0x02,0x0F,0x02,0x00, // 35 '#' + 0x00,0xC0,0x20,0xF0,0x20,0x20,0x00,0x00,0x00,0x08,0x09,0x1F,0x09,0x06,0x00,0x00, // 36 '$' + 0x00,0x30,0x48,0x30,0xC0,0x20,0x18,0x00,0x00,0x18,0x04,0x03,0x0C,0x12,0x0C,0x00, // 37 '%' + 0x00,0x60,0x90,0x90,0x60,0x00,0x00,0x00,0x00,0x0E,0x11,0x11,0x12,0x0C,0x12,0x00, // 38 '&' + 0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 39 ''' + 0x00,0x00,0x00,0xC0,0x30,0x08,0x04,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00, // 40 '(' + 0x00,0x04,0x08,0x30,0xC0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00, // 41 ')' + 0x00,0x00,0x40,0x80,0x80,0x40,0x00,0x00,0x00,0x01,0x05,0x03,0x03,0x05,0x01,0x00, // 42 '*' + 0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x0F,0x01,0x01,0x01, // 43 '+' + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x30,0x18,0x08,0x00,0x00,0x00, // 44 ',' + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x00, // 45 '-' + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38,0x10,0x00,0x00,0x00, // 46 '.' + 0x00,0x00,0x00,0x00,0xC0,0x30,0x0C,0x00,0x00,0x30,0x0C,0x03,0x00,0x00,0x00,0x00, // 47 '/' + 0x00,0xE0,0x10,0x08,0x88,0x10,0xE0,0x00,0x00,0x07,0x08,0x11,0x10,0x08,0x07,0x00, // 48 '0' + 0x00,0x40,0x20,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x00, // 49 '1' + 0x00,0x30,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x18,0x14,0x12,0x11,0x10,0x10,0x00, // 50 '2' + 0x00,0x10,0x08,0x88,0x88,0x88,0x70,0x00,0x00,0x0C,0x10,0x10,0x10,0x10,0x0F,0x00, // 51 '3' + 0x00,0x00,0xC0,0x30,0x08,0xF8,0x00,0x00,0x00,0x03,0x02,0x02,0x02,0x1F,0x02,0x00, // 52 '4' + 0x00,0xF8,0x48,0x48,0x48,0x48,0x88,0x00,0x00,0x0C,0x10,0x10,0x10,0x10,0x0F,0x00, // 53 '5' + 0x00,0xF0,0x08,0x88,0x88,0x88,0x10,0x00,0x00,0x0F,0x11,0x10,0x10,0x10,0x0F,0x00, // 54 '6' + 0x00,0x08,0x08,0x08,0x88,0x68,0x18,0x00,0x00,0x00,0x18,0x06,0x01,0x00,0x00,0x00, // 55 '7' + 0x00,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00,0x0F,0x10,0x10,0x10,0x10,0x0F,0x00, // 56 '8' + 0x00,0xF0,0x08,0x08,0x08,0x88,0xF0,0x00,0x00,0x08,0x11,0x11,0x11,0x10,0x0F,0x00, // 57 '9' + 0x00,0x00,0x40,0xE0,0x40,0x00,0x00,0x00,0x00,0x00,0x10,0x38,0x10,0x00,0x00,0x00, // 58 ':' + 0x00,0x00,0x40,0xE0,0x40,0x00,0x00,0x00,0x00,0x40,0x30,0x18,0x08,0x00,0x00,0x00, // 59 ';' + 0x00,0x00,0x80,0x40,0x20,0x10,0x00,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x00,0x00, // 60 '<' + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x00, // 61 '=' + 0x00,0x00,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x00,0x10,0x08,0x04,0x02,0x01,0x00, // 62 '>' + 0x00,0x08,0x08,0x88,0x48,0x30,0x00,0x00,0x00,0x00,0x1B,0x00,0x00,0x00,0x00,0x00, // 63 '?' + 0x00,0xE0,0x10,0x88,0x48,0x48,0xF0,0x00,0x00,0x07,0x08,0x13,0x14,0x14,0x07,0x00, // 64 '@' + 0x00,0xF0,0x08,0x08,0x08,0x08,0xF0,0x00,0x00,0x1F,0x01,0x01,0x01,0x01,0x1F,0x00, // 65 'A' + 0x00,0xF8,0x88,0x88,0x88,0xF0,0x00,0x00,0x00,0x1F,0x10,0x10,0x10,0x10,0x0F,0x00, // 66 'B' + 0x00,0xF0,0x08,0x08,0x08,0x08,0x30,0x00,0x00,0x0F,0x10,0x10,0x10,0x10,0x0C,0x00, // 67 'C' + 0x00,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x00,0x1F,0x10,0x10,0x10,0x08,0x07,0x00, // 68 'D' + 0x00,0xF8,0x88,0x88,0x88,0x88,0x08,0x00,0x00,0x1F,0x10,0x10,0x10,0x10,0x10,0x00, // 69 'E' + 0x00,0xF8,0x88,0x88,0x88,0x88,0x08,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00, // 70 'F' + 0x00,0xF0,0x08,0x08,0x08,0x08,0x30,0x00,0x00,0x0F,0x10,0x10,0x11,0x11,0x0F,0x00, // 71 'G' + 0x00,0xF8,0x80,0x80,0x80,0x80,0xF8,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x1F,0x00, // 72 'H' + 0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x10,0x10,0x1F,0x10,0x10,0x00,0x00, // 73 'I' + 0x00,0x00,0x00,0x08,0x08,0x08,0xF8,0x00,0x00,0x0C,0x10,0x10,0x10,0x10,0x0F,0x00, // 74 'J' + 0x00,0xF8,0x80,0x40,0xA0,0x10,0x08,0x00,0x00,0x1F,0x00,0x00,0x01,0x06,0x18,0x00, // 75 'K' + 0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x10,0x10,0x10,0x10,0x10,0x00, // 76 'L' + 0x00,0xF8,0x30,0xC0,0x00,0xC0,0x30,0xF8,0x00,0x1F,0x00,0x00,0x03,0x00,0x00,0x1F, // 77 'M' + 0x00,0xF8,0x30,0xC0,0x00,0x00,0xF8,0x00,0x00,0x1F,0x00,0x00,0x03,0x0C,0x1F,0x00, // 78 'N' + 0x00,0xF0,0x08,0x08,0x08,0x08,0xF0,0x00,0x00,0x0F,0x10,0x10,0x10,0x10,0x0F,0x00, // 79 'O' + 0x00,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x00,0x1F,0x01,0x01,0x01,0x01,0x00,0x00, // 80 'P' + 0x00,0xF0,0x08,0x08,0x08,0x08,0xF0,0x00,0x00,0x0F,0x10,0x10,0x1C,0x30,0x2F,0x00, // 81 'Q' + 0x00,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x00,0x1F,0x01,0x03,0x05,0x09,0x10,0x00, // 82 'R' + 0x00,0x70,0x88,0x88,0x08,0x08,0x10,0x00,0x00,0x08,0x10,0x10,0x11,0x11,0x0E,0x00, // 83 'S' + 0x00,0x08,0x08,0x08,0xF8,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x00, // 84 'T' + 0x00,0xF8,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x0F,0x10,0x10,0x10,0x10,0x0F,0x00, // 85 'U' + 0x00,0xF8,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x01,0x06,0x18,0x18,0x06,0x01,0x00, // 86 'V' + 0x00,0xF8,0x00,0x00,0x80,0x00,0x00,0xF8,0x00,0x07,0x18,0x06,0x01,0x06,0x18,0x07, // 87 'W' + 0x00,0x18,0x60,0x80,0x80,0x60,0x18,0x00,0x00,0x18,0x06,0x01,0x01,0x06,0x18,0x00, // 88 'X' + 0x00,0x78,0x80,0x00,0x00,0x80,0x78,0x00,0x00,0x00,0x00,0x01,0x1F,0x00,0x00,0x00, // 89 'Y' + 0x00,0x08,0x08,0x08,0x88,0x68,0x18,0x00,0x00,0x18,0x14,0x13,0x10,0x10,0x10,0x00, // 90 'Z' + 0x00,0x00,0x00,0xFC,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00, // 91 '[' + 0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0C,0x30,0x00, // 92 '\' + 0x00,0x04,0x04,0x04,0xFC,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00, // 93 ']' + 0x00,0x20,0x10,0x08,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 94 '^' + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x00, // 95 '_' + 0x00,0x00,0x08,0x18,0x30,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 96 '`' + 0x00,0x00,0x40,0x40,0x40,0x40,0x80,0x00,0x00,0x0E,0x11,0x11,0x11,0x09,0x1F,0x00, // 97 'a' + 0x00,0xF8,0x80,0x40,0x40,0x40,0x80,0x00,0x00,0x1F,0x08,0x10,0x10,0x10,0x0F,0x00, // 98 'b' + 0x00,0x80,0x40,0x40,0x40,0x40,0x80,0x00,0x00,0x0F,0x10,0x10,0x10,0x10,0x08,0x00, // 99 'c' + 0x00,0x80,0x40,0x40,0x40,0x80,0xF8,0x00,0x00,0x0F,0x10,0x10,0x10,0x08,0x1F,0x00, // 100 'd' + 0x00,0x80,0x40,0x40,0x40,0x40,0x80,0x00,0x00,0x0F,0x12,0x12,0x12,0x12,0x13,0x00, // 101 'e' + 0x00,0x00,0xF0,0x08,0x08,0x08,0x10,0x00,0x00,0x01,0x1F,0x01,0x01,0x01,0x00,0x00, // 102 'f' + 0x00,0x80,0x40,0x40,0x40,0x80,0xC0,0x00,0x00,0x47,0x88,0x88,0x88,0x84,0x7F,0x00, // 103 'g' + 0x00,0xF8,0x80,0x40,0x40,0x40,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x1F,0x00, // 104 'h' + 0x00,0x00,0x40,0x40,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x00, // 105 'i' + 0x00,0x00,0x00,0x40,0x40,0xD8,0x00,0x00,0x00,0x20,0x40,0x40,0x40,0x3F,0x00,0x00, // 106 'j' + 0x00,0xF8,0x00,0x00,0x80,0x40,0x00,0x00,0x00,0x1F,0x02,0x03,0x04,0x08,0x10,0x00, // 107 'k' + 0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x10,0x10,0x10,0x00,0x00, // 108 'l' + 0x00,0xC0,0x40,0x40,0x80,0x40,0x40,0x80,0x00,0x1F,0x00,0x00,0x07,0x00,0x00,0x1F, // 109 'm' + 0x00,0xC0,0x80,0x40,0x40,0x40,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x1F,0x00, // 110 'n' + 0x00,0x80,0x40,0x40,0x40,0x40,0x80,0x00,0x00,0x0F,0x10,0x10,0x10,0x10,0x0F,0x00, // 111 'o' + 0x00,0xC0,0x80,0x40,0x40,0x40,0x80,0x00,0x00,0xFF,0x04,0x08,0x08,0x08,0x07,0x00, // 112 'p' + 0x00,0x80,0x40,0x40,0x40,0x80,0xC0,0x00,0x00,0x07,0x08,0x08,0x08,0x04,0xFF,0x00, // 113 'q' + 0x00,0xC0,0x80,0x40,0x40,0x40,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00, // 114 'r' + 0x00,0x80,0x40,0x40,0x40,0x40,0x80,0x00,0x00,0x09,0x12,0x12,0x12,0x12,0x0C,0x00, // 115 's' + 0x00,0x40,0xF0,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x0F,0x10,0x10,0x10,0x08,0x00, // 116 't' + 0x00,0xC0,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x0F,0x10,0x10,0x10,0x08,0x1F,0x00, // 117 'u' + 0x00,0xC0,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x01,0x06,0x18,0x18,0x06,0x01,0x00, // 118 'v' + 0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x0F,0x10,0x08,0x07,0x08,0x10,0x0F, // 119 'w' + 0x00,0x40,0x80,0x00,0x00,0x80,0x40,0x00,0x00,0x10,0x08,0x05,0x05,0x08,0x10,0x00, // 120 'x' + 0x00,0xC0,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x47,0x88,0x88,0x88,0x84,0x7F,0x00, // 121 'y' + 0x00,0x40,0x40,0x40,0x40,0x40,0xC0,0x00,0x00,0x10,0x18,0x14,0x12,0x11,0x10,0x00, // 122 'z' + 0x00,0x00,0x00,0x00,0xF8,0x04,0x04,0x00,0x00,0x00,0x01,0x01,0x3E,0x40,0x40,0x00, // 123 '{' + 0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00, // 124 '|' + 0x00,0x04,0x04,0xF8,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x3E,0x01,0x01,0x00,0x00, // 125 '}' + 0x00,0x60,0x10,0x10,0x20,0x40,0x40,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 126 '~' diff --git a/font88.h b/font88.h new file mode 100644 index 0000000..6b10b59 --- /dev/null +++ b/font88.h @@ -0,0 +1,121 @@ +// File generated by 'bdfe -r -s 32-126 clR8x8.bdf' +// COMMENT http://cgit.freedesktop.org/xorg/font/schumacher-misc/tree/clR8x8.bdf +// COMMENT $Xorg: clR8x8.bdf,v 1.3 2000/08/18 15:17:40 xorgcvs Exp $ +// COMMENT +// COMMENT Copyright 1989 Dale Schumacher, dal@syntel.mn.org +// COMMENT 399 Beacon Ave. +// COMMENT St. Paul, MN 55104-3527 +// COMMENT +// COMMENT Permission to use, copy, modify, and distribute this software and +// COMMENT its documentation for any purpose and without fee is hereby +// COMMENT granted, provided that the above copyright notice appear in all +// COMMENT copies and that both that copyright notice and this permission +// COMMENT notice appear in supporting documentation, and that the name of +// COMMENT Dale Schumacher not be used in advertising or publicity pertaining to +// COMMENT distribution of the software without specific, written prior +// COMMENT permission. Dale Schumacher makes no representations about the +// COMMENT suitability of this software for any purpose. It is provided "as +// COMMENT is" without express or implied warranty. +// COMMENT +// FONT -Schumacher-Clean-Medium-R-Normal--8-80-75-75-C-80-ISO646.1991-IRV +// FONTBOUNDINGBOX 8 8 0 -1 +// FONT_ASCENT 7 +// FONT_DESCENT 1 +// COPYRIGHT "Copyright 1989 Dale Schumacher." +// Converted Font Size 8x8 + + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32 ' ' + 0x00,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, // 33 '!' + 0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x00, // 34 '"' + 0x00,0x00,0x14,0x7F,0x14,0x7F,0x14,0x00, // 35 '#' + 0x00,0x00,0x24,0x2A,0x7F,0x2A,0x12,0x00, // 36 '$' + 0x00,0x02,0x45,0x32,0x08,0x26,0x51,0x20, // 37 '%' + 0x00,0x32,0x4D,0x49,0x51,0x20,0x50,0x00, // 38 '&' + 0x00,0x00,0x00,0x04,0x03,0x01,0x00,0x00, // 39 ''' + 0x00,0x00,0x00,0x1C,0x22,0x41,0x00,0x00, // 40 '(' + 0x00,0x00,0x00,0x41,0x22,0x1C,0x00,0x00, // 41 ')' + 0x00,0x04,0x44,0x28,0x1F,0x28,0x44,0x04, // 42 '*' + 0x00,0x08,0x08,0x08,0x7F,0x08,0x08,0x08, // 43 '+' + 0x00,0x00,0x80,0x60,0x20,0x00,0x00,0x00, // 44 ',' + 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08, // 45 '-' + 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00, // 46 '.' + 0x00,0x00,0xC0,0x30,0x0C,0x03,0x00,0x00, // 47 '/' + 0x00,0x3E,0x41,0x41,0x41,0x41,0x3E,0x00, // 48 '0' + 0x00,0x00,0x00,0x02,0x7F,0x00,0x00,0x00, // 49 '1' + 0x00,0x42,0x61,0x51,0x49,0x45,0x42,0x00, // 50 '2' + 0x00,0x22,0x41,0x49,0x49,0x49,0x36,0x00, // 51 '3' + 0x00,0x10,0x18,0x14,0x52,0x7F,0x50,0x00, // 52 '4' + 0x00,0x4F,0x49,0x49,0x49,0x49,0x31,0x00, // 53 '5' + 0x00,0x3C,0x4A,0x49,0x49,0x49,0x30,0x00, // 54 '6' + 0x00,0x01,0x01,0x41,0x31,0x0D,0x03,0x00, // 55 '7' + 0x00,0x36,0x49,0x49,0x49,0x49,0x36,0x00, // 56 '8' + 0x00,0x06,0x49,0x49,0x49,0x29,0x1E,0x00, // 57 '9' + 0x00,0x00,0x00,0x66,0x66,0x00,0x00,0x00, // 58 ':' + 0x00,0x00,0x80,0x66,0x26,0x00,0x00,0x00, // 59 ';' + 0x00,0x08,0x08,0x14,0x14,0x22,0x22,0x00, // 60 '<' + 0x00,0x24,0x24,0x24,0x24,0x24,0x24,0x24, // 61 '=' + 0x00,0x22,0x22,0x14,0x14,0x08,0x08,0x00, // 62 '>' + 0x00,0x00,0x02,0x01,0x51,0x09,0x06,0x00, // 63 '?' + 0x00,0x1C,0x22,0x49,0x55,0x49,0x12,0x0C, // 64 '@' + 0x00,0x40,0x70,0x1C,0x17,0x1C,0x70,0x40, // 65 'A' + 0x00,0x7F,0x49,0x49,0x49,0x49,0x49,0x36, // 66 'B' + 0x00,0x1C,0x22,0x41,0x41,0x41,0x41,0x22, // 67 'C' + 0x00,0x7F,0x41,0x41,0x41,0x41,0x22,0x1C, // 68 'D' + 0x00,0x7F,0x49,0x49,0x49,0x49,0x41,0x41, // 69 'E' + 0x00,0x7F,0x09,0x09,0x09,0x09,0x01,0x01, // 70 'F' + 0x00,0x1C,0x22,0x41,0x41,0x49,0x49,0x7A, // 71 'G' + 0x00,0x7F,0x08,0x08,0x08,0x08,0x08,0x7F, // 72 'H' + 0x00,0x00,0x41,0x41,0x7F,0x41,0x41,0x00, // 73 'I' + 0x00,0x30,0x40,0x40,0x41,0x41,0x3F,0x00, // 74 'J' + 0x00,0x7F,0x08,0x08,0x14,0x22,0x41,0x00, // 75 'K' + 0x00,0x7F,0x40,0x40,0x40,0x40,0x40,0x00, // 76 'L' + 0x00,0x7F,0x02,0x04,0x08,0x04,0x02,0x7F, // 77 'M' + 0x00,0x7F,0x02,0x04,0x08,0x10,0x20,0x7F, // 78 'N' + 0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x1C, // 79 'O' + 0x00,0x7F,0x09,0x09,0x09,0x09,0x09,0x06, // 80 'P' + 0x00,0x1C,0x22,0x41,0x41,0xC1,0xA2,0x9C, // 81 'Q' + 0x00,0x7F,0x09,0x09,0x09,0x19,0x29,0x46, // 82 'R' + 0x00,0x26,0x49,0x49,0x49,0x49,0x49,0x32, // 83 'S' + 0x00,0x01,0x01,0x01,0x7F,0x01,0x01,0x01, // 84 'T' + 0x00,0x3F,0x40,0x40,0x40,0x40,0x40,0x3F, // 85 'U' + 0x00,0x01,0x07,0x18,0x60,0x18,0x07,0x01, // 86 'V' + 0x00,0x7F,0x20,0x10,0x08,0x10,0x20,0x7F, // 87 'W' + 0x00,0x41,0x22,0x14,0x08,0x14,0x22,0x41, // 88 'X' + 0x00,0x01,0x02,0x04,0x78,0x04,0x02,0x01, // 89 'Y' + 0x00,0x41,0x61,0x51,0x49,0x45,0x43,0x41, // 90 'Z' + 0x00,0x00,0x00,0x00,0x7F,0x41,0x41,0x00, // 91 '[' + 0x00,0x00,0x03,0x0C,0x30,0xC0,0x00,0x00, // 92 '\' + 0x00,0x00,0x41,0x41,0x7F,0x00,0x00,0x00, // 93 ']' + 0x00,0x00,0x04,0x02,0x01,0x02,0x04,0x00, // 94 '^' + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80, // 95 '_' + 0x00,0x00,0x00,0x01,0x03,0x04,0x00,0x00, // 96 '`' + 0x00,0x38,0x44,0x44,0x44,0x44,0x24,0x7C, // 97 'a' + 0x00,0x7F,0x44,0x44,0x44,0x44,0x44,0x38, // 98 'b' + 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x00, // 99 'c' + 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x7F, // 100 'd' + 0x00,0x38,0x54,0x54,0x54,0x54,0x54,0x18, // 101 'e' + 0x00,0x04,0x7E,0x05,0x05,0x01,0x01,0x00, // 102 'f' + 0x00,0x18,0xA4,0xA4,0xA4,0xA4,0xA4,0x7C, // 103 'g' + 0x00,0x7F,0x04,0x04,0x04,0x04,0x04,0x78, // 104 'h' + 0x00,0x00,0x44,0x44,0x7D,0x40,0x40,0x00, // 105 'i' + 0x00,0x00,0x80,0x84,0x84,0x84,0x7D,0x00, // 106 'j' + 0x00,0x7F,0x10,0x10,0x28,0x44,0x44,0x00, // 107 'k' + 0x00,0x00,0x00,0x41,0x7F,0x40,0x00,0x00, // 108 'l' + 0x00,0x7C,0x04,0x04,0x38,0x04,0x04,0x78, // 109 'm' + 0x00,0x7C,0x08,0x04,0x04,0x04,0x04,0x78, // 110 'n' + 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38, // 111 'o' + 0x00,0xFC,0x44,0x44,0x44,0x44,0x44,0x38, // 112 'p' + 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0xFC, // 113 'q' + 0x00,0x00,0x7C,0x08,0x04,0x04,0x04,0x00, // 114 'r' + 0x00,0x48,0x54,0x54,0x54,0x54,0x24,0x00, // 115 's' + 0x00,0x04,0x04,0x3F,0x44,0x44,0x44,0x00, // 116 't' + 0x00,0x3C,0x40,0x40,0x40,0x40,0x20,0x7C, // 117 'u' + 0x00,0x04,0x0C,0x30,0x40,0x30,0x0C,0x04, // 118 'v' + 0x00,0x3C,0x40,0x40,0x38,0x40,0x40,0x3C, // 119 'w' + 0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44, // 120 'x' + 0x00,0x1C,0xA0,0xA0,0xA0,0xA0,0x7C,0x00, // 121 'y' + 0x00,0x44,0x64,0x54,0x54,0x4C,0x44,0x00, // 122 'z' + 0x00,0x00,0x00,0x08,0x36,0x41,0x00,0x00, // 123 '{' + 0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00, // 124 '|' + 0x00,0x00,0x00,0x41,0x36,0x08,0x00,0x00, // 125 '}' + 0x00,0x06,0x01,0x01,0x02,0x04,0x04,0x03, // 126 '~' diff --git a/main.c b/main.c new file mode 100644 index 0000000..0b1a6f5 --- /dev/null +++ b/main.c @@ -0,0 +1,217 @@ +/* BSD License + Copyright (c) 2014 Andrey Chilikin https://github.com/achilikin + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + Basic BDF Exporter - converts BDF files to C structures. + Only 8 bits wide fonts are supported. +*/ +#include +#include +#include +#include +#include + +#include "bdf.h" +#include "pi2c.h" +#include "rterm.h" +#include "ossd_i2c.h" + +#define DISPLAY_FONT 0x80000000 + +/** + sarg: short argument + larg: long argument + */ +static int arg_is(const char *arg, const char *sarg, const char *larg) +{ + if (sarg && (strcmp(arg, sarg) == 0)) + return 1; + if (larg && (strcmp(arg, larg) == 0)) + return 1; + return 0; +} + +static void usage(const char *name) +{ + printf("%s [options] \n", name); + printf(" options are:\n"); + printf(" header: print file header\n"); + printf(" verbose: add extra info to the header\n"); + printf(" line: one line per glyph\n"); + printf(" subset a-b: subset of glyphs to convert a to b, default 32-126\n"); + printf(" all: print all glyphs, not just 32-126\n"); + printf(" native: do not adjust font height 8 pixels\n"); + printf(" ascender H: add extra ascender of H pixels per glyph\n"); + printf(" rotate: rotate glyphs' bitmaps CCW\n"); + printf(" display A: show converted font on SSD1306 compatible display\n"); + printf(" using I2C bus 1, hexadecimal address A (default 3C)\n"); + printf(" updown: display orientation is upside down\n"); +} + +int main(int argc, char **argv) +{ + char *file; + bdfe_t *font; + int flags = 0; + uint8_t i2c_address = 0x3C; + uint8_t orientation = 0; + uint32_t gidx = 0; + unsigned ascender = 0; + unsigned gmin = 32, gmax = 126; + + if (argc < 2) { + usage(basename(argv[0])); + return -1; + } + + for(int i = 1; i < argc; i++) { + if (arg_is(argv[i], "-?", "help")) { + usage(basename(argv[0])); + return 0; + } + + if (arg_is(argv[i], "-h", "header")) + flags |= BDF_HEADER; + + if (arg_is(argv[i], "-v", "verbose")) + flags |= BDF_VERBOSE; + + if (arg_is(argv[i], "-a", "ascender")) { + if (i < argc && isdigit(*argv[i+1])) + ascender = atoi(argv[++i]); + } + + if (arg_is(argv[i], "-l", "line")) + flags |= BDF_GPL; + + if (arg_is(argv[i], "-s", "subset")) { + if (i < argc && isdigit(*argv[i+1])) { + i++; + char *end; + gmin = strtoul(argv[i], &end, 10); + gmax = gmin; + if (*end == '-') + gmax = strtoul(end+1, &end, 10); + if (gmax < gmin) { + unsigned tmp = gmin; + gmin = gmax; + gmax = tmp; + } + } + } + + if (arg_is(argv[i], "-a", "all")) { + gmin = 0; + gmax = 0xFFFFFFFF; + } + + if (arg_is(argv[i], "-n", "native")) + flags |= BDF_NATIVE; + + if (arg_is(argv[i], "-r", "rotate")) + flags |= BDF_ROTATE; + + if (arg_is(argv[i], "-d", "display")) { + flags |= DISPLAY_FONT; + if (i < argc && isxdigit(*argv[i+1])) { + i++; + uint32_t i2ca = strtoul(argv[i], NULL, 16); + if (i2ca && (i2ca < 0x78)) + i2c_address = i2ca; + } + } + + if (arg_is(argv[i], "-u", "updown")) + orientation = OSSD_UPDOWN; + } + + file = argv[argc - 1]; + font = bdf_convert(file, gmin, gmax, ascender, flags); + + if (font == NULL) { + fprintf(stderr, "Unable to convert '%s'\n", file); + return -1; + } + + if (!(flags & DISPLAY_FONT)) { + free(font); + return 0; + } + + if (pi2c_open(PI2C_BUS) < 0) { + fprintf(stderr, "Unable to open i2c bus %d\n", PI2C_BUS); + free(font); + return -1; + } + pi2c_select(PI2C_BUS, i2c_address); + + ossd_font_t of; + of.gw = font->gw; + of.gh = font->bpg; + of.go = (uint8_t)gmin; + of.gn = (uint8_t)font->chars; + of.font = font->font; + + ossd_init(orientation); + ossd_set_user_font(&of, NULL); + ossd_select_font(OSSD_FONT_USER); + + int gh = (of.gh + 7)/8; // glyph height in lines + + char buf[16]; + sprintf(buf, "%dx%d", of.gw, of.gh); + file = basename(file); + ossd_putlx(0, -1, file, OSSD_TEXT_REVERSE); + ossd_putlx(8 - gh, -1, buf, OSSD_TEXT_UNDERLINE | OSSD_TEXT_OVERLINE); + buf[1] = '\0'; + + stdin_mode(TERM_MODE_RAW); + fprintf(stderr, "Press any key to continue, 'q' to exit\n"); + if (stdin_getch(-1) == 'q') goto exit; + + ossd_fill_screen(0); + + do { + if (gidx > 0) { + fprintf(stderr, "Press any key to continue, 'q' to exit\n"); + if (stdin_getch(-1) == 'q') break; + ossd_fill_screen(0); + } + for(int line = 0, l = 0; line < 8; line += gh, l++) { + for(int i = 0; i < (128/of.gw) && gidx < font->chars; i++, gidx++) { + buf[0] = gidx + of.go; + ossd_putlx(line, i*of.gw, (const char *)buf, 0); + } + } + } while(gidx < font->chars); + +exit: + stdin_mode(TERM_MODE_CAN); + pi2c_close(PI2C_BUS); + free(font); + + return 0; +} diff --git a/ossd_i2c.c b/ossd_i2c.c new file mode 100644 index 0000000..39eba4d --- /dev/null +++ b/ossd_i2c.c @@ -0,0 +1,390 @@ +/* BSD License + Copyright (c) 2014 Andrey Chilikin https://github.com/achilikin + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + Limited set of functions for SSD1306 compatible OLED 128x64 displays + in text mode to minimize memory footprint if used on Atmel AVRs chips + with low memory. +*/ + +#include + +#include "ossd_i2c.h" + +#if (OSSD_TARGET == OSSD_AVR) + #include + #include + #include + #include "i2cmaster.h" +#else + #define PROGMEM + #define pgm_read_byte(x) (*((uint8_t *)x)) + #include + #include +#if (OSSD_TARGET == OSSD_RPI) + #include "pi2c.h" +#endif +#endif + +#define OSSD_CMD 0x00 +#define OSSD_DATA 0x40 + +#define OSSD_SET_ADDR_MODE 0x20 +#define OSSD_ADDR_MODE_PAGE 0x10 +#define OSSD_ADDR_MODE_HOR 0x00 +#define OSSD_ADDR_MODE_VER 0x01 + +#define OSSD_SET_COL_ADDR 0x21 +#define OSSD_SET_PAGE_ADDR 0x22 + +#define OSSD_SET_START_LINE 0x40 + +#define OSSD_SET_START_PAGE 0xB0 +#define OSSD_SET_START_LCOL 0x00 +#define OSSD_SET_START_HCOL 0x10 + +#define OSSD_SET_MUX_RATIO 0xA8 +#define OSSD_SET_DISP_OFFSET 0xD3 + +#define OSSD_SET_CONTRAST 0x81 + +#define OSSD_SET_SEG_REMAP 0xA0 +#define OSSD_SEG_REMAP_R2L 0x01 + +#define OSSD_SET_COM_DIR 0xC0 +#define OSSD_COM_DIR_UPDOWN 0x08 + +#define OSSD_SET_COM_CONFIG 0xDA +#define OSSD_COM_ALT 0x12 +#define OSSD_COM_LR_REMAP 0x22 + +#define OSSD_SET_SLEEP_ON 0xAE +#define OSSD_SET_SLEEP_OFF 0xAF + +#define OSSD_SET_INVERSE_ON 0xA7 +#define OSSD_SET_INVERSE_OFF 0xA6 + +#define OSSD_SET_OUTPUT_RAM 0xA4 +#define OSSD_SET_OUTPUT_ON 0xA5 + +#define OSSD_SET_DISP_CLOCK 0xD5 + +#define OSSD_SET_PRECHARGE 0xD9 + +#define OSSD_SET_VCOMH_LEVEL 0xDB +#define OSSD_VCOMH_L065 0x00 +#define OSSD_VCOMH_L077 0x20 +#define OSSD_VCOMH_L083 0x30 + +#define OSSD_SET_CHARGE_PUMP 0x8D +#define OSSD_CHARGE_PUMP_ON 0x14 +#define OSSD_CHARGE_PUMP_OFF 0x10 + +static const uint8_t font88[] PROGMEM = { +#include "font88.h" +}; + +static const uint8_t font816[] PROGMEM = { +#include "font816.h" +}; + +static ossd_font_t _ofont[OSSD_FONT_MAX+1] = { + { 8, 8, 32, 127-32, font88 }, + { 8, 16, 32, 127-32, font816 }, + { 0, 0, 0, 0, NULL } +}; + +static uint8_t _cfont; +static uint8_t _mode; + +uint8_t ossd_select_font(uint8_t font) +{ + uint8_t fret = _cfont; + if (font <= OSSD_FONT_MAX) + _cfont = font; + return fret; +} + +void ossd_set_user_font(ossd_font_t *nfont, ossd_font_t *ofont) +{ + if (ofont) { + ofont->gw = _ofont[OSSD_FONT_USER].gw; + ofont->gh = _ofont[OSSD_FONT_USER].gh; + ofont->go = _ofont[OSSD_FONT_USER].go; + ofont->gn = _ofont[OSSD_FONT_USER].gn; + ofont->font = _ofont[OSSD_FONT_USER].font; + } + _ofont[OSSD_FONT_USER].gw = nfont->gw; + _ofont[OSSD_FONT_USER].gh = nfont->gh; + _ofont[OSSD_FONT_USER].go = nfont->go; + _ofont[OSSD_FONT_USER].gn = nfont->gn; + _ofont[OSSD_FONT_USER].font = nfont->font; +} + +#if (OSSD_TARGET == OSSD_AVR) + +static void ossd_send_byte(uint8_t dc, uint8_t data) +{ + i2c_start(I2C_OSSD | I2C_WRITE); + i2c_write(dc); + i2c_write(data); + i2c_stop(); +} + +static void ossd_cmd_arg(uint8_t cmd, uint8_t arg) +{ + i2c_start(I2C_OSSD | I2C_WRITE); + i2c_write(OSSD_CMD); + i2c_write(cmd); + i2c_write(arg); + i2c_stop(); +} + +static void ossd_cmd_arg2(uint8_t cmd, uint8_t arg1, uint8_t arg2) +{ + i2c_start(I2C_OSSD | I2C_WRITE); + i2c_write(OSSD_CMD); + i2c_write(cmd); + i2c_write(arg1); + i2c_write(arg2); + i2c_stop(); +} + +static void ossd_fill_line(uint8_t data, uint8_t num) +{ + i2c_start(I2C_OSSD | I2C_WRITE); + i2c_write(OSSD_DATA); + for(uint8_t i = 0; i < num; i++) + i2c_write(data); + i2c_stop(); +} + +#else + +static void ossd_send_byte(uint8_t dc, uint8_t data) +{ + uint8_t buf[2]; + buf[0] = dc; + buf[1] = data; + + pi2c_write(PI2C_BUS, buf, 2); +} + +static void ossd_cmd_arg(uint8_t cmd, uint8_t arg) +{ + uint8_t data[3]; + data[0] = OSSD_CMD; + data[1] = cmd; + data[2] = arg; + pi2c_write(PI2C_BUS, data, 3); +} + +static void ossd_cmd_arg2(uint8_t cmd, uint8_t arg1, uint8_t arg2) +{ + uint8_t data[4]; + data[0] = OSSD_CMD; + data[1] = cmd; + data[2] = arg1; + data[3] = arg2; + pi2c_write(PI2C_BUS, data, 4); +} + +static void ossd_fill_line(uint8_t data, uint8_t num) +{ + uint8_t *buf = (uint8_t *)alloca(num+1); + memset(buf, data, num+1); + buf[0] = OSSD_DATA; + pi2c_write(PI2C_BUS, buf, num+1); +} + +#endif + +static inline void ossd_cmd(uint8_t cmd) +{ + ossd_send_byte(OSSD_CMD, cmd); +} + +static inline void ossd_data(uint8_t data) +{ + ossd_send_byte(OSSD_DATA, data); +} + +static uint8_t ossd_set_addr_mode(uint8_t set_mode) +{ + uint8_t ret = _mode; + if (_mode != set_mode) { + ossd_cmd_arg(OSSD_SET_ADDR_MODE, set_mode); + // if switching back to page mode + // set full screen as output region + if (set_mode == OSSD_ADDR_MODE_PAGE) { + ossd_cmd_arg2(OSSD_SET_PAGE_ADDR, 0, 7); + ossd_cmd_arg2(OSSD_SET_COL_ADDR, 0, 127); + } + _mode = set_mode; + } + return ret; +} + +void ossd_goto(uint8_t line, uint8_t x) +{ + if (_mode == OSSD_ADDR_MODE_PAGE) { + ossd_cmd(OSSD_SET_START_PAGE | (line & 0x07)); + ossd_cmd(OSSD_SET_START_LCOL | (x & 0x0F)); + ossd_cmd(OSSD_SET_START_HCOL | (x >> 4)); + } + else { + uint8_t gw = _ofont[_cfont].gw; + // in OSSD_ADDR_MODE_HOR/VER mode we set output region (gw x 16) + ossd_cmd_arg2(OSSD_SET_COL_ADDR, x, x + gw - 1); + ossd_cmd_arg2(OSSD_SET_PAGE_ADDR, line, line+1); + } +} + +void ossd_fill_screen(uint8_t data) +{ + // fill full screen line by line + for(uint8_t line = 0; line < 8; line++) { + ossd_goto(line, 0); + ossd_fill_line(data, 128); + } +} + +void ossd_sleep(uint8_t on_off) +{ + if (on_off) + ossd_cmd(OSSD_SET_SLEEP_ON); + else + ossd_cmd(OSSD_SET_SLEEP_OFF); +} + +void ossd_set_contrast(uint8_t val) +{ + ossd_cmd_arg(OSSD_SET_CONTRAST, val); +} + +static void ossd_put_centre(uint8_t line, const char *str, uint8_t atr) +{ + uint16_t len; + uint8_t x = 0; + uint8_t gw = _ofont[_cfont].gw; + uint8_t gh = _ofont[_cfont].gh; + for(len = 0; str[x]; len+=gw, x++); + if (len > 128) + x = 0; + else + x = (128 - len) / 2; + + // in case if new text is shorter than previous one + // we clean line up to x position + if (x) { + for(uint8_t i = 0; i < (gh+7)/8; i++) { + ossd_goto(line + i, 0); + ossd_fill_line(0, x); + } + } + + // recursive call of ossd_putlx() + ossd_putlx(line, x, str, atr); + + // in case if new text is shorter than previous one + // we clean to the end of the line + if (x) { + for(uint8_t i = 0; i < (gh+7)/8; i++) { + ossd_goto(line + i, x + len); + ossd_fill_line(0, x); + } + } +} + +void ossd_putlx(uint8_t line, int8_t x, const char *str, uint8_t atr) +{ + line &= 0x07; + + // try to put this text in the middle of the line: + // ossd_put_centre() will calculate proper x coordinate + if (x < 0) { + ossd_put_centre(line, str, atr); + return; + } + + uint8_t rev = 0; + uint8_t over = 0; + uint8_t under = 0; + if (atr & OSSD_TEXT_REVERSE) + rev = ~rev; + if (atr & OSSD_TEXT_OVERLINE) + over = 0x01; + if (atr & OSSD_TEXT_UNDERLINE) + under = 0x80; + + uint8_t gw = _ofont[_cfont].gw; + uint8_t gh = _ofont[_cfont].gh; + uint8_t go = _ofont[_cfont].go; + const uint8_t *font = _ofont[_cfont].font; + uint8_t cmode = ossd_set_addr_mode(OSSD_ADDR_MODE_HOR); + for(; *str != '\0'; str++, x += gw) { + uint16_t idx = (*str - go) * gh; + if ((uint8_t)x > (128 - gw)) { + x = 0; + line = (line + (gh+7)/8) & 0x07; + } + ossd_goto(line, x); + for(uint8_t i = 0; i < gh; i++) { + uint8_t d = pgm_read_byte(&font[idx+i]); + d ^= rev; + if (under && (gh == 8 || i > (gw - 1))) + d ^= under; + if (i < gw) + d ^= over; + ossd_data(d); + } + } + ossd_set_addr_mode(cmode); +} + +void ossd_init(uint8_t orientation) +{ + _mode = 0xFF; + // set all default values + ossd_cmd(OSSD_SET_SLEEP_ON); + ossd_cmd_arg(OSSD_SET_MUX_RATIO, 63); + ossd_cmd_arg(OSSD_SET_DISP_OFFSET, 0); + ossd_cmd(OSSD_SET_START_LINE | 0); + ossd_cmd(OSSD_SET_SEG_REMAP | (orientation & OSSD_SEG_REMAP_R2L)); + ossd_cmd(OSSD_SET_COM_DIR | (orientation & OSSD_COM_DIR_UPDOWN)); + ossd_cmd_arg(OSSD_SET_COM_CONFIG, OSSD_COM_ALT); + ossd_cmd_arg(OSSD_SET_CONTRAST, 0x7F); + ossd_cmd(OSSD_SET_OUTPUT_RAM); + ossd_cmd_arg(OSSD_SET_DISP_CLOCK, 0x80); + ossd_cmd_arg(OSSD_SET_PRECHARGE, 0x22); + ossd_cmd_arg(OSSD_SET_VCOMH_LEVEL, OSSD_VCOMH_L077); + ossd_cmd(OSSD_SET_INVERSE_OFF); + ossd_cmd_arg(OSSD_SET_CHARGE_PUMP, OSSD_CHARGE_PUMP_ON); + ossd_set_addr_mode(OSSD_ADDR_MODE_PAGE); + ossd_fill_screen(0); + ossd_cmd(OSSD_SET_SLEEP_OFF); + ossd_goto(0, 0); +} diff --git a/ossd_i2c.h b/ossd_i2c.h new file mode 100644 index 0000000..747528f --- /dev/null +++ b/ossd_i2c.h @@ -0,0 +1,122 @@ +/* BSD License + Copyright (c) 2014 Andrey Chilikin https://github.com/achilikin + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef __OLED_SSD1306_I2C__ +#define __OLED_SSD1306_I2C__ + +/** + Limited set of functions for SSD1306 compatible OLED displays in text mode + to minimize memory footprint if used on Atmel AVRs with low memory. +*/ + +#ifdef __cplusplus +extern "C" { +#if 0 +} // dummy bracket for Visual Assist +#endif +#endif + +/** Target platform */ +#define OSSD_AVR 1 /*< AVR compiler */ +#define OSSD_RPI 2 /*< Raspberry Pi */ +#define OSSD_GALILEO 3 /*< Reserved for Intel Galileo */ + +#ifdef __AVR_ARCH__ + #define OSSD_TARGET OSSD_AVR +#else + #define OSSD_TARGET OSSD_RPI +#endif + +#if (OSSD_TARGET == OSSD_AVR) + #define I2C_OSSD (0x3C << 1) +#else + #include +#endif + +#define OSSD_FONT_8x8 0 +#define OSSD_FONT_8x16 1 +#define OSSD_FONT_USER 2 +#define OSSD_FONT_MAX OSSD_FONT_USER + +typedef struct ossd_font_s +{ + uint8_t gw; /*< glyph width */ + uint8_t gh; /*< glyph height */ + uint8_t go; /*< font offset, first glyph index */ + uint8_t gn; /*< number of glyphs presented */ + const uint8_t *font; +} ossd_font_t; + +/** + flat cable connected at the top + use ossd_init(OSSD_UPDOWN) to rotate screen + */ +#define OSSD_UPDOWN 0x09 + +/** set default parameters */ +void ossd_init(uint8_t orientation); + +/** fill screen with specified pattern */ +void ossd_fill_screen(uint8_t data); + +/** set display to sleep mode */ +void ossd_sleep(uint8_t on_off); + +/** set display contrast */ +void ossd_set_contrast(uint8_t val); + +/** select one of three fonts for following ossd_putlx() calls */ +uint8_t ossd_select_font(uint8_t font); + +/** + set user font selectable by OSSD_FONT_USER to nfont + store current user font in ofont (if not NULL) + */ +void ossd_set_user_font(ossd_font_t *nfont, ossd_font_t *ofont); + +/** text attributes */ +#define OSSD_TEXT_REVERSE 0x01 +#define OSSD_TEXT_UNDERLINE 0x02 +#define OSSD_TEXT_OVERLINE 0x04 + +/** + output string up to 64 chars in length + line: 0-7 + x: 0-127, or -1 for centre of the line + str: output string + atr: OSSD_TEXT_* + */ +void ossd_putlx(uint8_t line, int8_t x, const char *str, uint8_t atr); + +/** void screen */ +static inline void ossd_cls(void) { + ossd_fill_screen(0); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pi2c.c b/pi2c.c new file mode 100644 index 0000000..518af4c --- /dev/null +++ b/pi2c.c @@ -0,0 +1,102 @@ +/* BSD License + Copyright (c) 2014 Andrey Chilikin https://github.com/achilikin + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + Basic I2C wrapper for Raspberry Pi, only write is supported. + + Make sure that RPi i2c driver is enabled, check following files: + /etc/modprobe.d/raspi-blacklist.conf + #blacklist i2c-bcm2708 + /etc/modules + i2c-dev + /etc/modprobe.d/i2c.conf + options i2c_bcm2708 baudrate=400000 +*/ +#include +#include +#include +#include +#include + +#include "pi2c.h" + +/** i2c bus file descriptors */ +static int i2c_bus[2] = { -1, -1 }; + +/** open I2C bus if not opened yet and store file descriptor */ +int pi2c_open(uint8_t bus) +{ + char bus_name[64]; + + if (bus > PI2C_BUS1) + return -1; + + // already opened? + if (i2c_bus[bus] >= 0) + return 0; + + // open i2c bus and store file descriptor + sprintf(bus_name, "/dev/i2c-%u", bus); + + if ((i2c_bus[bus] = open(bus_name, O_RDWR)) < 0) + return -1; + + return 0; +} + +/** close I2C bus file descriptor */ +int pi2c_close(uint8_t bus) +{ + if (bus > PI2C_BUS1) + return -1; + + if (i2c_bus[bus] >= 0) + close(i2c_bus[bus]); + i2c_bus[bus] = -1; + + return 0; +} + +/** select I2C device for pi2c_write() calls */ +int pi2c_select(uint8_t bus, uint8_t slave) +{ + if ((bus > PI2C_BUS1) || (i2c_bus[bus] < 0)) + return -1; + + return ioctl(i2c_bus[bus], I2C_SLAVE, slave); +} + +/** write to I2C device selected by pi2c_select() */ +int pi2c_write(uint8_t bus, const uint8_t *data, uint32_t len) +{ + if ((bus > PI2C_BUS1) || (i2c_bus[bus] < 0)) + return -1; + + if (write(i2c_bus[bus], data, len) != (ssize_t)len) + return -1; + + return 0; +} diff --git a/pi2c.h b/pi2c.h new file mode 100644 index 0000000..50d0691 --- /dev/null +++ b/pi2c.h @@ -0,0 +1,61 @@ +/* BSD License + Copyright (c) 2014 Andrey Chilikin https://github.com/achilikin + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + Basic I2C wrapper for Raspberry Pi, only write is supported. + + Make sure that RPi i2c driver is enabled, check following files: + /etc/modprobe.d/raspi-blacklist.conf + #blacklist i2c-bcm2708 + /etc/modules + i2c-dev + /etc/modprobe.d/i2c.conf + options i2c_bcm2708 baudrate=400000 +*/ + +#ifndef __PI2C_H__ +#define __PI2C_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PI2C_BUS0 0 /*< P5 header I2C bus */ +#define PI2C_BUS1 1 /*< P1 header I2C bus */ +#define PI2C_BUS PI2C_BUS1 // default bus + +int pi2c_open(uint8_t bus); /*< open I2C bus */ +int pi2c_close(uint8_t bus); /*< close I2C bus */ +int pi2c_select(uint8_t bus, uint8_t slave); /*< select I2C slave */ +int pi2c_write(uint8_t bus, const uint8_t *data, uint32_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rterm.c b/rterm.c new file mode 100644 index 0000000..4414d56 --- /dev/null +++ b/rterm.c @@ -0,0 +1,90 @@ +/* BSD License + Copyright (c) 2014 Andrey Chilikin https://github.com/achilikin + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + Sets stdin to raw mode so read() can get chars one by one + without waiting for the Enter +*/ +#include +#include +#include +#include +#include +#include + +#include "rterm.h" + +static int restore = 0; + +/** restore canonical mode ar exit */ +static void mode_restore_proc(void) +{ + stdin_mode(TERM_MODE_CAN); +} + +/** set terminal mode: RAW or CANonical */ +int stdin_mode(int mode) +{ + struct termios term_attr; + + tcgetattr(STDIN_FILENO, &term_attr); + /* set the terminal to raw mode */ + if (mode == TERM_MODE_RAW) { + term_attr.c_lflag &= ~(ECHO | ICANON); + term_attr.c_cc[VMIN] = 0; + if (!restore) { + restore++; + atexit(mode_restore_proc); + } + } + else { + term_attr.c_lflag |= (ECHO | ICANON); + term_attr.c_cc[VMIN] = 1; + } + tcsetattr(STDIN_FILENO, TCSANOW, &term_attr); + + return mode; +} + +/** read stdin with timeout in ms, or -1 until a key is pressed */ +int stdin_getch(int timeout) +{ + struct pollfd polls; + polls.fd = STDIN_FILENO; + polls.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; + polls.revents = 0; + + if (poll(&polls, 1, timeout) < 0) + return -1; + + int ch = 0; + if (polls.revents) { + if (read(STDIN_FILENO, &ch, 1) < 0) + return -1; + } + + return ch; +} diff --git a/rterm.h b/rterm.h new file mode 100644 index 0000000..d73f042 --- /dev/null +++ b/rterm.h @@ -0,0 +1,42 @@ +/* BSD License + Copyright (c) 2014 Andrey Chilikin https://github.com/achilikin + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + Sets stdin to raw mode so read() can get chars one by one + without waiting for the Enter +*/ +#ifndef __RAW_STDIN_TERM_H__ +#define __RAW_STDIN_TERM_H__ + +#define TERM_MODE_CAN 0 /*< canonical terminal mode */ +#define TERM_MODE_RAW 1 /*< raw terminal mode */ + +/** set terminal mode: RAW or CANonical */ +int stdin_mode(int mode); +/** read stdin with timeout in ms, or -1 until a key is pressed */ +int stdin_getch(int timeout); + +#endif