BT200 / tic55x support: working with keyboard, lcd, and several test programs
authorRick van Rein <vanrein@hwdev.(none)>
Fri, 15 Apr 2011 14:45:10 +0000 (14:45 +0000)
committerRick van Rein <vanrein@hwdev.(none)>
Fri, 15 Apr 2011 14:45:10 +0000 (14:45 +0000)
Added a warning about license conflict potential for this architecture.  Sigh.

14 files changed:
doc/top2bottom.rst
include/0cpm/app.h
include/0cpm/kbd.h
include/0cpm/show.h [new file with mode: 0644]
include/bottom/grandstream.h
include/bottom/ht162x.h [new file with mode: 0644]
include/bottom/tic55x.h
src/driver/Makefile
src/driver/ht162x.c [new file with mode: 0644]
src/driver/tic55x/LICENSE-WARNING.TXT [new file with mode: 0644]
src/driver/tic55x/grandstream-bt20x.c
src/driver/tic55x/int.c
src/function/develtest/keys2display.c
src/target/Kconfig.platform

index 37c898a..22bfcf4 100644 (file)
@@ -455,7 +455,7 @@ Buttons are grouped for practical purposes, as follows:
 * Function-bound keys like Hold, Transfer, Flash, Menu or Up/Down.
 * Line buttons, positioned to manage lines/accounts/calls.
 * Soft function buttons, usually positioned under a display.
-* Generic buttons, which can be programmed for speed dial and so on.
+* User programmable buttons, usuable for speed dial and so on.
 
 The configuration files specify which are available, and
 how many of the various classes.  The bottom half is
@@ -475,6 +475,7 @@ ones are released, even if this may not reflect what the
 hardware detects.  The ability to decode multiple buttons
 pressed at the same time is so dependent on hardware that
 the top half should refrain from interpreting such situations.
+Furthermore, this is not commonly done for phone keyboards.
 This is also why the ``top_button_release()`` function has
 no arguments -- everything that may still be thought of as
 being pressed should be released after this call.
index 0f6d062..38231f2 100644 (file)
@@ -116,4 +116,6 @@ void app_focus (app_t *app);
 // TODO: API?  Unfocus, unregister?  When to start, how long to claim, and so on?
 
 
+
+
 #endif
index 718f617..83f193c 100644 (file)
@@ -5,21 +5,43 @@
  */
 
 
-#include <resource.h>
-#include <kbd.h>
 
+/* Button classes: DTMF, function-specific, lines, soft functions, userprog */
+typedef enum {
+       BUTCLS_NONE,
+       BUTCLS_DTMF,
+       BUTCLS_FIXED_FUNCTION,
+       BTCLS_LINE,
+       BUTCLS_SOFT_FUNCTION,
+       BUTCLS_USER_PROGRAMMABLE
+} buttonclass_t;
 
-/* The keyboard can be used and reused in many different ways.  Which way applies when is
- * dependent on the state of the phone.  At each resource level, the application may
- * request the use of certain keys and other resources.  When not all resources are
- * available because higher resource levels overtake them, the application will be
- * suspended.  At a later moment, when the higher resource level application ends, the
- * application at the lower level may be resumed.
+
+#define BUTTON_NULL    '\x00'
+
+
+/* Button codes: An ASCII code or a special function */
+typedef uint8_t buttoncode_t;
+
+
+/* Functions that may be required if the keyboard and/or hook need to be
+ * scanned actively, instead of initiated purely by level-change interrupts.
  */
+#if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
+void bottom_keyboard_scan (void);
+#endif
+
+#if defined NEED_HOOK_SCANNER_WHEN_ONHOOK || defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
+void bottom_hook_scan (void);
+#endif
 
 
-resource_t resource_keyboard = {
-       /* res_claims */        NULL,
-       /* res_eventprio */     EVT_PRIO_USER,
-};
+/* Interrupt routines invoked by the bottom, possibly during bottom_xxx_scan().
+ * The application may assume that the phone is onhook, and that no key is
+ * pressed when the phone comes online.  The top functions will be called if the
+ * situation is found to be different.
+ */
+void top_button_press (buttonclass_t bcl, buttoncode_t cde);
+void top_button_release (void);
+void top_hook_update (bool offhook);
 
diff --git a/include/0cpm/show.h b/include/0cpm/show.h
new file mode 100644 (file)
index 0000000..6478834
--- /dev/null
@@ -0,0 +1,53 @@
+/* Show output on displays.
+ *
+ * Display interaction depends heavily on available hardware.
+ * For this reason, the messages are formatted in the bottom half
+ * of the 0cpm firmerware.  By defining different routines for
+ * different kinds of display action, and assigning priority
+ * levels to what is being displayed, the resulting show ought
+ * to be optimal on any concrete phone device.
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+
+#ifndef HEADER_SHOW
+#define HEADER_SHOW
+
+
+/* A number of fixed messages is defined in a numeric way, so their
+ * actual representation can be optimised for the display (notably,
+ * for its size).
+ */
+typedef enum {
+       FIXMSG_OFFLINE,         // The phone is offline
+       FIXMSG_REGISTERING,     // The phone is registering
+       FIXMSG_READY,           // The phone is ready (shown actively!)
+       FIXMSG_BOOTLOAD,        // The bootloader is active
+       FIXMSG_SENDING,         // A call request is being / has been sent
+       FIXMSG_RINGING,         // The remote phone is ringing
+       FIXMSG_CALL_ENDED,      // The call has ended
+       FIXMSG_COUNT            // The number of fixed messages
+} fixed_msg_t;
+
+
+/* Stop displaying content at the specified level.  In some cases, older
+ * content may now pop up, in others the display could get cleared.
+ */
+void bottom_show_close_level (app_level_t level);
+
+/* Show a period (not a wallclock time) on the display.
+ */
+void bottom_show_period (app_level_t level, uint8_t h, uint8_t m, uint8_t s);
+
+/* Print an IP address on the display */
+void bottom_show_ip4 (app_level_t level, uint8_t  bytes [4]);
+void bottom_show_ip6 (app_level_t level, uint16_t bytes [8]);
+
+/* Print a fixed message prominently on the display */
+void bottom_show_fixed_msg (app_level_t level, fixed_msg_t msg);
+
+/* Print a notification of the number of new / old voicemails */
+void bottom_show_voicemail (app_level_t level, uint16_t new, uint16_t old);
+#endif
index d1c8161..696db04 100644 (file)
@@ -5,8 +5,35 @@
 
 /* Settings for Budgetone devices */
 #if defined CONFIG_TARGET_GRANDSTREAM_BT20x || defined CONFIG_TARGET_GRANDSTREAM_BT10x
+
 #define HAVE_LED_MESSAGE 1
 #define HAVE_LED_BACKLIGHT 1
