From 37d3acaa622b7f695ce57578e56311d031a22d22 Mon Sep 17 00:00:00 2001 From: bernie Date: Sun, 23 May 2004 15:43:16 +0000 Subject: [PATCH] Import mware modules. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1 38d2e660-2303-0410-9eaa-f027e97ec537 --- mware/fifobuf.c | 137 ++++++++ mware/fifobuf.h | 172 +++++++++ mware/font.c | 330 ++++++++++++++++++ mware/font.h | 39 +++ mware/formatwr.c | 827 ++++++++++++++++++++++++++++++++++++++++++++ mware/formatwr.h | 40 +++ mware/gfx.c | 404 ++++++++++++++++++++++ mware/gfx.h | 91 +++++ mware/list.c | 49 +++ mware/list.h | 122 +++++++ mware/sprintf.c | 86 +++++ mware/text.c | 257 ++++++++++++++ mware/text.h | 98 ++++++ mware/text_format.c | 110 ++++++ 14 files changed, 2762 insertions(+) create mode 100755 mware/fifobuf.c create mode 100755 mware/fifobuf.h create mode 100755 mware/font.c create mode 100755 mware/font.h create mode 100755 mware/formatwr.c create mode 100755 mware/formatwr.h create mode 100755 mware/gfx.c create mode 100755 mware/gfx.h create mode 100755 mware/list.c create mode 100755 mware/list.h create mode 100755 mware/sprintf.c create mode 100755 mware/text.c create mode 100755 mware/text.h create mode 100755 mware/text_format.c diff --git a/mware/fifobuf.c b/mware/fifobuf.c new file mode 100755 index 00000000..6f6340e6 --- /dev/null +++ b/mware/fifobuf.c @@ -0,0 +1,137 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \author Bernardo Innocenti + * + * \brief FIFO buffer handling routines + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + */ + +#include "fifobuf.h" +#include "compiler.h" +#include + +void fifo_init(volatile FIFOBuffer *fb, unsigned char *buf, size_t size) +{ + fb->head = fb->tail = fb->begin = buf; + fb->end = buf + size - 1; +} + + +/*! + * Pop a character from the fifo buffer. + * + * \note Calling \c fifo_push() on a full buffer is undefined. + * The caller must make sure the buffer has at least + * one free slot before calling this function. + * + * \note It is safe to call fifo_pop() and fifo_push() from + * concurrent contexts. + */ +void fifo_push(volatile FIFOBuffer *fb, unsigned char c) +{ +#pragma interrupt called + /* Write at tail position */ + *(fb->tail) = c; + + if (fb->tail == fb->end) + /* wrap tail around */ + fb->tail = fb->begin; + else + /* Move tail forward */ + fb->tail++; +} + +/*! + * Pop a character from the fifo buffer. + * + * \note Calling \c fifo_pop() on an empty buffer is undefined. + * The caller must make sure the buffer contains at least + * one character before calling this function. + * + * \note It is safe to call fifo_pop() and fifo_push() from + * concurrent contexts. + */ +unsigned char fifo_pop(volatile FIFOBuffer *fb) +{ +#pragma interrupt called + if (fb->head == fb->end) + { + /* wrap head around */ + fb->head = fb->begin; + return *(fb->end); + } + else + /* move head forward */ + return *(fb->head++); +} + + +#if 0 + +/* untested */ +void fifo_pushblock(volatile FIFOBuffer *fb, unsigned char *block, size_t len) +{ + size_t freelen; + + /* Se c'e' spazio da tail alla fine del buffer */ + if (fb->tail >= fb->head) + { + freelen = fb->end - fb->tail + 1; + + /* C'e' abbastanza spazio per scrivere tutto il blocco? */ + if (freelen < len) + { + /* Scrivi quello che entra fino alla fine del buffer */ + memcpy(fb->tail, block, freelen); + block += freelen; + len -= freelen; + fb->tail = fb->begin; + } + else + { + /* Scrivi tutto il blocco */ + memcpy(fb->tail, block, len); + fb->tail += len; + return; + } + } + + for(;;) + { + while (!(freelen = fb->head - fb->tail - 1)) + Delay(FIFO_POLLDELAY); + + /* C'e' abbastanza spazio per scrivere tutto il blocco? */ + if (freelen < len) + { + /* Scrivi quello che entra fino alla fine del buffer */ + memcpy(fb->tail, block, freelen); + block += freelen; + len -= freelen; + fb->tail += freelen; + } + else + { + /* Scrivi tutto il blocco */ + memcpy(fb->tail, block, len); + fb->tail += len; + return; + } + } +} + +#endif /* UNUSED */ diff --git a/mware/fifobuf.h b/mware/fifobuf.h new file mode 100755 index 00000000..1cbd89d4 --- /dev/null +++ b/mware/fifobuf.h @@ -0,0 +1,172 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \author Bernardo Innocenti + * + * \brief General pourpose FIFO buffer implemented with a ring buffer + * + * \li \c begin punta al primo elemento del buffer, + * \li \c end punta all'ultimo elemento, + * \li \c head punta al prossimo elemento che verra' estratto, + * \li \c tail punta alla posizione successiva all'ultimo elemento inserito. + * \li quando uno dei due puntatori raggiunge @c end, viene resettato a @c begin. + * + *
+ *
+ *  +-----------------------------------+
+ *  |  vuoto  |   dati validi  |  vuoto |
+ *  +-----------------------------------+
+ *  ^         ^                ^        ^
+ *  begin    head             tail     end
+ *
+ * 
+ * + * Il buffer e' VUOTO quando head e tail coincidono: + * \code head == tail \endcode + * + * Il buffer e' PIENO quando tail si trova immediatamente dietro a head: + * \code tail == head - 1 \endcode + * + * Il buffer e' PIENO anche quando tail e' posizionato + * sull'ultima posizione del buffer e head sulla prima: + * \code head == begin && tail == end \endcode + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + * Revision 1.3 2004/05/22 17:55:58 rasky + * \samp non esiste in doxygen + * + * Revision 1.2 2004/04/27 11:13:29 rasky + * Spostate tutte le definizioni CPU-specific da compiler.h nel nuovo file cpu.h + * + * Revision 1.1 2004/04/21 17:38:25 rasky + * New application + * + * Revision 1.4 2004/03/24 15:37:03 bernie + * Remove Copyright messages from Doxygen output + * + * Revision 1.3 2004/03/18 18:11:07 bernie + * Add thread-safe FIFO handling macros + * + * Revision 1.2 2004/03/01 08:00:36 bernie + * Fixes for Doxygen + * + * Revision 1.1 2003/12/07 04:04:20 bernie + * Initial project_ks framework. + * + * Revision 1.1 2003/11/21 16:36:17 aleph + * Rename from fifo to fifobuf to avoid conflict with BSP fifo.h header + * + * Revision 1.1 2003/11/20 22:17:41 aleph + * Add fifo buffer used by serial + * + */ + +#ifndef MWARE_FIFO_H +#define MWARE_FIFO_H + +#include "cpu.h" +#ifndef COMPILER_H +#include "compiler.h" +#endif + +typedef struct FIFOBuffer +{ + unsigned char *head; + unsigned char *tail; + unsigned char *begin; + unsigned char *end; +} FIFOBuffer; + +/* Public function prototypes */ +void fifo_init(volatile FIFOBuffer *fb, unsigned char *buf, size_t size); + +#pragma interrupt called +void fifo_push(volatile FIFOBuffer *fb, unsigned char c); + +#pragma interrupt called +unsigned char fifo_pop(volatile FIFOBuffer *fb); + + +/*! + * Check whether the fifo is empty + * + * \note Calling fifo_isempty() is safe while a concurrent + * execution context is calling fifo_push() or fifo_pop() + * only if the CPU can atomically update a pointer. + */ +#define fifo_isempty(fb) ((fb)->head == (fb)->tail) + +/*! + * Check whether the fifo is full + * + * \note Calling fifo_isfull() is safe while a concurrent + * execution context is calling fifo_pop() and the + * CPU can update a pointer atomically. + * It is NOT safe when the other context calls + * fifo_push(). + * This limitation is not usually problematic in a + * consumer/producer scenario because the + * fifo_isfull() and fifo_push() are usually called + * in the producer context. + */ +#define fifo_isfull(fb) \ + ((((fb)->head == (fb)->begin) && ((fb)->tail == (fb)->end)) \ + || ((fb)->tail == (fb)->head - 1)) + +/*! + * Make the fifo empty, discarding all its current contents. + */ +#define fifo_flush(fb) ((fb)->head = (fb)->tail) + +#if !defined(__AVR__) + + /* No tricks needed on 16/32bit CPUs */ +# define fifo_isempty_locked(fb) fifo_isempty((fb)) + +#else /* !__AVR__ */ + + INLINE bool fifo_isempty_locked(const volatile FIFOBuffer *_fb); + INLINE bool fifo_isempty_locked(const volatile FIFOBuffer *_fb) + { + bool _result; + cpuflags_t _flags; + + DISABLE_IRQSAVE(_flags); + _result = fifo_isempty(_fb); + ENABLE_IRQRESTORE(_flags); + + return _result; + } + +#endif /* !__AVR__ */ + +/*! + * Thread safe version of fifo_isfull() + */ +INLINE bool fifo_isfull_locked(const volatile FIFOBuffer *_fb); +INLINE bool fifo_isfull_locked(const volatile FIFOBuffer *_fb) +{ + bool _result; + cpuflags_t _flags; + + DISABLE_IRQSAVE(_flags); + _result = fifo_isfull(_fb); + ENABLE_IRQRESTORE(_flags); + + return _result; +} + +#endif /* MWARE_FIFOBUF_H */ + diff --git a/mware/font.c b/mware/font.c new file mode 100755 index 00000000..58e00e03 --- /dev/null +++ b/mware/font.c @@ -0,0 +1,330 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \author Bernardo Innocenti + * + * \brief Font 8x6 IBM-PC 8bit + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + * Revision 1.5 2004/03/24 15:48:53 bernie + * Remove Copyright messages from Doxygen output + * + * Revision 1.4 2004/03/03 18:30:17 bernie + * Substitute left triangle glyph with left arrow + * + * Revision 1.3 2004/02/28 14:48:33 aleph + * Improve arrow glyphs + * + * Revision 1.2 2004/01/13 12:15:28 aleph + * Move font table in program memory; add font.h + * + * Revision 1.1 2004/01/07 23:31:54 aleph + * Add text routines + * + */ + +#include "font.h" + +const prog_uchar font[256 * 6] = +{ +/* 0x00 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* */ + 0x3E, 0x45, 0x51, 0x45, 0x3E, 0x00, /* */ + 0x3E, 0x7B, 0x6F, 0x7B, 0x3E, 0x00, /* */ + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00, /* */ + 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, /* */ + 0x18, 0x5A, 0x67, 0x5A, 0x18, 0x00, /* */ + 0x0C, 0x5E, 0x6F, 0x5E, 0x0C, 0x00, /* */ + 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, /* */ +/* 0x08 */ + 0x77, 0x63, 0x41, 0x63, 0x77, 0x00, /* */ + 0x18, 0x3C, 0x66, 0x3C, 0x18, 0x00, /* */ + 0x77, 0x63, 0x41, 0x63, 0x77, 0x00, /* */ + 0x20, 0x50, 0x5A, 0x56, 0x2E, 0x00, /* */ + 0x06, 0x29, 0x79, 0x29, 0x06, 0x00, /* */ + 0x60, 0x60, 0x7F, 0x05, 0x07, 0x00, /* */ + 0x18, 0x1F, 0x01, 0x61, 0x7F, 0x00, /* */ + 0x15, 0x0E, 0x1B, 0x0E, 0x15, 0x00, /* */ +/* 0x10 */ + 0x00, 0x08, 0x1C, 0x3E, 0x08, 0x08, /* */ + 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x00, /* */ + 0x14, 0x36, 0x7F, 0x36, 0x14, 0x00, /* */ + 0x00, 0x5F, 0x00, 0x5F, 0x00, 0x00, /* */ + 0x02, 0x05, 0x7F, 0x01, 0x7F, 0x00, /* */ + 0x20, 0x4A, 0x55, 0x29, 0x02, 0x00, /* */ + 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, /* */ + 0x54, 0x76, 0x7F, 0x76, 0x54, 0x00, /* */ +/* 0x18 */ + 0x08, 0x0C, 0x7E, 0x0C, 0x08, 0x00, /* */ + 0x10, 0x30, 0x7E, 0x30, 0x10, 0x00, /* */ + 0x08, 0x08, 0x3E, 0x1C, 0x08, 0x00, /* */ + 0x08, 0x1C, 0x3E, 0x08, 0x08, 0x00, /* */ + 0x1C, 0x10, 0x10, 0x10, 0x10, 0x00, /* */ + 0x08, 0x1C, 0x08, 0x1C, 0x08, 0x00, /* */ + 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x00, /* */ + 0x0C, 0x1C, 0x3C, 0x1C, 0x0C, 0x00, /* */ +/* 0x20 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* */ + 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, /* ! */ + 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, /* " */ + 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, /* # */ + 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, /* $ */ + 0x63, 0x13, 0x08, 0x64, 0x63, 0x00, /* % */ + 0x36, 0x49, 0x55, 0x22, 0x50, 0x00, /* & */ + 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, /* ' */ +/* 0x28 */ + 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, /* ( */ + 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, /* ) */ + 0x14, 0x08, 0x3E, 0x08, 0x14, 0x00, /* * */ + 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, /* + */ + 0x00, 0x50, 0x30, 0x00, 0x00, 0x00, /* , */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, /* - */ + 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, /* . */ + 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, /* / */ +/* 0x30 */ + 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, /* 0 */ + 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, /* 1 */ + 0x62, 0x51, 0x49, 0x49, 0x46, 0x00, /* 2 */ + 0x21, 0x41, 0x45, 0x4B, 0x31, 0x00, /* 3 */ + 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, /* 4 */ + 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, /* 5 */ + 0x3C, 0x4A, 0x49, 0x49, 0x30, 0x00, /* 6 */ + 0x01, 0x71, 0x09, 0x05, 0x03, 0x00, /* 7 */ +/* 0x38 */ + 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, /* 8 */ + 0x06, 0x49, 0x49, 0x29, 0x1E, 0x00, /* 9 */ + 0x00, 0x36, 0x36, 0x00, 0x00, 0x00, /* : */ + 0x00, 0x56, 0x36, 0x00, 0x00, 0x00, /* ; */ + 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, /* < */ + 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, /* = */ + 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, /* > */ + 0x02, 0x01, 0x51, 0x09, 0x06, 0x00, /* ? */ +/* 0x40 */ + 0x32, 0x49, 0x79, 0x41, 0x3E, 0x00, /* @ */ + 0x7E, 0x09, 0x09, 0x09, 0x7E, 0x00, /* A */ + 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, /* B */ + 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, /* C */ + 0x7F, 0x41, 0x41, 0x22, 0x1C, 0x00, /* D */ + 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, /* E */ + 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, /* F */ + 0x3E, 0x41, 0x49, 0x49, 0x7A, 0x00, /* G */ +/* 0x48 */ + 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, /* H */ + 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, /* I */ + 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, /* J */ + 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, /* K */ + 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, /* L */ + 0x7F, 0x02, 0x0C, 0x02, 0x7F, 0x00, /* M */ + 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, /* N */ + 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, /* O */ +/* 0x50 */ + 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, /* P */ + 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, /* Q */ + 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, /* R */ + 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, /* S */ + 0x01, 0x01, 0x7F, 0x01, 0x01, 0x00, /* T */ + 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, /* U */ + 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, /* V */ + 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, /* W */ +/* 0x58 */ + 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, /* X */ + 0x07, 0x08, 0x70, 0x08, 0x07, 0x00, /* Y */ + 0x61, 0x51, 0x49, 0x45, 0x43, 0x00, /* Z */ + 0x00, 0x7F, 0x41, 0x41, 0x00, 0x00, /* [ */ + 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, /* \ */ + 0x00, 0x41, 0x41, 0x7F, 0x00, 0x00, /* ] */ + 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, /* ^ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, /* _ */ +/* 0x60 */ + 0x00, 0x01, 0x02, 0x04, 0x00, 0x00, /* ` */ + 0x00, 0x74, 0x54, 0x54, 0x78, 0x00, /* a */ + 0x7F, 0x44, 0x44, 0x44, 0x38, 0x00, /* b */ + 0x38, 0x44, 0x44, 0x44, 0x28, 0x00, /* c */ + 0x38, 0x44, 0x44, 0x44, 0x7F, 0x00, /* d */ + 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, /* e */ + 0x08, 0x7E, 0x09, 0x01, 0x02, 0x00, /* f */ + 0x08, 0x54, 0x54, 0x54, 0x3C, 0x00, /* g */ +/* 0x68 */ + 0x7F, 0x04, 0x04, 0x04, 0x78, 0x00, /* h */ + 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, /* i */ + 0x20, 0x40, 0x44, 0x3D, 0x00, 0x00, /* j */ + 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, /* k */ + 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, /* l */ + 0x7C, 0x04, 0x18, 0x04, 0x78, 0x00, /* m */ + 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, /* n */ + 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, /* o */ +/* 0x70 */ + 0x7C, 0x14, 0x14, 0x14, 0x08, 0x00, /* p */ + 0x08, 0x14, 0x14, 0x14, 0x7C, 0x00, /* q */ + 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, /* r */ + 0x48, 0x54, 0x54, 0x54, 0x24, 0x00, /* s */ + 0x04, 0x3F, 0x44, 0x40, 0x20, 0x00, /* t */ + 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, /* u */ + 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, /* v */ + 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, /* w */ +/* 0x78 */ + 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, /* x */ + 0x0C, 0x50, 0x50, 0x50, 0x3C, 0x00, /* y */ + 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, /* z */ + 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, /* { */ + 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, /* | */ + 0x00, 0x41, 0x36, 0x08, 0x00, 0x00, /* } */ + 0x02, 0x01, 0x02, 0x01, 0x00, 0x00, /* ~ */ + 0x70, 0x48, 0x44, 0x48, 0x70, 0x00, /*  */ +/* 0x80 */ + 0x38, 0xC4, 0xC4, 0x44, 0x28, 0x00, /* € */ + 0x3A, 0x40, 0x40, 0x20, 0x7A, 0x00, /*  */ + 0x38, 0x54, 0x54, 0x55, 0x19, 0x00, /* ‚ */ + 0x22, 0x55, 0x55, 0x55, 0x78, 0x00, /* ƒ */ + 0x20, 0x55, 0x54, 0x54, 0x79, 0x00, /* „ */ + 0x21, 0x75, 0x55, 0x54, 0x78, 0x00, /* … */ + 0x20, 0x74, 0x57, 0x54, 0x78, 0x00, /* † */ + 0x08, 0x54, 0x54, 0x74, 0x14, 0x00, /* ‡ */ +/* 0x88 */ + 0x3A, 0x55, 0x55, 0x55, 0x1A, 0x00, /* ˆ */ + 0x39, 0x54, 0x54, 0x55, 0x18, 0x00, /* ‰ */ + 0x39, 0x55, 0x55, 0x54, 0x18, 0x00, /* Š */ + 0x00, 0x45, 0x7C, 0x41, 0x00, 0x00, /* ‹ */ + 0x02, 0x45, 0x7D, 0x42, 0x00, 0x00, /* Œ */ + 0x01, 0x45, 0x7D, 0x40, 0x00, 0x00, /*  */ + 0x79, 0x14, 0x12, 0x14, 0x79, 0x00, /* Ž */ + 0x70, 0x2B, 0x2B, 0x2B, 0x70, 0x00, /*  */ +/* 0x90 */ + 0x7C, 0x54, 0x55, 0x55, 0x45, 0x00, /*  */ + 0x20, 0x54, 0x38, 0x54, 0x48, 0x00, /* ‘ */ + 0x7E, 0x09, 0x7F, 0x49, 0x49, 0x00, /* ’ */ + 0x32, 0x49, 0x49, 0x49, 0x32, 0x00, /* “ */ + 0x32, 0x48, 0x48, 0x48, 0x32, 0x00, /* ” */ + 0x32, 0x4A, 0x4A, 0x48, 0x30, 0x00, /* • */ + 0x3A, 0x41, 0x41, 0x21, 0x7A, 0x00, /* – */ + 0x3A, 0x42, 0x42, 0x20, 0x78, 0x00, /* — */ +/* 0x98 */ + 0x0D, 0x50, 0x50, 0x50, 0x3D, 0x00, /* ˜ */ + 0x19, 0x24, 0x42, 0x24, 0x19, 0x00, /* ™ */ + 0x3D, 0x40, 0x40, 0x40, 0x3D, 0x00, /* š */ + 0x18, 0x24, 0x7E, 0x24, 0x24, 0x00, /* › */ + 0x28, 0x5E, 0x29, 0x42, 0x20, 0x00, /* œ */ + 0x09, 0x2A, 0x7C, 0x2A, 0x09, 0x00, /*  */ + 0x7F, 0x05, 0x15, 0x3D, 0x52, 0x00, /* ž */ + 0x20, 0x48, 0x3E, 0x09, 0x02, 0x00, /* Ÿ */ +/* 0xa0 */ + 0x20, 0x74, 0x55, 0x55, 0x79, 0x00, /*   */ + 0x01, 0x45, 0x7D, 0x40, 0x00, 0x00, /* ¡ */ + 0x30, 0x48, 0x4A, 0x4A, 0x32, 0x00, /* ¢ */ + 0x38, 0x40, 0x42, 0x22, 0x7A, 0x00, /* £ */ + 0x7A, 0x12, 0x0A, 0x0A, 0x72, 0x00, /* ¤ */ + 0x7D, 0x09, 0x11, 0x21, 0x7D, 0x00, /* ¥ */ + 0x02, 0x15, 0x15, 0x12, 0x04, 0x00, /* ¦ */ + 0x02, 0x15, 0x15, 0x15, 0x02, 0x00, /* § */ +/* 0xa8 */ + 0x30, 0x48, 0x45, 0x40, 0x20, 0x00, /* ¨ */ + 0x00, 0x38, 0x08, 0x08, 0x08, 0x00, /* © */ + 0x00, 0x08, 0x08, 0x08, 0x38, 0x00, /* ª */ + 0x0B, 0x04, 0x6A, 0x55, 0x48, 0x00, /* « */ + 0x0B, 0x24, 0x32, 0x79, 0x20, 0x00, /* ¬ */ + 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, /* ­ */ + 0x08, 0x14, 0x2A, 0x14, 0x22, 0x00, /* ® */ + 0x22, 0x14, 0x2A, 0x14, 0x08, 0x00, /* ¯ */ +/* 0xb0 */ + 0x2A, 0x55, 0x00, 0x2A, 0x55, 0x00, /* ° */ + 0x2A, 0x55, 0x2A, 0x55, 0x2A, 0x55, /* ± */ + 0x55, 0x2A, 0x7F, 0x55, 0x2A, 0x7F, /* ² */ + 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, /* ³ */ + 0x08, 0x08, 0xFF, 0x00, 0x00, 0x00, /* ´ */ + 0x14, 0x14, 0xFF, 0x00, 0x00, 0x00, /* µ */ + 0x08, 0xFF, 0x00, 0xFF, 0x00, 0x00, /* ¶ */ + 0x08, 0xF8, 0x08, 0xF8, 0x00, 0x00, /* · */ +/* 0xb8 */ + 0x14, 0x14, 0xFC, 0x00, 0x00, 0x00, /* ¸ */ + 0x14, 0xF7, 0x00, 0xFF, 0x00, 0x00, /* ¹ */ + 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, /* º */ + 0x14, 0xF4, 0x04, 0xFC, 0x00, 0x00, /* » */ + 0x14, 0x17, 0x10, 0x1F, 0x00, 0x00, /* ¼ */ + 0x08, 0x0F, 0x08, 0x0F, 0x00, 0x00, /* ½ */ + 0x14, 0x14, 0x1F, 0x00, 0x00, 0x00, /* ¾ */ + 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, /* ¿ */ +/* 0xc0 */ + 0x00, 0x00, 0x0F, 0x08, 0x08, 0x08, /* À */ + 0x08, 0x08, 0x0F, 0x08, 0x08, 0x08, /* Á */ + 0x08, 0x08, 0xF8, 0x08, 0x08, 0x08, /*  */ + 0x00, 0x00, 0xFF, 0x08, 0x08, 0x08, /* à */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* Ä */ + 0x08, 0x08, 0xFF, 0x08, 0x08, 0x08, /* Å */ + 0x00, 0x00, 0xFF, 0x14, 0x14, 0x14, /* Æ */ + 0x00, 0xFF, 0x00, 0xFF, 0x08, 0x08, /* Ç */ +/* 0xc8 */ + 0x00, 0x1F, 0x10, 0x17, 0x14, 0x14, /* È */ + 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14, /* É */ + 0x28, 0x2F, 0x20, 0x2F, 0x28, 0x28, /* Ê */ + 0x14, 0xF4, 0x04, 0xF4, 0x14, 0x14, /* Ë */ + 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14, /* Ì */ + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, /* Í */ + 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14, /* Î */ + 0x14, 0x14, 0xF7, 0x14, 0x14, 0x14, /* Ï */ +/* 0xd0 */ + 0x08, 0x0F, 0x08, 0x0F, 0x08, 0x08, /* Ð */ + 0x14, 0x14, 0xF4, 0x14, 0x14, 0x14, /* Ñ */ + 0x08, 0x08, 0xF8, 0x08, 0x08, 0x08, /* Ò */ + 0x08, 0x0F, 0x08, 0x0F, 0x08, 0x08, /* Ó */ + 0x00, 0x00, 0x1F, 0x14, 0x14, 0x14, /* Ô */ + 0x00, 0x00, 0xFC, 0x14, 0x14, 0x14, /* Õ */ + 0x00, 0xF8, 0x08, 0xF8, 0x08, 0x08, /* Ö */ + 0x08, 0xFF, 0x08, 0xFF, 0x08, 0x08, /* × */ +/* 0xd8 */ + 0x14, 0x14, 0xFF, 0x14, 0x14, 0x14, /* Ø */ + 0x08, 0x08, 0x0F, 0x00, 0x00, 0x00, /* Ù */ + 0x00, 0x00, 0xF8, 0x08, 0x08, 0x08, /* Ú */ + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, /* Û */ + 0x70, 0x70, 0x70, 0x70, 0x70, 0x00, /* Ü */ + 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, /* Ý */ + 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x00, /* Þ */ + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, /* ß */ +/* 0xe0 */ + 0x30, 0x48, 0x48, 0x30, 0x48, 0x00, /* à */ + 0x7E, 0x11, 0x25, 0x25, 0x1A, 0x00, /* á */ + 0x7E, 0x02, 0x02, 0x02, 0x06, 0x00, /* â */ + 0x04, 0x7C, 0x04, 0x7C, 0x04, 0x00, /* ã */ + 0x41, 0x63, 0x55, 0x49, 0x63, 0x00, /* ä */ + 0x3C, 0x42, 0x4A, 0x4A, 0x31, 0x00, /* å */ + 0x40, 0x7C, 0x20, 0x20, 0x1C, 0x00, /* æ */ + 0x08, 0x04, 0x7C, 0x08, 0x04, 0x00, /* ç */ +/* 0xe8 */ + 0x49, 0x55, 0x77, 0x55, 0x49, 0x00, /* è */ + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, 0x00, /* é */ + 0x4C, 0x72, 0x02, 0x72, 0x4C, 0x00, /* ê */ + 0x30, 0x4A, 0x45, 0x49, 0x31, 0x00, /* ë */ + 0x18, 0x24, 0x18, 0x24, 0x18, 0x00, /* ì */ + 0x5C, 0x72, 0x2A, 0x27, 0x1D, 0x00, /* í */ + 0x1C, 0x2A, 0x49, 0x49, 0x00, 0x00, /* î */ + 0x7E, 0x01, 0x01, 0x01, 0x7E, 0x00, /* ï */ +/* 0xf0 */ + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, /* ð */ + 0x24, 0x24, 0x2E, 0x24, 0x24, 0x00, /* ñ */ + 0x40, 0x51, 0x4A, 0x44, 0x00, 0x00, /* ò */ + 0x44, 0x4A, 0x51, 0x40, 0x00, 0x00, /* ó */ + 0x00, 0x00, 0xFE, 0x01, 0x02, 0x00, /* ô */ + 0x20, 0x40, 0x3F, 0x00, 0x00, 0x00, /* õ */ + 0x08, 0x08, 0x2A, 0x08, 0x08, 0x00, /* ö */ + 0x24, 0x12, 0x24, 0x12, 0x00, 0x00, /* ÷ */ +/* 0xf8 */ + 0x06, 0x09, 0x09, 0x09, 0x06, 0x00, /* ø */ + 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* ù */ + 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, /* ú */ + 0x10, 0x30, 0x7F, 0x01, 0x01, 0x00, /* û */ + 0x01, 0x0E, 0x01, 0x01, 0x0E, 0x00, /* ü */ + 0x0A, 0x09, 0x0D, 0x0A, 0x00, 0x00, /* ý */ + 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, /* þ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* ÿ */ +}; diff --git a/mware/font.h b/mware/font.h new file mode 100755 index 00000000..cf639365 --- /dev/null +++ b/mware/font.h @@ -0,0 +1,39 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \author Stefano Fedrigo + * + * \brief Font 8x6 IBM-PC 8bit + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + * Revision 1.2 2004/03/24 15:48:53 bernie + * Remove Copyright messages from Doxygen output + * + * Revision 1.1 2004/01/13 12:15:28 aleph + * Move font table in program memory; add font.h + * + */ +#ifndef FONT_H +#define FONT_H + +#include "avr/pgmspace.h" + +/* Font size (in pixel) */ +#define FONT_WIDTH 6 +#define FONT_HEIGHT 8 + +/*! Font table */ +extern const prog_uchar font[256 * FONT_WIDTH]; + +#endif /* FONT_H */ diff --git a/mware/formatwr.c b/mware/formatwr.c new file mode 100755 index 00000000..bd7b3c78 --- /dev/null +++ b/mware/formatwr.c @@ -0,0 +1,827 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \brief Basic "printf", "sprintf" and "fprintf" formatter. + * + * This module is 100% reentrant and can be adapted to user-defined routines + * that needs formatters with special properties like different output chann- + * els or new format specifiers. + * + * To reduce size in applications not using real numbers or long integers + * the formatter may be compiled to exclude certain parts. This is + * controlled by giving a -D option a compilation time. + * + * -DFLOAT_SUPPORT Full ANSI formatter + * -DNO_FLOATS Full ANSI except floats + * -DREDUCED_SUPPORT Reduced 'int' type of converter + * + * The reduced version of formatter is suitable when program size is critical + * rather than formatting power. This routine uses less than 20 bytes of + * stack space which makes it practical even in systems with less than 256 + * bytes of user RAM. + * + * The only formatting specifiers supported by the reduced formatter are: + * \code + * %% %c %s %d %o %x %X and %hd %ho %hx %hX %ld %lo %lx %lX + * \endcode + * + * It means that real variables are not supported as well as field + * width and precision arguments. + * + * The last eight (h and l modifiers) can easily be removed by + * removing the line "#define MODIFIERS_IN_REDUCED". + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + */ + +/* bernie */ +#define FLOAT_SUPPORT +#undef NO_FLOATS +#undef REDUCED_SUPPORT + +#ifndef FLOAT_SUPPORT +#ifndef NO_FLOATS +#ifndef REDUCED_SUPPORT +#error -DFLOAT_SUPPORT, -DNO_FLOATS or -DREDUCED_SUPPORT missing +#endif +#endif +#endif + +/* Make it easy for customers to disable h and l + modifiers in REDUCED_SUPPORT by removing the next #define */ +#define MODIFIERS_IN_REDUCED + +#include "formatwr.h" +#include "compiler.h" /* progmem macros */ +#include + +#ifndef FRMWRI_BUFSIZE +/*bernie: save some memory, who cares about floats with lots of decimals? */ +/*#define FRMWRI_BUFSIZE 134*/ +#define FRMWRI_BUFSIZE 32 +#endif + +#ifndef MEM_ATTRIBUTE +#define MEM_ATTRIBUTE +#endif + +#ifdef MODIFIERS_IN_REDUCED +#define IS_SHORT (h_modifier || (sizeof(int) == 2 && !l_modifier)) +#else +#define IS_SHORT (sizeof(int) == 2) +#endif + + +#ifdef FLOAT_SUPPORT + +static char *float_conversion(MEM_ATTRIBUTE long double value, + MEM_ATTRIBUTE short nr_of_digits, + MEM_ATTRIBUTE char *buf, + MEM_ATTRIBUTE char format_flag, + MEM_ATTRIBUTE char g_flag, + MEM_ATTRIBUTE char alternate_flag) +{ + MEM_ATTRIBUTE char *cp; + MEM_ATTRIBUTE char *buf_pointer; + MEM_ATTRIBUTE short n, i, dec_point_pos, integral_10_log; + + buf_pointer = buf; + integral_10_log = 0; + + if (value >= 1) + { + while (value >= 1e11) /* To speed up things a bit */ + { + value /= 1e10; + integral_10_log += 10; + } + while (value >= 10) + { + value /= 10; + integral_10_log++; + } + } + else if (value) /* Not just 0.0 */ + { + while (value <= 1e-10) /* To speed up things a bit */ + { + value *= 1e10; + integral_10_log -= 10; + } + while (value < 1) + { + value *= 10; + integral_10_log--; + } + } + if (g_flag) + { + if (integral_10_log < nr_of_digits && integral_10_log >= -4) + { + format_flag = 0; + nr_of_digits -= integral_10_log; + } + nr_of_digits--; + if (alternate_flag) + { + /* %#G - No removal of trailing zeros */ + g_flag = 0; + } + else + { + /* %G - Removal of trailing zeros */ + alternate_flag = 1; + } + } + + /* %e or %E */ + if (format_flag) + { + dec_point_pos = 0; + } + else + { + /* Less than one... */ + if (integral_10_log < 0) + { + *buf_pointer++ = '0'; + if ((n = nr_of_digits) || alternate_flag) + { + *buf_pointer++ = '.'; + } + i = 0; + while (--i > integral_10_log && nr_of_digits) + { + *buf_pointer++ = '0'; + nr_of_digits--; + } + if (integral_10_log < (-n - 1)) + { + /* Nothing more to do */ + goto CLEAN_UP; + } + dec_point_pos = 1; + } + else + { + dec_point_pos = - integral_10_log; + } + } + + i = dec_point_pos; + while (i <= nr_of_digits ) + { + value -= (long double)(n = (short)value); /* n=Digit value=Remainder */ + value *= 10; /* Prepare for next shot */ + *buf_pointer++ = n + '0'; + if ( ! i++ && (nr_of_digits || alternate_flag)) + { + *buf_pointer++ = '.'; + } + } + + /* Rounding possible */ + if (value >= 5) + { + n = 1; /* Carry */ + cp = buf_pointer - 1; + do + { + if (*cp != '.') + { + if ( (*cp += n) == ('9' + 1) ) + { + *cp = '0'; + n = 1; + } + else + { + n = 0; + } + } + } while (cp-- > buf); + if (n) + { + /* %e or %E */ + if (format_flag) + { + cp = buf_pointer; + while (cp > buf) + { + if (*(cp - 1) == '.') + { + *cp = *(cp - 2); + cp--; + } + else + { + *cp = *(cp - 1); + } + cp--; + } + integral_10_log++; + } + else + { + cp = ++buf_pointer; + while (cp > buf) + { + *cp = *(cp - 1); + cp--; + } + } + *buf = '1'; + } + } + +CLEAN_UP: + /* %G - Remove trailing zeros */ + if (g_flag) + { + while (*(buf_pointer - 1) == '0') + { + buf_pointer--; + } + if (*(buf_pointer - 1) == '.') + { + buf_pointer--; + } + } + + /* %e or %E */ + if (format_flag) + { + *buf_pointer++ = format_flag; + if (integral_10_log < 0) + { + *buf_pointer++ = '-'; + integral_10_log = -integral_10_log; + } + else + { + *buf_pointer++ = '+'; + } + n = 0; + buf_pointer +=10; + do + { + n++; + *buf_pointer++ = (integral_10_log % 10) + '0'; + integral_10_log /= 10; + } while ( integral_10_log || n < 2 ); + for ( i = n ; n > 0 ; n-- ) + *(buf_pointer - 11 - i + n) = *(buf_pointer - n); + buf_pointer -= 10; + } + return (buf_pointer); +} + +#endif /* FLOAT_SUPPORT */ + +/*! + * This routine forms the core and entry of the formatter. + * + * The conversion performed conforms to the ANSI specification for "printf". + */ +int +PGM_FUNC(_formatted_write)(const char * PGM_ATTR format, + void put_one_char(char, void *), + void *secret_pointer, + va_list ap) +{ + MEM_ATTRIBUTE static char bad_conversion[] = "???"; + MEM_ATTRIBUTE static char null_pointer[] = ""; + +#ifndef REDUCED_SUPPORT + MEM_ATTRIBUTE char format_flag; + MEM_ATTRIBUTE int precision; + MEM_ATTRIBUTE int n; + MEM_ATTRIBUTE int field_width, nr_of_chars; + MEM_ATTRIBUTE char plus_space_flag, left_adjust, l_L_modifier; + MEM_ATTRIBUTE char h_modifier, alternate_flag; + MEM_ATTRIBUTE char nonzero_value; + MEM_ATTRIBUTE unsigned long ulong, div_factor; + +#ifdef FLOAT_SUPPORT + MEM_ATTRIBUTE long double fvalue; +#endif + + MEM_ATTRIBUTE char *buf_pointer; + MEM_ATTRIBUTE char *ptr; + MEM_ATTRIBUTE const char *hex; + MEM_ATTRIBUTE char zeropad; + MEM_ATTRIBUTE char buf[FRMWRI_BUFSIZE]; + + nr_of_chars = 0; + for (;;) /* Until full format string read */ + { + while ((format_flag = PGM_READ_CHAR(format++)) != '%') /* Until '%' or '\0' */ + { + if (!format_flag) + return (nr_of_chars); + put_one_char (format_flag, secret_pointer); + nr_of_chars++; + } + if (PGM_READ_CHAR(format) == '%') /* %% prints as % */ + { + format++; + put_one_char('%', secret_pointer); + nr_of_chars++; + continue; + } + + plus_space_flag = left_adjust = alternate_flag = zeropad = 0; + ptr = buf_pointer = &buf[0]; + hex = "0123456789ABCDEF"; + + /* check for leading '-', '+', ' ','#' or '0' flags */ + for (;;) + { + switch (PGM_READ_CHAR(format)) + { + case ' ': + if (plus_space_flag) + goto NEXT_FLAG; + case '+': + plus_space_flag = PGM_READ_CHAR(format); + goto NEXT_FLAG; + case '-': + left_adjust++; + goto NEXT_FLAG; + case '#': + alternate_flag++; + goto NEXT_FLAG; + case '0': + zeropad++; + goto NEXT_FLAG; + } + break; +NEXT_FLAG: + format++; + } + + /* Optional field width (may be '*') */ + if (PGM_READ_CHAR(format) == '*') + { + field_width = va_arg(ap, int); + if (field_width < 0) + { + field_width = -field_width; + left_adjust++; + } + format++; + } + else + { + field_width = 0; + while (PGM_READ_CHAR(format) >= '0' && PGM_READ_CHAR(format) <= '9') + field_width = field_width * 10 + (PGM_READ_CHAR(format++) - '0'); + } + + if (left_adjust) + zeropad = 0; + + /* Optional precision (or '*') */ + if (PGM_READ_CHAR(format) == '.') + { + if (PGM_READ_CHAR(++format) == '*') + { + precision = va_arg(ap, int); + format++; + } + else + { + precision = 0; + while (PGM_READ_CHAR(format) >= '0' && PGM_READ_CHAR(format) <= '9') + precision = precision * 10 + (PGM_READ_CHAR(format++) - '0'); + } + } + else + precision = -1; + + /* At this point, "left_adjust" is nonzero if there was + * a sign, "zeropad" is 1 if there was a leading zero + * and 0 otherwise, "field_width" and "precision" + * contain numbers corresponding to the digit strings + * before and after the decimal point, respectively, + * and "plus_space_flag" is either 0 (no flag) or + * contains a plus or space character. If there was no + * decimal point, "precision" will be -1. + */ + + l_L_modifier = h_modifier = 0; + + /* Optional 'l','L' r 'h' modifier? */ + switch (PGM_READ_CHAR(format)) + { + case 'l': + case 'L': + l_L_modifier++; + format++; + break; + case 'h': + h_modifier++; + format++; + break; + } + + /* + * At exit from the following switch, we will emit + * the characters starting at "buf_pointer" and + * ending at "ptr"-1 + */ + switch (format_flag = PGM_READ_CHAR(format++)) + { +#if 0 /* bernie */ + case 'n': + if (sizeof(short) != sizeof(int)) + { + if (sizeof(int) != sizeof(long)) + { + if (h_modifier) + *va_arg(ap, short *) = nr_of_chars; + else if (l_L_modifier) + *va_arg(ap, long *) = nr_of_chars; + else + *va_arg(ap, int *) = nr_of_chars; + } + else + { + if (h_modifier) + *va_arg(ap, short *) = nr_of_chars; + else + *va_arg(ap, int *) = nr_of_chars; + } + } + else + { + if (l_L_modifier) + *va_arg(ap, long *) = nr_of_chars; + else + *va_arg(ap, int *) = nr_of_chars; + } + continue; +#endif + case 'c': + buf[0] = va_arg(ap, int); + ptr++; + break; + + case 's': + if ( !(buf_pointer = va_arg(ap, char *)) ) + buf_pointer = null_pointer; + if (precision < 0) + precision = 10000; + for (n=0; *buf_pointer++ && n < precision; n++) + ; + ptr = --buf_pointer; + buf_pointer -= n; + break; + + case 'o': + if (alternate_flag && !precision) + precision++; + case 'x': + hex = "0123456789abcdef"; + case 'u': + case 'p': + case 'X': + if (format_flag == 'p') +#if defined(__AVR__) || defined(__I196__) /* 16bit pointers */ + ulong = (unsigned long)(unsigned short)va_arg(ap, char *); +#else /* 32bit pointers */ + ulong = (unsigned long)va_arg(ap, char *); +#endif /* 32bit pointers */ + else if (sizeof(short) == sizeof(int)) + ulong = l_L_modifier ? + va_arg(ap, unsigned long) : (unsigned long)va_arg(ap, unsigned int); + else + ulong = h_modifier ? + (unsigned long)(unsigned short) va_arg(ap, int) + : (unsigned long)va_arg(ap, int); + div_factor = (format_flag == 'o') ? + 8 : (format_flag == 'u') ? 10 : 16; + plus_space_flag = 0; + goto INTEGRAL_CONVERSION; + + case 'd': + case 'i': + if (sizeof(short) == sizeof(long)) + { + if ( (long)(ulong = va_arg(ap, unsigned long)) < 0) + { + plus_space_flag = '-'; + ulong = (unsigned long)(-((signed long)ulong)); + } + } + else if (sizeof(short) == sizeof(int)) + { + if ( (long)(ulong = l_L_modifier ? + va_arg(ap,unsigned long) : (unsigned long)va_arg(ap,int)) < 0) + { + plus_space_flag = '-'; + ulong = (unsigned long)(-((signed long)ulong)); + } + } + else + { + if ( (signed long)(ulong = (unsigned long) (h_modifier ? + (short) va_arg(ap, int) : va_arg(ap,int))) < 0) + { + plus_space_flag = '-'; + ulong = (unsigned long)(-((signed long)ulong)); + } + } + div_factor = 10; + + /* Now convert to digits */ +INTEGRAL_CONVERSION: + ptr = buf_pointer = &buf[FRMWRI_BUFSIZE - 1]; + nonzero_value = (ulong != 0); + + /* No char if zero and zero precision */ + if (precision != 0 || nonzero_value) + do + *--buf_pointer = hex[ulong % div_factor]; + while (ulong /= div_factor); + + /* "precision" takes precedence */ + if (precision < 0) + if (zeropad) + precision = field_width - (plus_space_flag != 0); + while (precision > (int)(ptr - buf_pointer)) + *--buf_pointer = '0'; + + if (alternate_flag && nonzero_value) + { + if (format_flag == 'x' || format_flag == 'X') + { + *--buf_pointer = format_flag; + *--buf_pointer = '0'; + } + else if ((format_flag == 'o') && (*buf_pointer != '0')) + { + *--buf_pointer = '0'; + } + } + break; + +#ifdef FLOAT_SUPPORT + case 'g': + case 'G': + n = 1; + format_flag -= 2; + if (! precision) + { + precision = 1; + } + goto FLOATING_CONVERSION; + case 'f': + format_flag = 0; + case 'e': + case 'E': + n = 0; +FLOATING_CONVERSION: + if (precision < 0) + { + precision = 6; + } + if (sizeof(double) != sizeof(long double)) + { + if ( (fvalue = l_L_modifier ? + va_arg(ap,long double) : va_arg(ap,double)) < 0) + { + plus_space_flag = '-'; + fvalue = -fvalue; + } + } + else if ( (fvalue = va_arg(ap,long double)) < 0) + { + plus_space_flag = '-'; + fvalue = -fvalue; + } + ptr = float_conversion (fvalue, + (short)precision, + buf_pointer += field_width, + format_flag, + (char)n, + alternate_flag); + if (zeropad) + { + precision = field_width - (plus_space_flag != 0); + while (precision > ptr - buf_pointer) + *--buf_pointer = '0'; + } + break; + +#else /* !FLOAT_SUPPORT */ + case 'g': + case 'G': + case 'f': + case 'e': + case 'E': + ptr = buf_pointer = bad_conversion; + while (*ptr) + ptr++; + break; +#endif /* !FLOAT_SUPPORT */ + + case '\0': /* Really bad place to find NUL in */ + format--; + + default: + /* Undefined conversion! */ + ptr = buf_pointer = bad_conversion; + ptr += 3; + break; + + } + + /* + * This part emittes the formatted string to "put_one_char". + */ + + /* If field_width == 0 then nothing should be written. */ + precision = ptr - buf_pointer; + + if ( precision > field_width) + { + n = 0; + } + else + { + n = field_width - precision - (plus_space_flag != 0); + } + + /* emit any leading pad characters */ + if (!left_adjust) + while (--n >= 0) + { + put_one_char(' ', secret_pointer); + nr_of_chars++; + } + + /* emit flag characters (if any) */ + if (plus_space_flag) + { + put_one_char(plus_space_flag, secret_pointer); + nr_of_chars++; + } + + /* emit the string itself */ + while (--precision >= 0) + { + put_one_char(*buf_pointer++, secret_pointer); + nr_of_chars++; + } + + /* emit trailing space characters */ + if (left_adjust) + while (--n >= 0) + { + put_one_char(' ', secret_pointer); + nr_of_chars++; + } + } + +#else /* REDUCED_SUPPORT STARTS HERE */ + +#ifdef MODIFIERS_IN_REDUCED + char l_modifier, h_modifier; + unsigned long u_val, div_val; +#else + unsigned int u_val, div_val; +#endif + char format_flag; + unsigned int nr_of_chars, base; + char outChar; + char *ptr; + + nr_of_chars = 0; + for (;;) /* Until full format string read */ + { + while ((format_flag = PGM_READ_CHAR(format++)) != '%') /* Until '%' or '\0' */ + { + if (!format_flag) + return (nr_of_chars); + put_one_char (format_flag, secret_pointer); + nr_of_chars++; + } + +#ifdef MODIFIERS_IN_REDUCED + /*=================================*/ + /* Optional 'l' or 'h' modifiers ? */ + /*=================================*/ + l_modifier = h_modifier = 0; + switch (PGM_READ_CHAR(format)) + { + case 'l': + l_modifier = 1; + format++; + break; + + case 'h': + h_modifier = 1; + format++; + break; + } +#endif + + switch (format_flag = PGM_READ_CHAR(format++)) + { + case 'c': + format_flag = va_arg(ap, int); + default: + put_one_char (format_flag, secret_pointer); + nr_of_chars++; + continue; + + case 's': + ptr = va_arg(ap, char *); + while (format_flag = *ptr++) + { + put_one_char (format_flag, secret_pointer); + nr_of_chars++; + } + continue; + + case 'o': + base = 8; + if (IS_SHORT) + div_val = 0x8000; + else + div_val = 0x40000000; + goto CONVERSION_LOOP; + + case 'd': + base = 10; + if (IS_SHORT) + div_val = 10000; + else + div_val = 1000000000; + goto CONVERSION_LOOP; + + case 'X': + case 'x': + base = 16; + if (IS_SHORT) + div_val = 0x1000; + else + div_val = 0x10000000; + +CONVERSION_LOOP: +#ifdef MODIFIERS_IN_REDUCED + if (h_modifier) + u_val = (format_flag == 'd') ? + (short)va_arg(ap, int) : (unsigned short)va_arg(ap, int); + else if (l_modifier) + u_val = va_arg(ap, long); + else + u_val = (format_flag == 'd') ? + va_arg(ap,int) : va_arg(ap,unsigned int); +#else + u_val = va_arg(ap,int); +#endif + if (format_flag == 'd') + { + if (((int)u_val) < 0) + { + u_val = - u_val; + put_one_char ('-', secret_pointer); + nr_of_chars++; + } + } + while (div_val > 1 && div_val > u_val) + { + div_val /= base; + } + do + { + outChar = (u_val / div_val) + '0'; + if (outChar > '9') + if (format_flag == 'x') + outChar += 'a'-'9'-1; + else + outChar += 'A'-'9'-1; + put_one_char (outChar, secret_pointer); + nr_of_chars++; + u_val %= div_val; + div_val /= base; + } + while (div_val); + + } /* end switch(format_flag...) */ + } +#endif +} diff --git a/mware/formatwr.h b/mware/formatwr.h new file mode 100755 index 00000000..091fea1e --- /dev/null +++ b/mware/formatwr.h @@ -0,0 +1,40 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \brief Basic "printf", "sprintf" and "fprintf" formatter. + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + */ +#ifndef MWARE_FORMATWR_H +#define MWARE_FORMATWR_H + +#include + +int _formatted_write( + const char *format, + void put_one_char(char, void *), + void *secret_pointer, + va_list ap); + +#ifdef __AVR__ + #include + int _formatted_write_P( + const char * PROGMEM format, + void put_one_char(char, void *), + void *secret_pointer, + va_list ap); +#endif /* __AVR__ */ + +#endif /* MWARE_FORMATWR_H */ + diff --git a/mware/gfx.c b/mware/gfx.c new file mode 100755 index 00000000..930510e3 --- /dev/null +++ b/mware/gfx.c @@ -0,0 +1,404 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \author Bernardo Innocenti + * \author Stefano Fedrigo + * + * \brief General pourpose graphics routines + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + * Revision 1.6 2004/03/24 15:03:45 bernie + * Use explicit include paths; clean Doxygen comments + * + * Revision 1.5 2004/02/09 00:21:28 aleph + * Various gfx fixes + * + * Revision 1.4 2004/01/27 23:24:19 aleph + * Add new graphics primitives + * + * Revision 1.3 2004/01/13 00:05:23 aleph + * Fix clipping bug + * + * Revision 1.2 2004/01/07 23:33:01 aleph + * Change copyright email + * + * Revision 1.1 2004/01/07 19:05:31 aleph + * Add graphics routines + * + */ + +#include "gfx.h" +#include "config.h" +#include + +#include + + +/*! + * Plot a point in bitmap. + * \note bm is evaluated twice + */ +#define BM_PLOT(bm, x, y) \ + ( *((bm)->raster + ((y) / 8) * (bm)->width + (x)) |= 1 << ((y) % 8) ) + +/*! + * Clear a point in bitmap. + * \note bm is evaluated twice + */ +#define BM_CLEAR(bm, x, y) \ + ( *((bm)->raster + ((y) / 8) * (bm)->width + (x)) &= ~(1 << ((y) % 8)) ) + +/*! Swap a with b */ +#define SWAP(a, b) \ + do { \ + (void)(&a == &b); /* type check */ \ + typeof(a) tmp; \ + tmp = (a); \ + (a) = (b); \ + (b) = tmp; \ + } while (0) + + +/*! + * Initialize a Bitmap structure with the provided parameters. + */ +void gfx_InitBitmap(Bitmap *bm, uint8_t *raster, coord_t w, coord_t h) +{ + bm->raster = raster; + bm->width = w; + bm->height = h; + bm->penX = 0; + bm->penY = 0; +} + + +/*! + * Clear the whole bitmap surface to all zeros + */ +void gfx_ClearBitmap(Bitmap *bm) +{ + memset(bm->raster, 0, (bm->width * bm->height) / 8); +} + + +/*! + * Copy a raster picture located in program memory in the bitmap. + * The size of the raster to copy *must* be the same of the raster bitmap. + */ +void gfx_blitBitmap_P(Bitmap *bm, const prog_uchar *raster) +{ + memcpy_P(bm->raster, raster, bm->height/8 * bm->width); +} + + +void gfx_DrawLine(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2) +{ + int x, y, e, len, adx, ady, signx, signy; + + +#ifdef CONFIG_GFX_CLIPPING + /* FIXME: broken */ + + #define XMIN 0 + #define YMIN 0 + #define XMAX (bm->width - 1) + #define YMAX (bm->height - 1) + + /* Clipping */ + if (x1 < XMIN) + { + y1 = y2 - ((x2 - XMIN) * (y2 - y1)) / (x2 - x1); + x1 = XMIN; + } + if (y1 < YMIN) + { + x1 = x2 - ((y2 - YMIN) * (x2 - x1)) / (y2 - y1); + y1 = YMIN; + } + if (x2 < XMIN) + { + y2 = y2 - ((XMIN - x1) * (y2 - y1)) / (x2 - x1); + x2 = XMIN; + } + if (y2 < YMIN) + { + x2 = x2 - ((YMIN - y1) * (x2 - x1)) / (y2 - y1); + y2 = YMIN; + } + + if (x1 > XMAX) + { + y1 = ((x2 - XMAX) * (y2 - y1)) / (x2 - x1); + x1 = XMAX; + } + if (y1 > YMAX) + { + x1 = ((y2 - YMAX) * (x2 - x1)) / (y2 - y1); + y1 = YMAX; + } + if (x2 > XMAX) + { + y2 = ((XMAX - x1) * (y2 - y1)) / (x2 - x1); + x2 = XMAX; + } + if (y2 > YMAX) + { + x2 = ((YMAX - y1) * (x2 - x1)) / (y2 - y1); + y2 = YMAX; + } + + #undef XMIN + #undef YMIN + #undef XMAX + #undef YMAX + +#endif /* CONFIG_GRAPH_CLIPPING */ + + + if (x2 > x1) + { + /* left to right */ + signx = +1; + adx = x2 - x1; + } + else + { + /* right to left */ + signx = -1; + adx = x1 - x2; + } + + if (y2 > y1) + { + /* top to bottom */ + signy = +1; + ady = y2 - y1; + } + else + { + /* bottom to top */ + signy = -1; + ady = y1 - y2; + } + + x = x1; + y = y1; + + if (adx > ady) + { + /* X-major line (octants 1/4/5/8) */ + + len = adx; + e = -adx; + while (len--) + { + /* Sanity check */ + if ((x >= 0) && (x < bm->width) && (y >= 0) && (y < bm->height)) + BM_PLOT(bm, x, y); + x += signx; + e += ady; + if (e >= 0) + { + y += signy; + e -= adx; + } + } + } + else + { + /* Y-major line (octants 2/3/6/7) */ + + len = ady; + e = -ady; + while (len--) + { + /* Sanity check */ + if ((x >= 0) && (x < bm->width) && (y >= 0) && (y < bm->height)) + BM_PLOT(bm, x, y); + y += signy; + e += adx; + if (e >= 0) + { + x += signx; + e -= ady; + } + } + } +} + + +void gfx_MoveTo(Bitmap *bm, coord_t x, coord_t y) +{ + bm->penX = x; + bm->penY = y; +} + + +void gfx_LineTo(Bitmap *bm, coord_t x, coord_t y) +{ + gfx_DrawLine(bm, bm->penX, bm->penY, x, y); + gfx_MoveTo(bm, x, y); +} + + +/*! + * Draw a filled rectangle. + * \note The bottom-right border of the rectangle is not drawn. + */ +void gfx_FillRect(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2) +{ + coord_t x, y; + + /* Sort coords */ + if (x1 > x2) SWAP(x1, x2); + if (y1 > y2) SWAP(y1, y2); + + /* Clip rect to bitmap bounds */ + if (x1 < 0) x1 = 0; + if (x2 < 0) x2 = 0; + if (x1 > bm->width) x1 = bm->width; + if (x2 > bm->width) x2 = bm->width; + if (y1 < 0) y1 = 0; + if (y2 < 0) y2 = 0; + if (y1 > bm->width) y1 = bm->width; + if (y2 > bm->width) y2 = bm->width; + + /* Draw rectangle */ + for (x = x1; x < x2; x++) + for (y = y1; y < y2; y++) + BM_PLOT(bm, x, y); +} + + +/*! + * Draw an empty rectangle. + * \note The bottom-right border of the rectangle is not drawn. + */ +void gfx_DrawRect(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2) +{ + /* Sort coords */ + if (x1 > x2) SWAP(x1, x2); + if (y1 > y2) SWAP(y1, y2); + + /* Draw rectangle */ + gfx_DrawLine(bm, x1, y1, x2-1, y1); + gfx_DrawLine(bm, x2-1, y1, x2-1, y2-1); + gfx_DrawLine(bm, x2-1, y2-1, x1, y2-1); + gfx_DrawLine(bm, x1, y2-1, x1, y1); +} + + +/*! + * Clear a rectangular area. + * \note The bottom-right border of the rectangle is not drawn. + */ +void gfx_ClearRect(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2) +{ + coord_t x, y; + + /* Sort coords */ + if (x1 > x2) SWAP(x1, x2); + if (y1 > y2) SWAP(y1, y2); + + /* Clip rect to bitmap bounds */ + if (x1 < 0) x1 = 0; + if (x2 < 0) x2 = 0; + if (x1 > bm->width) x1 = bm->width; + if (x2 > bm->width) x2 = bm->width; + if (y1 < 0) y1 = 0; + if (y2 < 0) y2 = 0; + if (y1 > bm->width) y1 = bm->width; + if (y2 > bm->width) y2 = bm->width; + + /* Draw rectangle */ + for (x = x1; x < x2; x++) + for (y = y1; y < y2; y++) + BM_CLEAR(bm, x, y); +} + + +/*! + * Imposta un rettangolo di clipping per il disegno nella bitmap + */ +void gfx_SetClipRect(Bitmap *bm, coord_t minx, coord_t miny, coord_t maxx, coord_t maxy) +{ + ASSERT(minx < maxx); + ASSERT(miny < maxy); + ASSERT(miny >= 0); + ASSERT(minx >= 0); + ASSERT(maxx < bm->width); + ASSERT(maxy < bm->height); + + bm->cr.xmin = minx; + bm->cr.ymin = miny; + bm->cr.xmax = maxx; + bm->cr.ymax = maxy; + +/* DB(kprintf("cr.xmin = %d, cr.ymin = %d, cr.xmax = %d, cr.ymax = %d\n", + bm->cr.xMin, bm->cr.ymin, bm->cr.xmax, bm->cr.ymax);) +*/ +} + + +#ifdef CONFIG_LCD_VCOORDS +/*! + * Imposta gli estremi del sistema di coordinate cartesiane rispetto + * al rettangolo di clipping della bitmap. + */ +void gfx_SetViewRect(Bitmap *bm, vcoord_t x1, vcoord_t y1, vcoord_t x2, vcoord_t y2) +{ + ASSERT(x1 != x2); + ASSERT(y1 != y2); + + bm->orgX = x1; + bm->orgY = y1; + bm->scaleX = (vcoord_t)(bm->cr.xmax - bm->cr.xmin) / (vcoord_t)(x2 - x1); /* +1 */ + bm->scaleY = (vcoord_t)(bm->cr.ymax - bm->cr.ymin) / (vcoord_t)(y2 - y1); /* +1 */ + +/* DB(kprintf("orgX = %f, orgY = %f, scaleX = %f, scaleY = %f\n", + bm->orgX, bm->orgY, bm->scaleX, bm->scaleY);) +*/ +} + + +/*! + * Transform a coordinate from the current reference system to a + * pixel offset within the bitmap. + */ +coord_t gfx_TransformX(Bitmap *bm, vcoord_t x) +{ + return bm->cr.xmin + (coord_t)((x - bm->orgX) * bm->scaleX); +} + +/*! + * Transform a coordinate from the current reference system to a + * pixel offset within the bitmap. + */ +coord_t gfx_TransformY(Bitmap *bm, vcoord_t y) +{ + return bm->cr.ymin + (coord_t)((y - bm->orgY) * bm->scaleY); +} + + +/*! + * Draw a line from (x1;y1) to (x2;y2) + */ +void gfx_VDrawLine(Bitmap *bm, vcoord_t x1, vcoord_t y1, vcoord_t x2, vcoord_t y2) +{ + gfx_DrawLine(bm, + gfx_TransformX(bm, x1), gfx_TransformY(bm, y1), + gfx_TransformY(bm, x2), gfx_TransformY(bm, y2)); +} +#endif /* CONFIG_LCD_VCOORDS */ diff --git a/mware/gfx.h b/mware/gfx.h new file mode 100755 index 00000000..16f34e6f --- /dev/null +++ b/mware/gfx.h @@ -0,0 +1,91 @@ +/*! + * \file + * Copyright (C) 1999 Bernardo Innocenti + * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/) + * All Rights Reserved. + * + * \version $Id$ + * + * \author Bernardo Innocenti + * \author Stefano Fedrigo + * + * \brief General pourpose graphics routines + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + * Revision 1.4 2004/02/09 00:21:28 aleph + * Various gfx fixes + * + * Revision 1.3 2004/01/27 23:24:19 aleph + * Add new graphics primitives + * + * Revision 1.2 2004/01/07 23:33:01 aleph + * Change copyright email + * + * Revision 1.1 2004/01/07 19:05:31 aleph + * Add graphics routines + * + */ + +#ifndef GFX_H +#define GFX_H + +#include "compiler.h" +#include + + +/*! Common type for coordinates expressed in pixel units */ +typedef int coord_t; + +#ifdef CONFIG_LCD_VCOORDS +/*! Common type for coordinates expressed in logical units */ +typedef float vcoord_t; +#endif /* CONFIG_LCD_VCOORDS */ + + +typedef struct Rect { coord_t xmin, ymin, xmax, ymax; } Rect; + + +/*! Control structure to draw in a bitmap */ + +typedef struct Bitmap +{ + uint8_t *raster; /*!< Pointer to byte array to hold the data */ + coord_t width, height; /*!< Width/Height in pixels */ + coord_t penX, penY; /*!< Current pen position MoveTo()/LineTo() */ + + Rect cr; /*!< Clip drawing inside this rectangle */ + +#ifdef CONFIG_LCD_VCOORDS + /*! Logical coordinate system */ + vcoord_t orgX, orgY; + vcoord_t scaleX, scaleY; +#endif /* CONFIG_LCD_VCOORDS */ + +} Bitmap; + + +/* Function prototypes */ +extern void gfx_InitBitmap(Bitmap *bm, uint8_t *raster, coord_t w, coord_t h); +extern void gfx_ClearBitmap(Bitmap *bm); +extern void gfx_blitBitmap_P(Bitmap *bm, const prog_uchar *raster); +extern void gfx_DrawLine(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2); +extern void gfx_FillRect(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2); +extern void gfx_DrawRect(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2); +extern void gfx_ClearRect(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2); +extern void gfx_MoveTo(Bitmap *bm, coord_t x, coord_t y); +extern void gfx_LineTo(Bitmap *bm, coord_t x, coord_t y); +extern void gfx_SetClipRect(Bitmap *bm, coord_t xmin, coord_t ymin, coord_t xmax, coord_t ymax); + +#ifdef CONFIG_LCD_VCOORDS +extern void gfx_SetViewRect(Bitmap *bm, vcoord_t x1, vcoord_t y1, vcoord_t x2, vcoord_t y2); +extern coord_t gfx_TransformX(Bitmap *bm, vcoord_t x); +extern coord_t gfx_TransformY(Bitmap *bm, vcoord_t y); +extern void gfx_VDrawLine(Bitmap *bm, vcoord_t x1, vcoord_t y1, vcoord_t x2, vcoord_t y2); +#endif /* CONFIG_LCD_VCOORDS */ + +#endif /* GFX_H */ diff --git a/mware/list.c b/mware/list.c new file mode 100755 index 00000000..74ae0400 --- /dev/null +++ b/mware/list.c @@ -0,0 +1,49 @@ +/*! + * \file + * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/) + * Copyright (C) 2001 Bernardo Innocenti + * All Rights Reserved. + * + * \version $Id$ + * + * \author Bernardo Innocenti + * + * \brief List handling functions + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + */ + +#include "list.h" + + +Node *_list_rem_head(List *l) +{ + Node *n; + + if (ISLISTEMPTY(l)) + return (Node *)0; + + n = l->head; + l->head = n->succ; + n->succ->pred = (Node *)l; + return n; +} + + +Node *_list_rem_tail(List *l) +{ + Node *n; + + if (ISLISTEMPTY(l)) + return (Node *)0; + + n = l->tail; + l->tail = n->pred; + n->pred->succ = (Node *)&l->null; + return n; +} diff --git a/mware/list.h b/mware/list.h new file mode 100755 index 00000000..8989728e --- /dev/null +++ b/mware/list.h @@ -0,0 +1,122 @@ +/*! + * \file + * Copyright (C) 2001 Bernardo Innocenti + * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/) + * All Rights Reserved. + * + * \version $Id$ + * + * \author Bernardo Innocenti + * + * \brief General pourpose double-linked lists + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + */ +#ifndef MWARE_LIST_H +#define MWARE_LIST_H + +typedef struct _Node +{ + struct _Node *succ; + struct _Node *pred; +} Node; + +typedef struct _List +{ + Node *head; + Node *null; + Node *tail; +} List; + + +/*! Template for a list of \a T structures */ +#define DECLARE_LIST(T) \ + struct { T *head; T *null; T *tail; } + +/*! Template for a node in a list of \a T structures */ +#define DECLARE_NODE(T) \ + struct { T *succ; T *pred; } + +/*! Template for a node in a list of \a T structures */ +#define DECLARE_NODE_ANON(T) \ + T *succ; T *pred; + +/*! + * Iterate over all nodes in a list. This statement defines a for cicle + * accepting the following parameters: + * \param n node pointer to be used in each iteration + * \param l pointer to list + */ +#define FOREACHNODE(n,l) \ + for( \ + (n) = (typeof(n))((l)->head); \ + ((Node *)(n))->succ; \ + (n) = (typeof(n))(((Node *)(n))->succ) \ + ) + +/*! Initialize a list */ +#define INITLIST(l) \ + do { \ + (l)->head = (Node *)(&(l)->null); \ + (l)->null = NULL; \ + (l)->tail = (Node *)(&(l)->head); \ + } while (0) + +/*! Add node to list head */ +#define ADDHEAD(l,n) \ + do { \ + (n)->succ = (l)->head; \ + (n)->pred = (Node *)&(l)->head; \ + (n)->succ->pred = (n); \ + (l)->head = (n); \ + } while (0) + +/*! Add node to list tail */ +#define ADDTAIL(l,n) \ + do { \ + (n)->succ = (Node *)(&(l)->null); \ + (n)->pred = (l)->tail; \ + (n)->pred->succ = (n); \ + (l)->tail = (n); \ + } while (0) + +/*! + * Insert node \a n before node \a ln + * Note: you can't pass in a list header as \a ln, but + * it is safe to pass list-\>head of an empty list. + */ +#define INSERTBEFORE(n,ln) \ + do { \ + (n)->succ = (ln); \ + (n)->pred = (ln)->pred; \ + (ln)->pred->succ = (n); \ + (ln)->pred = (n); \ + } while (0) + +/*! Remove \a n from whatever list it is in */ +#define REMOVE(n) \ + do { \ + (n)->pred->succ = (n)->succ; \ + (n)->succ->pred = (n)->pred; \ + } while (0) + +/*! Tell whether a list is empty */ +#define ISLISTEMPTY(l) ( (l)->head == (Node *)(&(l)->null) ) + +/*! \name Extract an element from the head/tail of the list. If the list empty, return NULL. */ +/*\{*/ +#define REMHEAD(l) _list_rem_head(l) +#define REMTAIL(l) _list_rem_tail(l) +/*\}*/ + +/* Prototypes for out-of-line functions */ +Node *_list_rem_head(List *l); +Node *_list_rem_tail(List *l); + + +#endif /* MWARE_LIST_H */ diff --git a/mware/sprintf.c b/mware/sprintf.c new file mode 100755 index 00000000..7a8e62af --- /dev/null +++ b/mware/sprintf.c @@ -0,0 +1,86 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \author Bernardo Innocenti + * + * \brief Simple sprintf() implementation based on _formatted_write() + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + * Revision 1.4 2004/04/03 20:42:27 aleph + * Remove duplicated defines + * + * Revision 1.3 2004/03/24 15:48:53 bernie + * Remove Copyright messages from Doxygen output + * + * Revision 1.2 2004/03/19 16:51:30 bernie + * Add PROGMEM kludge. + * + * Revision 1.1 2004/02/23 09:45:09 aleph + * Add missing library functions. + * + * Revision 1.1 2003/11/13 16:56:37 aleph + * Add first implementation of dsp firmware + * + */ + +#include "compiler.h" +#include "formatwr.h" +#include + + +static void __str_put_char(char c, void *ptr) +{ + /* + * This Does not work on Code Warrior. Hmm... + * *(*((char **)ptr))++ = c; + */ + + **((char **)ptr) = c; + (*((char **)ptr))++; +} + +static void __null_put_char(UNUSED(char c), UNUSED(void *ptr)) +{ + /* nop */ +} + + +int PGM_FUNC(vsprintf)(char * str, const char * PGM_ATTR fmt, va_list ap) +{ + int result; + + result = PGM_FUNC(_formatted_write)( + fmt, (str ? __str_put_char : __null_put_char), &str, ap); + + /* terminate string */ + *str = '\0'; + + return result; +} + +/* FIXME: sprintf_P is incorrectly declared in */ +int PGM_FUNC(sprintf)(char *str, const char * fmt, ...) +{ + int result; + va_list ap; + + va_start(ap, fmt); + result = PGM_FUNC(vsprintf)(str, fmt, ap); + va_end(ap); + + /* terminate string */ + *str = '\0'; + + return result; +} diff --git a/mware/text.c b/mware/text.c new file mode 100755 index 00000000..c73ef075 --- /dev/null +++ b/mware/text.c @@ -0,0 +1,257 @@ +/*! + * \file + * + * + * \version $Id$ + * + * \author Bernardo Innocenti + * \author Stefano Fedrigo + * + * \brief Text graphic routines + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + * Revision 1.17 2004/05/15 16:57:01 aleph + * Fixes for non-DEBUG build + * + * Revision 1.16 2004/04/03 20:42:49 aleph + * Add text_clear() + * + * Revision 1.15 2004/03/24 15:03:45 bernie + * Use explicit include paths; clean Doxygen comments + * + * Revision 1.14 2004/03/19 16:52:28 bernie + * Move printf() like functions from text.c to text_format.c and add PROGMEM versions. + * + * Revision 1.13 2004/03/17 18:23:32 bernie + * Oops. + * + * Revision 1.12 2004/03/17 18:03:22 bernie + * Make diagnostic message shorter + * + * Revision 1.11 2004/03/13 22:52:54 aleph + * documentation fixes + */ + +#include "gfx.h" +#include "font.h" +#include "text.h" +#include + +/*! + * Flags degli stili algoritmici + * La routine di rendering del testo e' in grado di applicare + * delle semplici trasformazioni al font interno per generare + * automaticamente degli stili predefiniti (bold, italic, + * underline) a partire dal set di caratteri plain. + */ +static uint8_t text_styles; + +/*! ANSI escape sequences flag: true for ESC state on */ +static bool ansi_mode = false; + + +/*! + * Move (imaginary) cursor to column and row specified. + * Next text write will start a that row and col. + */ +void text_moveto(struct Bitmap *bm, int row, int col) +{ + ASSERT(col >= 0); + ASSERT(col < bm->width / FONT_WIDTH); + ASSERT(row >= 0); + ASSERT(row < bm->height / FONT_HEIGHT); + + bm->penX = col * FONT_WIDTH; + bm->penY = row * FONT_HEIGHT; +} + + +/*! + * Move (imaginary) cursor to coordinates specified. + */ +void text_setcoord(struct Bitmap *bm, int x, int y) +{ + bm->penX = x; + bm->penY = y; +} + + +/*! + * Render char c + */ +static int text_putglyph(char c, struct Bitmap *bm) +{ + const uint8_t * PROGMEM glyph; /* font is in progmem */ + uint8_t glyph_width; + uint8_t i; + uint8_t *buf; + + /* + * Il carattere da stampare viene usato come indice per prelevare + * la prima colonna di dots del glyph all'interno del font. + */ + glyph = font + (((unsigned char)c) * FONT_WIDTH); + glyph_width = FONT_WIDTH; + + if (text_styles & STYLEF_CONDENSED) + --glyph_width; + + if (text_styles & STYLEF_EXPANDED) + glyph_width *= 2; + + /* The y coord is rounded at multiples of 8 for simplicity */ + bm->penY &= ~((coord_t)7); + + /* Check if glyph to write fits in the bitmap */ + if ((bm->penX < 0) || (bm->penX + glyph_width > bm->width) || + (bm->penY < 0) || (bm->penY + FONT_HEIGHT > bm->height)) + { + DB(kprintf("bad coords x=%d y=%d\n", bm->penX, bm->penY);) + return 0; + } + + /* Locate position where to write in the raster */ + buf = bm->raster + bm->penY / 8 * bm->width + bm->penX; + + bm->penX += glyph_width; + + /* If some styles are set */ + if (text_styles) + { + uint8_t prev_dots = 0, italic_prev_dots = 0, new_dots; + uint8_t dots; + + /* Per ogni colonna di dot del glyph... */ + for (i = 0; i < glyph_width; ++i) + { + dots = pgm_read_byte(glyph); + + /* Advance to next column in glyph. + * Expand: advances only once every two columns + */ + if (!(text_styles & STYLEF_EXPANDED) || (i & 1)) + glyph++; + + /* Italic: get lower 4 dots from previous column */ + if (text_styles & STYLEF_ITALIC) + { + new_dots = dots; + dots = (dots & 0xF0) | italic_prev_dots; + italic_prev_dots = new_dots & 0x0F; + } + + /* Bold: "or" pixels with the previous column */ + if (text_styles & STYLEF_BOLD) + { + new_dots = dots; + dots |= prev_dots; + prev_dots = new_dots; + } + + /* Underlined: turn on base pixel */ + if (text_styles & STYLEF_UNDERLINE) + dots |= 0x80; + + /* Inverted: invert pixels */ + if (text_styles & STYLEF_INVERT) + dots = ~dots; + + /* Output dots */ + *buf++ = dots; + } + } + else /* No style: fast vanilla copy of glyph to line buffer */ + while (glyph_width--) + *buf++ = pgm_read_byte(glyph++); + + return c; +} + + +/*! + * Render char \c c, with (currently) limited ANSI escapes + * emulation support and '\n' for newline. + */ +int text_putchar(char c, struct Bitmap *bm) +{ + /* Handle ANSI escape sequences */ + if (ansi_mode) + { + switch (c) + { + case ANSI_ESC_CLEARSCREEN: + gfx_ClearBitmap(bm); + bm->penX = 0; + bm->penY = 0; + text_style(0, STYLEF_MASK); + break; + DB(default: + kprintf("Unknown ANSI esc code: %x\n", c);) + } + ansi_mode = false; + } + else if (c == '\033') /* Enter ANSI ESC mode */ + { + ansi_mode = true; + } + else if (c == '\n') /* Go one line down on a line-feed */ + { + if (bm->penY + FONT_HEIGHT < bm->height) + { + bm->penY += FONT_HEIGHT; + bm->penX = 0; + } + } + else + { + text_putglyph(c, bm); + } + return c; +} + + +/*! + * Clear the screen and reset cursor position + */ +void text_clear(struct Bitmap *bmp) +{ + text_putchar('\x1b', bmp); + text_putchar('c', bmp); +} + + +/*! + * Set/clear algorithmic font style bits. + * + * \param flags Style flags to set + * \param mask Mask of flags to modify + * \return Old style flags + * + * Examples: + * Turn on bold, leave other styles alone + * \code prt_style(STYLEF_BOLD, STYLEF_BOLD); \endcode + * + * Turn off bold and turn on italic, leave others as they are + * \code prt_style(STYLEF_ITALIC, STYLEF_BOLD | STYLEF_ITALIC); \endcode + * + * Query current style without chaning it + * \code style = prt_style(0, 0); \endcode + * + * Reset all styles (plain text) + * \code prt_style(0, STYLE_MASK); \endcode + */ +uint8_t text_style(uint8_t flags, uint8_t mask) +{ + uint8_t old = text_styles; + text_styles = (text_styles & ~mask) | flags; + return old; +} diff --git a/mware/text.h b/mware/text.h new file mode 100755 index 00000000..2cd1cacf --- /dev/null +++ b/mware/text.h @@ -0,0 +1,98 @@ +/*! + * \file + * Copyright (C) 1999 Bernardo Innocenti + * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/) + * All Rights Reserved. + * + * \version $Id$ + * + * \author Bernardo Innocenti + * \author Stefano Fedrigo + * + * \brief Text graphic routines + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + * Revision 1.9 2004/04/03 20:42:49 aleph + * Add text_clear() + * + * Revision 1.8 2004/03/19 16:52:28 bernie + * Move printf() like functions from text.c to text_format.c and add PROGMEM versions. + * + * Revision 1.7 2004/03/17 17:30:30 bernie + * Add GCC format checks to printf()-like functions. + * + * Revision 1.6 2004/02/21 21:40:20 aleph + * Various small fixes + * + * Revision 1.5 2004/02/18 11:50:10 aleph + * Add right alignment to xprintf + * + * Revision 1.4 2004/01/13 12:15:28 aleph + * Move font table in program memory; add font.h + * + * Revision 1.3 2004/01/13 00:06:47 aleph + * Fix clipping and ANSI esc bug, add text_xprintf() + * + * Revision 1.2 2004/01/08 18:03:12 aleph + * Add text functions to set coordinates + * + * Revision 1.1 2004/01/07 23:31:54 aleph + * Add text routines + * + */ + +#ifndef TEXT_H +#define TEXT_H + +#include "compiler.h" +#include + +/* Style flags */ +#define STYLEF_BOLD BV(0) +#define STYLEF_ITALIC BV(1) +#define STYLEF_UNDERLINE BV(2) +#define STYLEF_INVERT BV(3) +#define STYLEF_EXPANDED BV(4) +#define STYLEF_CONDENSED BV(5) +#define STYLEF_STRIKEOUT BV(6) /* Not implemented */ + +#define STYLEF_MASK \ + (STYLEF_BOLD | STYLEF_ITALIC | STYLEF_UNDERLINE | \ + STYLEF_EXPANDED | STYLEF_CONDENSED | STYLEF_INVERT) + +/* Flags for text_xprintf() */ +#define TEXT_NORMAL 0 /*!< Normal mode */ +#define TEXT_FILL BV(0) /*!< Fill rest of line with spaces */ +#define TEXT_CENTER BV(1) /*!< Center string in line */ +#define TEXT_INVERT BV(2) /*!< Inverted mode */ +#define TEXT_RIGHT BV(3) /*!< Right aligned */ + +/* Escape sequences codes */ +#define ANSI_ESC_CLEARSCREEN 'c' + + + +/* Fwd decl */ +struct Bitmap; + +void text_moveto(struct Bitmap *bm, int row, int col); +void text_setcoord(struct Bitmap *bm, int x, int y); +int text_putchar(char c, struct Bitmap *bm); +int text_puts(const char *str, struct Bitmap *bm); +int text_vprintf(struct Bitmap *bm, const char *fmt, va_list ap); +int text_printf(struct Bitmap *bm, const char *fmt, ...) FORMAT(__printf__, 2, 3); +int text_xprintf(struct Bitmap *bm, uint8_t row, uint8_t col, uint8_t mode, const char *fmt, ...) FORMAT(__printf__, 5, 6); +uint8_t text_style(uint8_t flags, uint8_t mask); +void text_clear(struct Bitmap *bm); + +int text_puts_P(const char * PROGMEM str, struct Bitmap *bm); +int text_vprintf_P(struct Bitmap *bm, const char * PROGMEM fmt, va_list ap); +int text_printf_P(struct Bitmap *bm, const char * PROGMEM fmt, ...) FORMAT(__printf__, 2, 3); +int text_xprintf_P(struct Bitmap *bm, uint8_t row, uint8_t col, uint8_t mode, const char * PROGMEM fmt, ...) FORMAT(__printf__, 5, 6); + +#endif /* TEXT_H */ diff --git a/mware/text_format.c b/mware/text_format.c new file mode 100755 index 00000000..6defd13c --- /dev/null +++ b/mware/text_format.c @@ -0,0 +1,110 @@ +/*! + * \file + * + * + * + * \version $Id$ + * + * \author Bernardo Innocenti + * \author Stefano Fedrigo + * + * \brief printf-family routines for text output + */ + +/* + * $Log$ + * Revision 1.1 2004/05/23 15:43:16 bernie + * Import mware modules. + * + * Revision 1.2 2004/03/26 18:50:50 bernie + * Move _PROGMEM stuff to compiler.h + * + * Revision 1.1 2004/03/19 16:52:28 bernie + * Move printf() like functions from text.c to text_format.c and add PROGMEM versions. + * + */ + +#include "text.h" +#include "formatwr.h" /* _formatted_write() */ +#include "font.h" +#include "gfx.h" +#include +#include /* strlen */ + +/*! + * Render string str in bitmap + */ +int PGM_FUNC(text_puts)(const char * PGM_ATTR str, struct Bitmap *bm) +{ + char c; + + while ((c = PGM_READ_CHAR(str++))) + text_putchar(c, bm); + + return 0; +} + + +int PGM_FUNC(text_vprintf)(struct Bitmap *bm, const char * PGM_ATTR fmt, va_list ap) +{ + return PGM_FUNC(_formatted_write)(fmt, (void (*)(char, void *))text_putchar, bm, ap); +} + + +int PGM_FUNC(text_printf)(struct Bitmap *bm, const char * PGM_ATTR fmt, ...) +{ + int len; + + va_list ap; + va_start(ap, fmt); + len = PGM_FUNC(text_vprintf)(bm, fmt, ap); + va_end(ap); + + return len; +} + + +int PGM_FUNC(text_xprintf)(struct Bitmap *bm, + uint8_t row, uint8_t col, uint8_t mode, const char * PGM_ATTR fmt, ...) +{ + int len; + uint8_t oldstyle = 0; + va_list ap; + + va_start(ap, fmt); + + text_moveto(bm, row, col); + + if (mode & TEXT_INVERT) + oldstyle = text_style(STYLEF_INVERT, STYLEF_INVERT); + + if (mode & (TEXT_CENTER | TEXT_RIGHT)) + { + uint8_t pad; + + pad = bm->width/FONT_WIDTH - PGM_FUNC(vsprintf)(NULL, fmt, ap); + + if (mode & TEXT_CENTER) + pad /= 2; + + while (pad--) + text_putchar(' ', bm); + } + + len = PGM_FUNC(text_vprintf)(bm, fmt, ap); + va_end(ap); + + if (mode & (TEXT_FILL | TEXT_CENTER)) + while (bm->penX + FONT_WIDTH < bm->width) + text_putchar(' ', bm); + + if (mode & TEXT_INVERT) + text_style(oldstyle, STYLEF_MASK); + + return len; +} + -- 2.25.1