--- /dev/null
+/*!
+ * \file
+ * <!--
+ * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright (C) 2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \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 <drv/kdebug.h>
+
+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 */
--- /dev/null
+/*!
+ * \file
+ * <!--
+ * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright (C) 2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \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.
+ *
+ * <pre>
+ *
+ * +-----------------------------------+
+ * | vuoto | dati validi | vuoto |
+ * +-----------------------------------+
+ * ^ ^ ^ ^
+ * begin head tail end
+ *
+ * </pre>
+ *
+ * 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 */
+
--- /dev/null
+/*!
+ * \file
+ * <!--
+ * Copyright (C) 2001 Bernardo Innocenti <bernie@codewiz.org>
+ * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \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, /* \7f */
+/* 0x80 */
+ 0x38, 0xC4, 0xC4, 0x44, 0x28, 0x00, /* \80 */
+ 0x3A, 0x40, 0x40, 0x20, 0x7A, 0x00, /* \81 */
+ 0x38, 0x54, 0x54, 0x55, 0x19, 0x00, /* \82 */
+ 0x22, 0x55, 0x55, 0x55, 0x78, 0x00, /* \83 */
+ 0x20, 0x55, 0x54, 0x54, 0x79, 0x00, /* \84 */
+ 0x21, 0x75, 0x55, 0x54, 0x78, 0x00, /* \85 */
+ 0x20, 0x74, 0x57, 0x54, 0x78, 0x00, /* \86 */
+ 0x08, 0x54, 0x54, 0x74, 0x14, 0x00, /* \87 */
+/* 0x88 */
+ 0x3A, 0x55, 0x55, 0x55, 0x1A, 0x00, /* \88 */
+ 0x39, 0x54, 0x54, 0x55, 0x18, 0x00, /* \89 */
+ 0x39, 0x55, 0x55, 0x54, 0x18, 0x00, /* \8a */
+ 0x00, 0x45, 0x7C, 0x41, 0x00, 0x00, /* \8b */
+ 0x02, 0x45, 0x7D, 0x42, 0x00, 0x00, /* \8c */
+ 0x01, 0x45, 0x7D, 0x40, 0x00, 0x00, /* \8d */
+ 0x79, 0x14, 0x12, 0x14, 0x79, 0x00, /* \8e */
+ 0x70, 0x2B, 0x2B, 0x2B, 0x70, 0x00, /* \8f */
+/* 0x90 */
+ 0x7C, 0x54, 0x55, 0x55, 0x45, 0x00, /* \90 */
+ 0x20, 0x54, 0x38, 0x54, 0x48, 0x00, /* \91 */
+ 0x7E, 0x09, 0x7F, 0x49, 0x49, 0x00, /* \92 */
+ 0x32, 0x49, 0x49, 0x49, 0x32, 0x00, /* \93 */
+ 0x32, 0x48, 0x48, 0x48, 0x32, 0x00, /* \94 */
+ 0x32, 0x4A, 0x4A, 0x48, 0x30, 0x00, /* \95 */
+ 0x3A, 0x41, 0x41, 0x21, 0x7A, 0x00, /* \96 */
+ 0x3A, 0x42, 0x42, 0x20, 0x78, 0x00, /* \97 */
+/* 0x98 */
+ 0x0D, 0x50, 0x50, 0x50, 0x3D, 0x00, /* \98 */
+ 0x19, 0x24, 0x42, 0x24, 0x19, 0x00, /* \99 */
+ 0x3D, 0x40, 0x40, 0x40, 0x3D, 0x00, /* \9a */
+ 0x18, 0x24, 0x7E, 0x24, 0x24, 0x00, /* \9b */
+ 0x28, 0x5E, 0x29, 0x42, 0x20, 0x00, /* \9c */
+ 0x09, 0x2A, 0x7C, 0x2A, 0x09, 0x00, /* \9d */
+ 0x7F, 0x05, 0x15, 0x3D, 0x52, 0x00, /* \9e */
+ 0x20, 0x48, 0x3E, 0x09, 0x02, 0x00, /* \9f */
+/* 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 /* ÿ */
+};
--- /dev/null
+/*!
+ * \file
+ * <!--
+ * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Stefano Fedrigo <aleph@develer.com>
+ *
+ * \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 */
--- /dev/null
+/*!
+ * \file
+ * <!--
+ * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \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 <float.h>
+
+#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[] = "<NULL>";
+
+#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
+}
--- /dev/null
+/*!
+ * \file
+ * <!--
+ * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \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 <stdarg.h>
+
+int _formatted_write(
+ const char *format,
+ void put_one_char(char, void *),
+ void *secret_pointer,
+ va_list ap);
+
+#ifdef __AVR__
+ #include <avr/pgmspace.h>
+ 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 */
+
--- /dev/null
+/*!
+ * \file
+ * <!--
+ * Copyright (C) 1999 Bernardo Innocenti <bernie@develer.com>
+ * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ *
+ * \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 <drv/kdebug.h>
+
+#include <string.h>
+
+
+/*!
+ * 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 */
--- /dev/null
+/*!
+ * \file
+ * Copyright (C) 1999 Bernardo Innocenti <bernie@develer.com>
+ * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ *
+ * \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 <avr/pgmspace.h>
+
+
+/*! 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 */
--- /dev/null
+/*!
+ * \file
+ * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright (C) 2001 Bernardo Innocenti <bernie@develer.com>
+ * All Rights Reserved.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \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;
+}
--- /dev/null
+/*!
+ * \file
+ * Copyright (C) 2001 Bernardo Innocenti <bernie@develer.com>
+ * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \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 */
--- /dev/null
+/*!
+ * \file
+ * <!--
+ * Copyright (C) 2002,2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \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 <stdio.h>
+
+
+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 <stdio.h> */
+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;
+}
--- /dev/null
+/*!
+ * \file
+ * <!--
+ * Copyright (C) 1999 Bernardo Innocenti <bernie@develer.com>
+ * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ *
+ * \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 <drv/kdebug.h>
+
+/*!
+ * 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 <code>c</code>
+ */
+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;
+}
--- /dev/null
+/*!
+ * \file
+ * Copyright (C) 1999 Bernardo Innocenti <bernie@develer.com>
+ * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ *
+ * \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 <stdarg.h>
+
+/* 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 */
--- /dev/null
+/*!
+ * \file
+ *
+ * <!--
+ * Copyright (C) 1999 Bernardo Innocenti <bernie@develer.com>
+ * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ *
+ * \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 <stdarg.h>
+#include <string.h> /* strlen */
+
+/*!
+ * Render string <code>str</code> 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;
+}
+