+#define HAVE_LED_HANDSET 1
+#define HAVE_LED_SPEAKERPHONE 1
+
+#define HAVE_BUTTON_MESSAGE    'i'
+#define HAVE_BUTTON_HOLD       'h'
+#define HAVE_BUTTON_TRANSFER   'x'
+#define HAVE_BUTTON_CONFERENCE 'c'
+#define HAVE_BUTTON_FLASH      'f'
+#define HAVE_BUTTON_MUTE       '-'
+#define HAVE_BUTTON_SEND       'g'
+#define HAVE_BUTTON_SPEAKER    's'
+#define HAVE_BUTTON_DOWN       '_'
+#define HAVE_BUTTON_UP         '^'
+#define HAVE_BUTTON_CALLERS    '?'
+#define HAVE_BUTTON_CALLED     '!'
+#define HAVE_BUTTON_MENU       'm'
+
+#define NEED_HOOK_SCANNER_WHEN_ONHOOK 1
+#define NEED_HOOK_SCANNER_WHEN_OFFHOOK 1
+#define NEED_KBD_SCANNER_BETWEEN_KEYS 1
+#define NEED_KBD_SCANNER_DURING_KEYPRESS 1
+
+#pragma FAR(kbdisp)
+extern volatile uint8_t kbdisp;
+asm ("_kbdisp .set 0x666666");
+
 #endif
 
 
diff --git a/include/bottom/ht162x.h b/include/bottom/ht162x.h
new file mode 100644 (file)
index 0000000..5ad2fa4
--- /dev/null
@@ -0,0 +1,86 @@
+/* HT162x includes
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+/* The following definitions are designed to clock bits
+ * out starting at the high part of a 16-bit word.
+ * Below these bits is a "1" bit and then fillup "0".
+ */
+
+#define HT162x_LCDPREFIX_CMD   (0x8000 | 0x1000)
+#define HT162x_LCDPREFIX_WRITE (0xa000 | 0x1000)
+
+#define HT162x_LCD_ADDRESS6(x) (((x) << 10) | 0x0200)
+#define HT162x_LCD_NIBBLE(x)   (((x) << 12) | 0x0800)
+#define HT162x_LCD_2NIBBLES(x) (((x) <<  8) | 0x0080)
+#define HT162x_LCD_CMD(x)      (((x) <<  8) | 0x0040)
+
+#define HT162x_LCDCMD_SYSDIS   HT162x_LCD_CMD (0x00)
+#define HT162x_LCDCMD_SYSEN    HT162x_LCD_CMD (0x01)
+#define HT162x_LCDCMD_LCDOFF   HT162x_LCD_CMD (0x02)
+#define HT162x_LCDCMD_LCDON    HT162x_LCD_CMD (0x03)
+#define HT162x_LCDCMD_TIMERDIS HT162x_LCD_CMD (0x04)
+#define HT162x_LCDCMD_WDTDIS   HT162x_LCD_CMD (0x05)
+#define HT162x_LCDCMD_TIMEREN  HT162x_LCD_CMD (0x06)
+#define HT162x_LCDCMD_WDTEN    HT162x_LCD_CMD (0x07)
+#define HT162x_LCDCMD_TONEOFF  HT162x_LCD_CMD (0x08)
+#define HT162x_LCDCMD_TONEON   HT162x_LCD_CMD (0x09)
+#define HT162x_LCDCMD_CLRTIMER HT162x_LCD_CMD (0x0c)
+#define HT162x_LCDCMD_CLRWDT   HT162x_LCD_CMD (0x0e)
+#define HT162x_LCDCMD_XTAL32K  HT162x_LCD_CMD (0x14)
+#define HT162x_LCDCMD_RC256K   HT162x_LCD_CMD (0x18)
+#define HT162x_LCDCMD_EXT256K  HT162x_LCD_CMD (0x1c)
+#define HT162x_LCDCMD_BIAS2_2  HT162x_LCD_CMD (0x20)
+#define HT162x_LCDCMD_BIAS2_3  HT162x_LCD_CMD (0x24)
+#define HT162x_LCDCMD_BIAS2_4  HT162x_LCD_CMD (0x28)
+#define HT162x_LCDCMD_BIAS3_2  HT162x_LCD_CMD (0x21)
+#define HT162x_LCDCMD_BIAS3_3  HT162x_LCD_CMD (0x25)
+#define HT162x_LCDCMD_BIAS3_4  HT162x_LCD_CMD (0x29)
+#define HT162x_LCDCMD_TONE4K   HT162x_LCD_CMD (0x40)
+#define HT162x_LCDCMD_TONE2K   HT162x_LCD_CMD (0x60)
+#define HT162x_LCDCMD_IRQDIS   HT162x_LCD_CMD (0x80)
+#define HT162x_LCDCMD_IRQEN    HT162x_LCD_CMD (0x88)
+#define HT162x_LCDCMD_F1       HT162x_LCD_CMD (0xa0)
+#define HT162x_LCDCMD_F2       HT162x_LCD_CMD (0xa1)
+#define HT162x_LCDCMD_F4       HT162x_LCD_CMD (0xa2)
+#define HT162x_LCDCMD_F8       HT162x_LCD_CMD (0xa3)
+#define HT162x_LCDCMD_F16      HT162x_LCD_CMD (0xa4)
+#define HT162x_LCDCMD_F32      HT162x_LCD_CMD (0xa5)
+#define HT162x_LCDCMD_F64      HT162x_LCD_CMD (0xa6)
+#define HT162x_LCDCMD_F128     HT162x_LCD_CMD (0xa7)
+//Note: HT162x_LCDCMD_TEST     -> should not be used
+#define HT162x_LCDCMD_NORMAL   HT162x_LCD_CMD (0xe3)
+
+
+#define HT162x_LCDCMD_DONE     0x8000
+
+
+/* The display data is stored in a shared array */
+#ifndef HAVE_HT162x_DISPBYTES
+#  define HAVE_HT162x_DISPBYTES 96
+#endif
+extern uint8_t ht162x_dispdata [HAVE_HT162x_DISPBYTES];
+
+/* The program should define an array of LCDCMD_xxx to
+ * initialise the HT162x chip.  The array should be
+ * terminated with HT162x_LCDCMD_DONE.
+ */
+extern uint16_t ht162x_setup_cmdseq [];
+
+/* The high-level driver offers a general setup routine
+ * that runs over the command sequence above.
+ */
+void ht162x_setup_lcd (void);
+
+/* Notify the HT162x driver of an update to a ht162x_dispdata range */
+void ht162x_dispdata_notify (uint8_t minaddr, uint8_t maxaddr);
+
+/* The low-level driver should provide a few functions that
+ * enable toggling the CS, WR and DATA bits.
+ */
+void ht162x_chipselect (bool selected);
+void ht162x_databit_prepare (bool databit);
+void ht162x_databit_commit (void);
+
index 2dbb8f8..484330c 100644 (file)
@@ -64,6 +64,12 @@ asm ("_PCR1 .set 0x2c12");
 #define REGBIT_PCR_RIOEN       12
 #define REGBIT_PCR_XIOEN       13
 
+#define REGVAL_PCR_CLKRP       0x01
+#define REGVAL_PCR_CLKXP       0x02
+#define REGVAL_PCR_FSRP                0x04
+#define REGVAL_PCR_FSXP                0x08
+#define REGVAL_PCR_DRSTAT      0x10
+
 /* Timer0/1 configuration registers */
 extern volatile uint16_t ioport GPTCLK_0;
 extern volatile uint16_t ioport GPTCNT1_0, GPTCNT2_0, GPTCNT3_0, GPTCNT4_0;
index 1eafb9d..98274c5 100644 (file)
@@ -1,5 +1,5 @@
 
-objs-bottom-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += src/driver/tic55x/grandstream-bt20x.o
+objs-bottom-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += src/driver/tic55x/grandstream-bt20x.o src/driver/ht162x.o
 
 #TODO: replace rts55.lib with bootstrapping in src/driver/tic55x/trampoline.o
 
@@ -7,3 +7,4 @@ objs-bottom-$(CONFIG_PLATFORM_TIC55x) += src/driver/tic55x/int.o src/driver/tic5
 
 metavars-$(CONFIG_TARGET_GRANDSTREAM_BT20x) += SYSCLK1_TO_MS_DIVIDER=4096
 
+includes-$(CONFIG_TARGET_GRANDSTREAM) += bottom/grandstream.h
diff --git a/src/driver/ht162x.c b/src/driver/ht162x.c
new file mode 100644 (file)
index 0000000..41ae117
--- /dev/null
@@ -0,0 +1,167 @@
+/* ht162x.c -- driver for Holtek 162x chips
+ *
+ * This is a general driver for Holtek 162x LCD driver chips.
+ * It is designed to output bits serially, using a few low-level
+ * routines elsewhere that depend on how the hardware is wired.
+ * 
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+
+#define BOTTOM
+#include <config.h>
+
+#include <bottom/ht162x.h>
+
+
+/* The display data is stored as a series of bytes.  This is
+ * not as general as the actual displays, which work per nibble.
+ * Since it is more common for computers to work with bytes, and
+ * since this is certainly useful for several applications (think
+ * of 7-segment displays, or a row of bits in a character) the
+ * grainsize of a byte seems easier to do.
+ */
+uint8_t ht162x_dispdata [HAVE_HT162x_DISPBYTES];
+
+/* The _minchg and _maxchg addresses mark an area that has
+ * changed, and should be updated on the next opportunity.
+ */
+uint8_t ht162x_dispdata_minchg = HAVE_HT162x_DISPBYTES;
+uint8_t ht162x_dispdata_maxchg = 0;
+
+/* The _sendstate details the progress of clocking out data */
+enum ht162x_sendstate {
+       SS_DISABLED,    // No sending in progress
+       SS_CMDBITS,     // Shifting the bits of a command
+       SS_WRPREFIX,    // Shifting write prefix bits
+       SS_ADDRESS,     // Shifting address bits
+       SS_DATA,        // Shifting the data word
+} sendstate;
+
+
+static uint16_t wr_data = 0x8000;
+static uint8_t wr_addr_cur = 1, wr_addr_max = 0;
+static bool wr_state_high = true;
+static bool wr_active = false;
+static uint16_t *wr_cmdptr;
+
+
+/* Start the process of shifting bits to the HT162x */
+static void start_shifting (void) {
+       void ht162x_bitshifter (void);
+       // TODO: Start up the process asynchronously!
+       wr_active = true;
+       sendstate = SS_DISABLED;
+       do {
+               uint16_t ctr = 250;
+               ht162x_bitshifter ();
+               while (ctr > 0) { ctr--; }
+       } while (wr_active);
+}
+
+
+/* Stop the process of shifting bits to the HT162x */
+static void stop_shifting (void) {
+       // TODO: Stop the asynchronous process
+       wr_active = false;
+}
+
+/* Take another step in the process of shifting data to the ht162x */
+void ht162x_bitshifter (void) {
+       bool done = false;
+       // Is the second half of a bit clock-in?
+       if (!wr_state_high) {
+               ht162x_databit_commit ();
+               wr_state_high = true;
+               return;
+       }
+       // Is this the end of a portion to be sent?
+       if (wr_data == 0x8000) {
+               switch (sendstate) {
+               case SS_DISABLED:
+                       // This is the start of a new block of LCD writes
+                       if (wr_cmdptr) {
+                               sendstate = SS_CMDBITS;
+                       } else if (ht162x_dispdata_minchg <= ht162x_dispdata_maxchg) {
+                               wr_addr_cur = ht162x_dispdata_minchg;
+                               wr_addr_max = ht162x_dispdata_maxchg;
+                               ht162x_dispdata_minchg = HAVE_HT162x_DISPBYTES;
+                               ht162x_dispdata_maxchg = 0;
+                               wr_data = HT162x_LCDPREFIX_WRITE;
+                               sendstate = SS_WRPREFIX;
+                       } else {
+                               stop_shifting ();
+                               return;
+                       }
+                       wr_state_high = true;
+                       ht162x_databit_prepare (0); // Ensure high WR
+                       ht162x_chipselect (true);
+                       return;
+               case SS_WRPREFIX:
+                       // Done sending the write prefix -> send address
+                       wr_data = HT162x_LCD_ADDRESS6 (wr_addr_cur << 1);
+                       sendstate = SS_ADDRESS;
+                       break;
+               case SS_ADDRESS:
+                       // Done sending the address -> send data bytes
+                       sendstate = SS_DATA;
+                       // Continue into SS_DATA...
+               case SS_DATA:
+                       if (wr_addr_cur > wr_addr_max) {
+                               done = true;
+                               break;
+                       }
+                       wr_data = HT162x_LCD_2NIBBLES (ht162x_dispdata [wr_addr_cur++]);
+                       break;
+               case SS_CMDBITS:
+                       // Done sending CMDBITS -> increment cmdptr
+                       if (*wr_cmdptr == HT162x_LCDCMD_DONE) {
+                               wr_cmdptr = NULL;
+                               done = true;
+                               break;
+                       }
+                       wr_data = *wr_cmdptr++;
+                       break;
+               }
+       }
+       // Is there nothing more to send in the CS period?
+       if (done) {
+               sendstate = SS_DISABLED;
+               ht162x_chipselect (false);
+               return; // Next invocation may terminate sending
+       }
+       // Send out the first phase of the next bit
+       ht162x_databit_prepare (wr_data >> 15);
+       wr_data <<= 1;
+       wr_state_high = false;
+}
+
+
+/* Notify the HT162x driver of an update to a ht162x_dispdata range */
+void ht162x_dispdata_notify (uint8_t minaddr, uint8_t maxaddr) {
+       if (minaddr < ht162x_dispdata_minchg) {
+               ht162x_dispdata_minchg = minaddr;
+       }
+       if (maxaddr > ht162x_dispdata_maxchg) {
+               ht162x_dispdata_maxchg = maxaddr;
+       }
+       if (!wr_active) {
+               start_shifting ();
+       }
+}
+
+
+/* Setup the HT162x by sending it the configuration commands */
+void ht162x_setup_lcd (void) {
+       ht162x_chipselect (false);  // Reset any current access
+       wr_cmdptr = ht162x_setup_cmdseq;
+       memset (ht162x_dispdata, 0x00, sizeof (ht162x_dispdata));
+       ht162x_dispdata_notify (0, HAVE_HT162x_DISPBYTES-1);
+       start_shifting ();
+}
+
diff --git a/src/driver/tic55x/LICENSE-WARNING.TXT b/src/driver/tic55x/LICENSE-WARNING.TXT
new file mode 100644 (file)
index 0000000..9c90d01
--- /dev/null
@@ -0,0 +1,183 @@
+LICENCE COMPATIBILITY WARNING FOR TIC55x
+========================================
+
+Contents:
+
+* Introduction to the license conflict
+* Diverting the problem
+* Why we release under GPL
+* A request to Texas Instruments
+
+
+Introduction to the license conflict
+------------------------------------
+
+Before starting a project in which you use the 0cpm firmerware
+on TI's C55x architecture, please understand that there is a
+licensing conflict between TI's compiler licenses and the GPLv3
+under which this software resides.
+
+The GPL enforces distribution of source code as well as a complete
+toolchain with which to build binaries; the TI license on the other
+hand, forbids distribution of their tool chain alongside source code.
+Solutions exist, but need extra attention in an early phase of
+your project.
+
+
+Diverting the problem
+---------------------
+
+It is difficult, but not impossible to avoid getting into trouble
+with either or both licenses.  We first summerise them, and than
+detail the options further down.
+
+1. Do not release your modified code to anyone
+2. Use unaltered binaries from the 0cpm project
+3. Get your changes accepted in the 0cpm project
+4. Get the 0cpm crew to port to your device
+5. Use another chip family
+
+We are not really happy about placing ourselves as central as the
+following options do; but the fact is that we are the only party
+who is not strictly held to the GPL (being the original authors)
+so we can sometimes provide a pragmatic way around the GPL -- which
+we are willing to do, inasfar as the openness of the firmware does
+not suffer from it.
+
+
+>>> ad 1. Do not release
+
+       As an end user, you have total freedom to modify the
+       code that runs on your phone.  We apologise for the
+       inconvenience of having to download the toolchain from
+       TI's website instead of finding it alongside the
+       0cpm firmerware.
+       As soon as you start start passing around (for instance,
+       selling) your modified code the GPL applies; you are
+       then in violation of either the GPL or the TI license
+       unless you follow any of the following strategies.
+       We are really sorry for the inconvenience, and will
+       work with TI in an attempt to resolve it.
+
+>>> ad 2. Unaltered binaries
+
+       You could make the choice to use unaltered binaries
+       that you can download from our website.  This could
+       imply that you would have to clone a hardware
+       platform.  Please inform yourself of the possible
+       copyright infringements that you are risking before
+       you do this.  We reverse engineered phones, which is
+       not an offense as we are not copying them, but you
+       might run into problems if you did.  Read (ad 2) for
+       a way out.
+
+>>> ad 3. Submit changes
+
+       We will be happy to take contributions to the 0cpm
+       firmwerware, as longs as they always lead to building
+       code, without ever crossing the separation between top
+       and bottom.  To enforce this, patches to top and bottom
+       must be submitted separately, and each should build
+       independently.  As soon as your patches have been
+       processed, you would be able to acquire unaltered
+       binaries and proceed as under (ad 1) but probably
+       without the copyright infringement risk.  If you
+       submit a good patch right away, you should not
+       expect us to charge you for it, but we may need a
+       few weeks before we can deliver your binary.
+
+>>> ad 4. 0cpm ports to your hardware
+
+       We will be happy to consider your request to port to
+       any device that you designed.  Please understand that
+       this is not a free service; we are trying to be as
+       flexible as possible but we will need to reserve the
+       time to dedicate to your product.
+
+>>> ad 5. Other chips
+
+       Your last bet could be to select another target platform
+       than the TIC55x; specifically, one with a milder license
+       for the toolchain.  The easiest would be a target platform
+       that is already supported by an open source toolchain such
+       as gcc or llvm.
+
+(And yes, there is a fifth option that would be quite unpractical...
+you could produce an open source toolchain for the TIC55x platform
+yourself and use that for your product.)
+
+
+Why we release under GPL
+------------------------
+
+We have made a deliberate choice to release our code under GPLv3 and
+not under a BSD-style license.  When we started this project, the
+market was full of VoIP phones that ran mediocre firmware.  Given
+the effort to write such firmware, it is not a surprise that not
+every whim of any user could be taken into account, but in practice
+there has been no progress at all in the SIP market, because all
+parties are waiting for (most) others to take the first step.
+
+This situation is a direct result of developers in different
+companies, working independently to build the same kind of software.
+This uneconomical duplication of work can be resolved by sharing the
+firmware, but that will only work if the rules for sharing are the
+same for everyone.  This is why we set forth to create a firmware
+that could serve as a basis for developers in any company, anywhere.
+
+We also wanted to avoid the return of the same situation in the
+future; by choosing the GPLv3, we ensured that future versions of
+the shared 0cpm firmerware would stay open and free.  Furthermore,
+the same license ensures absolute freedom for end users to replace,
+update and modify the firmware.  Effectively, this will mean that
+not only the manufacturers, but knowledgeable users can join the
+collaborative effort to finally make SIP do what it has always been
+supposed to do -- instead of sticking to a bare minimum of simulated
+analog telephony.
+
+Please understand that open source licenses are at least as serious as
+commercial licenses.  Active users who believe in the aforementioned
+views are known to exercise their rights to obtain source code and
+access to their devices, as specified in the GPL.  If no settlement is
+possible out of court, cases are being trialed, at a staggering success
+rate.  Please do not understand this as a threat to undermine you or
+your product, but merely to cooperate under clear and fair guidelines
+of sharing.  The same rules apply to your competitors!  Manufacturers,
+distributors and resellers who ship products with the 0cpm firmerware
+or derivatives are all required to act in accordance with GPLv3.
+
+
+A request to Texas Instruments
+------------------------------
+
+We really enjoyed developing for the TIC55x platform based on the
+TI toolchain.  We are impressed by the excellent documentation that
+accompanies both the tools and the target platform, and have great
+respect for the accomplishments of these DSP chips.
+
+What we don't quite understand, is that the license accompanying the
+toolchain forbids the redistribution of the tools alongside source code
+or code that could be compiled to other platforms than those marketed
+by TI.  It does not seem very practical to distribute a compiler or
+assembler without source code to pass through it  ;-)
+
+We expect that the inability for manufacturers to live up to the GPL
+without us as an intermediary might put them off, and drive some of
+them to VoIP solutions by other chip manufacturers.  We do not believe
+that the mere legality of the toolchain should have such a powerful
+impact.
+
+For that reason, we ask TI to consider making an exemption for the
+0cpm firmerware and its derivatives, by granting permission to
+redistribute the complete toolchain alongside the source code of
+the 0cpm firmerware and its derivatives.  We suspect that TI will
+want to include a clause that no user has the freedom to use the
+toolchain to target non-TI targets.  Since this is not a limitation
+to the user's ability to exercise the freedom brought to the
+0cpm firmerware by the GPL, we do not expect this to be challenged.
+
+
+As soon as TI permits this redistribution of their TIC55x toolkit,
+we will update or remove this file from the software distribution,
+and the cautioning note in src/target/Kconfig.platform
+
index 5baa7b8..ab3adf8 100644 (file)
 #include <0cpm/cpu.h>
 #include <0cpm/timer.h>
 #include <0cpm/led.h>
+#include <0cpm/kbd.h>
+#include <0cpm/app.h>
+#include <0cpm/show.h>
+
+#include <bottom/ht162x.h>
+
+
+/******** HT162x LCD DRIVER LOW-LEVEL FUNCTIONS ********/
+
+
+/* The program defines an array of LCDCMD_xxx to
+ * initialise the HT162x chip.  The array should be
+ * terminated with HT162x_LCDCMD_DONE.
+ */
+extern uint16_t ht162x_setup_cmdseq [] = {
+       HT162x_LCDPREFIX_CMD,
+       HT162x_LCDCMD_LCDOFF,
+       HT162x_LCDCMD_NORMAL,
+       HT162x_LCDCMD_RC256K,
+       HT162x_LCDCMD_SYSEN,
+       HT162x_LCDCMD_LCDON,
+       HT162x_LCDCMD_TIMERDIS,
+       HT162x_LCDCMD_WDTDIS,
+       HT162x_LCDCMD_TONEOFF,
+       HT162x_LCDCMD_BIAS3_4,
+       HT162x_LCDCMD_TONE2K,
+       // Terminate the sequence:
+       HT162x_LCDCMD_DONE
+};
+
+
+/* Chip-enable or -disable the LCD driver */
+void ht162x_chipselect (bool selected) {
+       if (selected) {
+               IODATA &= ~ (1 << 1);
+       } else {
+               IODATA |=   (1 << 1);
+       }
+}
+
+
+/* Send out a databit for the LCD driver, but do not clock it in */
+static uint16_t kbdisp_outbuf = 0x0000;
+void ht162x_databit_prepare (bool databit) {
+       if (databit) {
+               kbdisp_outbuf &= ~0x4040;
+               kbdisp_outbuf |=  0x8080;
+       } else {
+               kbdisp_outbuf &= ~0xc0c0;
+       }
+       kbdisp = kbdisp_outbuf;
+}
+
+/* Clock in the database that was prepared for the LCD driver */
+void ht162x_databit_commit (void) {
+       kbdisp_outbuf |= 0x4040;
+       kbdisp = kbdisp_outbuf;
+}
+
+
+/******** LCD-SPECIFIC FORM PAINTING ROUTINES ********/
+
+
+/* Digit notations on the LCD's 7 segment displays */
+uint8_t lcd7seg_digits [10] = {
+       0xaf, 0xa0, 0xcb, 0xe9, 0xe4,   // 01234
+       0x6d, 0x6f, 0xa8, 0xef, 0xed    // 56789
+};
+
+/* Alphabetic notations on the LCD's 7 segment displays */
+uint8_t lcd7seg_alpha [26] = {
+       0xee, 0x67, 0x0f, 0xe3, 0x4f,   // AbCdE
+       0x4e, 0x2f, 0xe6, 0x06, 0xa1,   // FGHIJ
+       0x6e, 0x07, 0x6a, 0x62, 0x63,   // kLMno
+       0xce, 0xec, 0x42, 0x6d, 0x47,   // PQRST
+       0xa7, 0x23, 0x2b,               // Uvw
+       0x49, 0xe5, 0xc2
+};
+
+/* Put a character into display byte idx, with ASCII code ch */
+void ht162x_putchar (uint8_t idx, uint8_t ch, bool notify) {
+       uint8_t chup = ch & 0xdf;
+       uint8_t lcd7seg;
+       if ((ch >= '0') && (ch <= '9')) {
+               lcd7seg = lcd7seg_digits [ch - '0'];
+       } else if ((chup >= 'A') && (chup <= 'Z')) {
+               lcd7seg = lcd7seg_alpha [chup - 'A'];
+       } else if (chup == 0x00) {
+               lcd7seg = 0x00;  // space for chup one of 0x00 and 0x20
+       } else {
+               lcd7seg = 0x40;  // dash
+       }
+       ht162x_dispdata [idx] = (ht162x_dispdata [idx] & 0x10) | lcd7seg;
+       if (notify) {
+               ht162x_dispdata_notify (idx, idx);
+       }
+}
+
+uint8_t lcd_bars [8] = {
+       0x00, 0x20, 0x60, 0xe0, 0xe8, 0xec, 0xee, 0xef
+};
+
+/* Level indication for volume, showing the upper 3 bits of "level" */
+void ht162x_audiolevel (uint8_t level) {
+       uint8_t bars = lcd_bars [level >> 5];
+       ht162x_dispdata [15] = (ht162x_dispdata [15] & 0x10) | bars;
+       ht162x_dispdata_notify (15, 15);
+}
+
+#define LCDSYM_NETWORK 14
+#define LCDSYM_HANDSET 13
+#define LCDSYM_SPEAKER 11
+#define LCDSYM_FORWARD 10
+#define LCDSYM_CLOCK   8
+#define LCDSYM_LOCK    7
+#define LCDSYM_BINARY  15
+#define LCDSYM_CN1     4
+#define LCDSYM_CN2     5
+#define LCDSYM_HOUR10  0
+#define LCDSYM_HMSEP   1
+#define LCDSYM_AM      2
+#define LCDSYM_PM      3
+#define LCDSYM_DOT12   12
+#define LCDSYM_DOT9    9
+#define LCDSYM_DOT6    6
+
+/* Special flag setting on the LCD, to flag conditions */
+void ht162x_led_set (uint8_t lcdidx, led_colour_t col, bool notify) {
+       if (col) {
+               ht162x_dispdata [lcdidx] |=  0x10;
+       } else {
+               ht162x_dispdata [lcdidx] &= ~0x10;
+       }
+       if (notify) {
+               ht162x_dispdata_notify (lcdidx, lcdidx);
+       }
+}
+
+/******** BOTTOM FUNCTIONS FOR LEDS AND BUTTONS ********/
 
 
 /* Bottom-half operations to manipulate LED states */
 void bottom_led_set (led_idx_t ledidx, led_colour_t col) {
        switch (ledidx) {
+       case LED_IDX_HANDSET:
+               ht162x_led_set (13, col, true);
+               break;
+       case LED_IDX_SPEAKERPHONE:
+               ht162x_led_set (11, col, true);
+               break;
        case LED_IDX_MESSAGE:
                //TODO: Figure out which pin -- incorrectly change backlight
        case LED_IDX_BACKLIGHT:
@@ -39,24 +184,278 @@ bool bottom_phone_is_offhook (void) {
 }
 
 
+/* Scan to see if the top_hook_update() function must be called */
+#if !defined NEED_HOOK_SCANNER_WHEN_ONHOOK || !defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
+#  error "The BT200 does not generate an interrupt on hook contact changes"
+#endif
+static bool bt200_offhook = false;
+void bottom_hook_scan (void) {
+       if (bt200_offhook != bottom_phone_is_offhook ()) {
+               bt200_offhook = !bt200_offhook;
+               top_hook_update (bt200_offhook);
+       }
+}
+
+/* Scan to see if the top_button_press() or top_button_release()
+ * functions must be called.
+ *
+ * The following bits are written to activate one or more keyboard rows:
+ * D0..D4 are sent to the variable "kbdisp" which has the proper address.
+ * The intermediate variable "kbdisp_outbuf" stores a copy of the bits,
+ * and is shared with the LCD routines so unused bits must be retained.
+ *
+ * The following bits of McBSP0 are read from PCR0 as keyboard columns:
+ * C0=CLKRP, C1=CLKXP, C2=FSRP, C3=FSXP, C4=DRSTAT
+ *
+ * The following routine is designed from the assumption that the keyboard
+ * is operated a single key at a time; if not, then any response could be
+ * valid.  Note that we do not suppress multiple keys by sending an error
+ * code, or behaving like with key release.
+ */
+#if !defined NEED_KBD_SCANNER_BETWEEN_KEYS || !defined NEED_KBD_SCANNER_DURING_KEYPRESS
+#  error "The BT200 does not generate an interrupt on key changes"
+#endif
+#define KBD_COLUMNS_MASK ( REGVAL_PCR_CLKRP | REGVAL_PCR_CLKXP | REGVAL_PCR_FSRP | REGVAL_PCR_FSXP | REGVAL_PCR_DRSTAT )
+static bool bt200_kbd_pressed = false;
+static const buttoncode_t keynum2code  [25] = {
+       '1',            '2',            '3',            HAVE_BUTTON_MESSAGE,    HAVE_BUTTON_HOLD,
+       '4',            '5',            '6',            HAVE_BUTTON_TRANSFER,   HAVE_BUTTON_CONFERENCE,
+       '7',            '8',            '9',            HAVE_BUTTON_FLASH,      HAVE_BUTTON_MUTE,
+       '*',            '0',            '#',            HAVE_BUTTON_SEND,       HAVE_BUTTON_SPEAKER,
+       HAVE_BUTTON_DOWN, HAVE_BUTTON_UP, HAVE_BUTTON_CALLERS, HAVE_BUTTON_CALLED, HAVE_BUTTON_MENU
+};
+void bottom_keyboard_scan (void) {
+       uint16_t scan;
+       scan = PCR0 & KBD_COLUMNS_MASK;
+       if (bt200_kbd_pressed) {
+               // Respond if the key is released
+               if (scan == KBD_COLUMNS_MASK) {
+                       bt200_kbd_pressed = false;
+                       kbdisp_outbuf &= 0xe0e0;                // Make D0..D4 low
+                       kbdisp = kbdisp_outbuf;
+                       top_button_release ();
+               }
+       } else {
+               // Respond if a key is being pressed
+               if (scan != KBD_COLUMNS_MASK) {
+                       uint16_t row;
+                       for (row = 0; row < 5; row++) {
+                               kbdisp_outbuf |=   0x1f1f;      // Make D0..D4 high
+                               kbdisp_outbuf &= ~(0x0101 << row); // Set D$row low
+                               kbdisp = kbdisp_outbuf;
+                               { volatile int pause = 5; while (pause > 0) pause--; }
+                               scan = PCR0 & KBD_COLUMNS_MASK;
+                               if (scan != KBD_COLUMNS_MASK) {
+                                       uint16_t col;
+                                       for (col = 0; col < 5; col++) {
+                                               if (! (scan & (0x01 << col))) {
+                                                       uint16_t keynum = row * 5 + col;
+                                                       buttonclass_t bcl = ((row <= 3) && (col <= 2))? BUTCLS_DTMF: BUTCLS_FIXED_FUNCTION;
+                                                       buttoncode_t  cde = keynum2code  [keynum];
+                                                       bt200_kbd_pressed = true;
+                                                       top_button_press (bcl, cde);
+                                                       return;
+                                               }
+                                       }
+                               }
+                       }
+                       // Failed, usually due to an I/O glitch
+                       kbdisp_outbuf &= 0xe0e0;                // Make D0..D4 low
+                       kbdisp = kbdisp_outbuf;
+               }
+       }
+}
+
+
+/******** BOTTOM FUNCTIONS FOR FORMATTING / PRINTING INFORMATION ********/
+
+
+/* Send an elapsed period (not a wallclock time) to the display.
+ * For BT200, this is shown in the top digits as MM:SS or as HH:MM.
+ * Note that there are 2 positions, and the first digit can only show a 1.
+ */
+static app_level_t bt200_period_level = APP_LEVEL_ZERO;
+void bottom_show_period (app_level_t level, uint8_t h, uint8_t m, uint8_t s) {
+       if (bt200_period_level > level) {
+               // Ignore those lower values, as this is highly time-dependent
+               return;
+       }
+       bt200_period_level = level;
+       if ((h == 0) && (m <= 19)) {
+               h = m;
+               m = s;
+       }
+       ht162x_led_set (2, false,   false); // "AM" off
+       ht162x_led_set (3, false,   false); // "PM" off
+       ht162x_led_set (1, true,    false); // ":" in "xx:xx"
+       ht162x_led_set (0, h >= 10, false); // "1" in "1x:xx"
+       ht162x_putchar (0, (h %  10) + '0', false);
+       ht162x_putchar (1, (m /  10) + '0', false);
+       ht162x_putchar (2, (m %  10) + '0', false);
+       ht162x_dispdata_notify (0, 3);
+}
+
+/* The level of the main portion of the display, along with an array
+ * with the contents at each level
+ */
+static bt200_displine_level = APP_LEVEL_ZERO;
+static bool    bt200_level_active [APP_LEVEL_COUNT];
+static uint8_t bt200_level_maintext [APP_LEVEL_COUNT] [12];
+static uint8_t bt200_level_dotbits  [APP_LEVEL_COUNT];
+
+/* Internal routine to move a display level to the display.
+ * Note that no "led" style bits other than the dots in the main
+ * line are influenced.
+ */
+static void bt200_displine_showlevel (app_level_t level) {
+       uint8_t i;
+       for (i = 0; i < 12; i++) {
+               ht162x_putchar (14 - i, bt200_level_maintext [level] [i], false);
+       }
+       ht162x_led_set (12, (bt200_level_dotbits [level] & 0x01), false);
+       ht162x_led_set ( 9, (bt200_level_dotbits [level] & 0x02), false);
+       ht162x_led_set ( 6, (bt200_level_dotbits [level] & 0x04), false);
+       ht162x_dispdata_notify (3, 14);
+}
+
+/* Internal routine to send a string to the display, either with or
+ * without setting the various dots.  The dots are coded in bits
+ * 0, 1 and 2 of the dotbits parameter, from left to right.
+ */
+static void bt200_display_showtxt (app_level_t level, char *txt, uint8_t dotbits) {
+       // 1. Print text to the proper level
+       int idx = 0;
+       while ((idx < 12) && *txt) {
+               bt200_level_maintext [level] [idx++] = *txt++;
+       }
+       while (idx < 12) {
+               bt200_level_maintext [level] [idx++] = ' ';
+       }
+       bt200_level_dotbits [level] = dotbits;
+       bt200_level_active [level] = true;
+       // 2. If the level is not exceeded by the current, reveal it
+       if (bt200_displine_level <= level) {
+               bt200_displine_showlevel (level);
+               bt200_displine_level = level;
+       }
+}
+
+
+/* Stop displaying content at the specified level.  In some cases, older
+ * content may now pop up, in others the display could get cleared.
+ */
+void bottom_show_close_level (app_level_t level) {
+       if (bt200_period_level == level) {
+               bt200_period_level = APP_LEVEL_ZERO;
+               ht162x_led_set (0, false, false);
+               ht162x_led_set (1, false, false);
+               ht162x_dispdata [0] = 0x00;
+               ht162x_dispdata [1] = 0x00;
+               ht162x_dispdata [2] = 0x00;
+               ht162x_dispdata_notify (0, 2);
+       }
+       if (bt200_displine_level == level) {
+               bt200_level_active [level] = false;
+               memset (bt200_level_maintext [level], ' ', 12);
+               while ((bt200_displine_level > APP_LEVEL_ZERO)
+                               && !bt200_level_active [bt200_displine_level]) {
+                       bt200_displine_level--;
+               }
+               bt200_displine_showlevel (bt200_displine_level);
+       }
+}
+
+/* Print an IPv4 address on the display */
+void bottom_show_ip4 (app_level_t level, uint8_t bytes [4]) {
+       uint8_t idx;
+       char ip [12];
+       char *ipptr = ip;
+       for (idx = 0; idx < 4; idx++) {
+               *ipptr++ = '0' +  (bytes [idx] / 100);
+               *ipptr++ = '0' + ((bytes [idx] % 100) / 10);
+               *ipptr++ = '0' +  (bytes [idx] % 10);
+       }
+       bt200_display_showtxt (level, ip, 0x07);
+}
+
+void bottom_show_ip6 (app_level_t level, uint16_t bytes [8]) {
+       ;       // Impossible, skip
+}
+
+/* A list of fixed messages, matching the fixed_msg_t values */
+
+static char *bt200_fixed_messages [FIXMSG_COUNT] = {
+       "offline",
+       "registering",
+       "ready",
+       "bootload",
+       "sending call",
+       "ringing",
+       "call ended",
+};
+
+/* Print a fixed message on the main line of the display */
+void bottom_show_fixed_msg (app_level_t level, fixed_msg_t msg) {
+       if (msg < FIXMSG_COUNT) {
+               bt200_display_showtxt (level, bt200_fixed_messages [msg], 0x00);
+       }
+}
+
+/* Print a notification of the number of new / old voicemails */
+void bottom_show_voicemail (app_level_t level, uint16_t new, uint16_t old) {
+       char msg [12];
+       if (new > 999) {
+               new = 999;
+       }
+       memcpy (msg, "xxx messages", 12);
+       msg [0] =  new / 100;
+       msg [1] = (new % 100) / 10;
+       msg [2] =  new        % 10;
+       bt200_display_showtxt (level, msg, 0x00);
+}
+
+/******** BOTTOM LEVEL MAIN PROGRAM ********/
+
+
 /* Setup the connectivity of the TIC55x as used on Grandstream BT20x */
 void main (void) {
+       uint16_t idx;
        led_colour_t led = LED_STABLE_ON;
+       for (idx = 0; idx < APP_LEVEL_COUNT; idx++) {
+               bt200_level_active [idx] = false;
+       }
+       IODIR  |= (1 << 1);
+       IODATA |= (1 << 1);
+{ uint16_t ctr = 250; while (ctr > 0) { ctr--; } }     
        bottom_critical_region_begin (); // _disable_interrupts ();
        IER0 = IER1 = 0x0000;
        tic55x_setup_timers ();
        tic55x_setup_interrupts ();
-       //TODO// IER0 = 0xdefc;
-       //TODO// IER1 = 0x00ff;
+       ht162x_setup_lcd ();
        PCR0 = (1 << REGBIT_PCR_XIOEN) | (1 << REGBIT_PCR_RIOEN);
+
 #if 0
-       while (true) {
-               uint32_t ctr;
-               bottom_led_set (LED_IDX_MESSAGE, led);
-               for (ctr=6500000; ctr>0; ctr--) { ; }
-               led ^= LED_STABLE_ON ^ LED_STABLE_OFF;
-       }
+{uint8_t idx, dig, bar;
+idx=0; dig=0; bar=0;
+memset (ht162x_dispdata, 0x00, sizeof (ht162x_dispdata));
+while (true) {
+uint32_t ctr;
+ht162x_putchar (14 - idx, (dig < 10)? (dig + '0'): (dig + 'A' - 11));
+ht162x_audiolevel ((bar < 8)? (bar << 5): ((14-bar) << 5));
+bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+ht162x_dispdata_notify (14 - idx, 14 - idx);
+ht162x_dispdata_notify (15, 15);
+bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+idx = (idx + 1) % 12;
+dig = (dig + 1) % 38;
+bar = (bar + 1) % 14;
+ctr = 650000; while (ctr>0) ctr--;
+}
+}
 #endif
+
+       //TODO// IER0 = 0xdefc;
+       //TODO// IER1 = 0x00ff;
        top_main ();
 }
 
index 8398df9..e4380ef 100644 (file)
@@ -32,7 +32,7 @@ void bottom_sleep_commit (sleep_depth_t depth) {
                if (depth == SLEEP_HIBERNATE) {
                        // Hibernate: Idle CPU and most I/O
                        ICR = (1 << REGBIT_ICR_CPUI) | (1 << REGBIT_ICR_ICACHEI) | (1 << REGBIT_ICR_MPI) | (1 << REGBIT_ICR_PERI);
-                       PICR = (1 << REGBIT_PICR_MISC) | (1 << REGBIT_PICR_BIOST) | (1 << REGBIT_PICR_WDT) | (1 << REGBIT_PICR_URT) | (1 << REGBIT_PICR_I2C) | (1 << REGBIT_PICR_SP1) | (1 << REGBIT_PICR_SP0);
+                       PICR = /*(1 << REGBIT_PICR_MISC) |*/ (1 << REGBIT_PICR_BIOST) | (1 << REGBIT_PICR_WDT) | (1 << REGBIT_PICR_URT) | (1 << REGBIT_PICR_I2C) | (1 << REGBIT_PICR_SP1) | (1 << REGBIT_PICR_SP0);
                } else {
                        // Snooze: Idle CPU but nothing more
                        ICR = 1 << REGBIT_ICR_CPUI;
index c151bfa..81c0bd6 100644 (file)
 #include <0cpm/cpu.h>
 #include <0cpm/timer.h>
 #include <0cpm/led.h>
+#include <0cpm/kbd.h>
+#include <0cpm/app.h>
+#include <0cpm/show.h>
 
-void top_main (void) {
+
+void top_timer_expiration (timing_t timeout) {
+       /* Keep the linker happy */ ;
+}
+
+void top_hook_update (bool offhook) {
+       /* Keep the linker happy */ ;
+}
+
+
+#define complete_top_main top_main
+
+
+buttonclass_t buttonclass = BUTCLS_NONE;
+buttoncode_t  buttoncode  = BUTTON_NULL;
+
+void top_button_press (buttonclass_t bcl, buttoncode_t cde) {
+       bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
+       buttonclass = bcl;
+       buttoncode  = cde;
+}
+
+void top_button_release (void) {
+       bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
+       buttonclass = BUTCLS_NONE;
+       buttoncode  = BUTTON_NULL;
+}
+
+
+
+/* A simple preliminary test that switches on a LED for as long
+ * as any key is pressed.  Note the brightness of the LED; if it
+ * glows more dimly for the last row than the first, then the
+ * LED is constantly being switched on and off, so there is a
+ * continuous sequence of top_button_press() / top_button_release()
+ * which may be the result of reading the matrix output too fast
+ * after having selecting the matrix input.
+ */
+void keytoled_top_main (void) {
        bottom_critical_region_end ();
        while (true) {
-               TODO: KEYBOARD AND DISPLAY DRIVING CODE
+#if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
+               bottom_keyboard_scan ();
+#endif
+#if defined NEED_HOOK_SCANNER_WHEN_ONHOOK || defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
+               // bottom_hook_scan ();
+#endif
        }
 }
 
+
+/* An experiment to show text describing the button being pressed
+ * for as long as it is being pressed.  On any other times, it will
+ * show how long the phone has been running.
+ */
+void keytodisplay_top_main (void) {
+       bottom_critical_region_end ();
+       bottom_show_fixed_msg (APP_LEVEL_ZERO, FIXMSG_OFFLINE);
+       while (true) {
+#if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
+               bottom_keyboard_scan ();
+#endif
+               if (buttonclass == BUTCLS_NONE) {
+                       bottom_show_close_level (APP_LEVEL_BACKGROUNDED);
+               } else {
+                       timing_t now = bottom_time () / TIME_SEC (1);
+                       uint8_t h, m, s;
+                       s = now % 60;
+                       now = now / 60;
+                       m = now % 60;
+                       h = now / 60;
+                       bottom_show_period (APP_LEVEL_BACKGROUNDED, h, m, s);
+               }
+       }
+}
+
+
+/* The complete application waits for digit keys being entered, and
+ * enters them in an IPv4 number.
+ * and, if need be, scrolls away older content.
+ */
+void complete_top_main (void) {
+       int which = 0;
+       uint8_t ip4 [4];
+       int value = 0;
+       bool processed = false;
+       bottom_critical_region_end ();
+       bottom_show_fixed_msg (APP_LEVEL_BACKGROUNDED, FIXMSG_READY);
+       ip4 [0] = ip4 [1] = ip4 [2] = ip4 [3] = 0x00;
+       while (true) {
+#if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
+               bottom_keyboard_scan ();
+#endif
+               if (buttonclass == BUTCLS_NONE) {
+                       processed = false;
+               } else if (!processed) {
+                       if (buttonclass == BUTCLS_DTMF) {
+                               if ((buttoncode >= '0') && (buttoncode <= '9')) {
+                                       value %= 100;
+                                       value *= 10;
+                                       value += buttoncode - '0';
+                                       if (value > 255) {
+                                               value %= 100;
+                                       }
+                                       ip4 [which] = value;
+                                       bottom_show_ip4 (APP_LEVEL_DIALING, ip4);
+                               } else {
+                                       which++;
+                                       if (which == 4) {
+                                               which = 0;
+                                               bottom_show_close_level (APP_LEVEL_DIALING);
+                                       }
+                                       value = ip4 [which];
+                               }
+                       }
+                       processed = true;
+               }
+       }
+}
index 9b125cc..8dd56ad 100644 (file)
@@ -14,8 +14,17 @@ config PLATFORM_TIC54x
        default y
 
 config PLATFORM_TIC55x
-       bool "tic55x"
+       bool "tic55x (READ HELP)"
        depends on TARGET_GRANDSTREAM_BT20x || TARGET_GRANDSTREAM_GXP20xx
        default y
+       help
+         **Please be careful**
+         The TIC55x platform is not supported by gcc or lvmm compilers.
+         You can download a toolchain at no expense from the TI website,
+         but this will not bring you the freedom that you need to comply
+         to the GPLv3 under which the 0cpm firmerware is released.
+         Please read the file src/driver/tic55x/LICENSE-WARNING.txt about
+         the incompatibility problem between TI's toolchain and the
+         license of the 0cpm firmerware.
 
 endchoice