src/main.cpp

Sun, 25 Oct 2020 22:17:15 +0100

author
David Douard <david.douard@sdf3.org>
date
Sun, 25 Oct 2020 22:17:15 +0100
changeset 34
94ab7ff42a1b
parent 32
bc1d6ecbb0cc
child 35
b2dca6b935bb
permissions
-rw-r--r--

Add a key mapping table (protocol value vs. raw keycode) and send it

Also reformat the file for 2-wspace-tabs

#include "stdio.h"

#include <mbed.h>
#include <rtos.h>
#include <string>

#include "Terminal6x8.h"
#include "Mono19x27.h"
#include "Mono15x22.h"
#include "Arial12x12.h"

#include "SSD1322.h"
#include "hp34comm.h"

#include "QEI.h"
#include "Keypad.h"

// Pins and device declarations
#if defined TARGET_NUCLEO_F446RE
#include "def_f446re.h"
#elif defined TARGET_HP34970_FP_F303RD
#include "def_hp34970_fp.h"
#endif

#include "platform/CircularBuffer.h"


SSD1322 *dsp;
HPSerial *hp;
volatile uint8_t must_refresh;
Thread tdsp, tloop;
Ticker blinker;
Timeout rst_delay;
Timeout splashscreen_timer;
InterruptIn rst(HP_RST);

QEI qenc(KP_ENC1, KP_ENC2, NC, 16);
volatile uint8_t knob;
volatile bool splashscreen;


typedef enum {
  KEY_NONE=0,
  KEY_PRESSED,
  KEY_RELEASED
} key_event_t;

typedef struct keycode {
  uint8_t row;
  uint8_t col;
  key_event_t keyevent;
} keycode_t;

//volatile keycode_t cur_keycode;

#define KEY_BUF_SIZE 10
CircularBuffer<keycode_t, KEY_BUF_SIZE> key_buf;

#define KP_NROWS 4
#define KP_NCOLS 5
DigitalIn kp_rows[KP_NROWS] = {
  KP_R0,
  KP_R1,
  KP_R2,
  KP_R3
};

DigitalOut kp_columns[KP_NCOLS] = {
  KP_C0, KP_C1,
  KP_C2, KP_C3,
  KP_C4
};

/* mapping (RxC)
0x2 0x00:  View
0x1 0x01:  Mon
3x3 0x02:  Sto/Rcl
0x0 0x03:  Scan
1x2 0x04:  Alarm
1x1 0x05:  Mx+B
1x0 0x06:  Measure
2x0 0x07:  Interval
3x2 0x08:  Card Reset
3x1 0x09:  Close
3x0 0x0A:  Open
0x3 0x0B:  Read
2x3 0x0C:  Shift
1x3 0x0D:  Write
0x4 0x0E:  Left
1x4 0x0F:  Right
2x2 0x10:  Advanced
2x1 0x11:  Step
*/

uint8_t kp_mapping[KP_NROWS][KP_NCOLS] = { // [row][column]
  {0x03, 0x01, 0x00, 0x0B, 0x0E},
  {0x06, 0x05, 0x04, 0x0D, 0x0F},
  {0x07, 0x11, 0x10, 0x0C, 0xFF},
  {0x0A, 0x09, 0x08, 0x02, 0xFF}
};


void kp_cb(uint8_t row, uint8_t col);
void kr_cb(uint8_t row, uint8_t col);

Keypad *kpad;
uint8_t curchar;
//uint8_t curcmd;
uint8_t nchars;
char buffer[MAX_BUFF+1];

void timeout_h() {
#if defined(HAS_LED)
  led = !led;
#endif
}

typedef struct _DSP
{
  uint8_t cmd;
  uint8_t color;
  uint8_t bgcolor;
  uint8_t x0;
  uint8_t y0;
  uint8_t fmt; // 0x01=>ascii, 0x02=>hex, 0x04=>bits, 0x08=>flags, 0x80=>ignore
  uint8_t maxsize;
  uint8_t width;
  const unsigned char* font;
  char buffer[MAX_BUFF+1];
} DSP;

static DSP table[] =
{
  { 0x00, 0xF, 0x0,  0,  0, 0x01, MAX_BUFF, 245, Mono19x27}, // main display
  { 0x0C, 0xF, 0x0,196, 34, 0x01, 3,        45,  Mono15x22}, // channels display
  { 0x0A, 0xF, 0x0,  0, 57, 0x08, 4,        0, Terminal6x8}, // flags + bits
};

// 9x10
const unsigned char icon_alarm[] __attribute__((aligned (2))) =
{
  0x1c, 0x0,
  0x3e, 0x0,
  0x7f, 0x0,
  0x7f, 0x0,
  0x7f, 0x0,
  0x7f, 0x0,
  0x7f, 0x0,
  0x7f, 0x0,
  0xff, 0x80,
  0x10, 0x0
};

const unsigned char icon_curve[] __attribute__((aligned (2))) =
{
  0x80, 0x0,
  0x80, 0x0,
  0x80, 0x80,
  0x81, 0x0,
  0x9e, 0x0,
  0xa0, 0x0,
  0xc0, 0x0,
  0x80, 0x0,
  0x80, 0x0,
  0xff, 0x80
 };

typedef struct _FLAG
{
  uint8_t flag;
  uint8_t x;
  uint8_t y;
  bool reverse;
  const char* msg;
  const unsigned char* icon;
} FLAG;

typedef struct _FRAME
{
  uint16_t flag;
  uint8_t x0;
  uint8_t y0;
  uint8_t x1;
  uint8_t y1;
} FRAME;

static const FLAG flags[] =
  {
    // flag, zone, x0, y0, reverse, msg, icon
    // right-side icons area
  { 0x00, 246, 0,  false, NULL, icon_alarm}, // F1.0
    { 0x01, 246, 11, false, NULL, icon_curve}, // F1.1

    // F1.2 == Channel frame
    { 0x03, 197, 27, false, "Channel"},  // F1.3
    // F1.7 == Alarm frame

    { 0x34, 0,  28+8,  false, "MON"},    // F4.4
    { 0x33, 0,  28+16, false, "VIEW"},   // F4.3
    { 0x35, 0,  28,    true, "SCAN"},   // F4.5
    { 0x36, 0,  28+25, true, "CONFIG"},    // F4.6

    { 0x32, 40, 52,    false, "*"},      // F4.2
    { 0x31, 50, 52,    false, "ADRS"},   // F4.1
    { 0x30, 80, 52,    false, "RMT"},    // F4.0
    { 0x27, 104, 52,   true, "ERROR"},    // F3.7

    { 0x26, 140, 52,   false, "EXT"},    // F3.6
    { 0x25, 164, 52,   false, "ONCE"},   // F3.5

    { 0x23, 104, 28+16, false, "MEM"},    // F3.3


    // col 5
    { 0x14, 244, 22,  false, "4W"},     // F2.4
    { 0x15, 244, 30,  false, "OC"},     // F2.5
    { 0x22, 129, 28+16, false, "LAST"},   // F3.2
    { 0x21, 129, 28+16, false, "MIN"},    // F3.1
    { 0x20, 129, 28+16, false, "MAX"},    // F3.0
    { 0x17, 129, 28+16, false, "AVG"},    // F2.7

    { 0x05, 154+0,  17+10, false, "Alarm"},  // F1.5
    { 0x06, 154+0,  17+20, false, "H"},      // F1.6
    { 0x13, 154+6,  17+20, false, "1"},      // F2.3
    { 0x10, 154+12, 17+20, false, "2"},      // F2.0
    { 0x12, 154+18, 17+20, false, "3"},      // F2.2
    { 0x11, 154+24, 17+20, false, "4"},      // F2.1
    { 0x04, 154+30, 17+20, false, "L"},      // F1.4

  };

static const FRAME zones[] =
{ // flag, x0, y0, x1, y1
    { 0x001, 0,   0, 245, 27}, // main display area
    { 0x002, 246, 0, 255, 27}, // right notif area
    { 0x004, 208, 35, 254, 62}, // channels display area
    { 0x008, 160, 28, 202, 54}, // alarms area
    { 0x010, 0,   28, 32,  54}, // flags col1
    { 0x020, 33,  28, 70,  54}, // flags col2
    { 0x040, 71,  28, 103, 54}, // flags col3
    { 0x080, 104, 28, 128, 54}, // flags col4
    { 0x100, 129, 28, 159, 54}, // flags col5

//    { 0x8000, 0, 55, 255, 63}, // flags bits display area
  };

static const FRAME frames[] =
  {
    { 0x02, 194, 30, 243, 53}, // F1.2 - channel frame
    { 0x07, 151, 30, 192, 46}, // F1.7 - alarm frame
  };


#ifdef DEBUG

DigitalOut dbgpin(DBGPIN);
inline void pulse(uint8_t count=1, bool stayup=false)
{
  dbgpin = 0;
  wait_us(2);
  while (count--)
  {
    dbgpin = 1;
    wait_us(2);
    dbgpin = 0;
    wait_us(2);
 }
  if (stayup)
    dbgpin = 1;
}
#else
inline void pulse(uint8_t count=1, bool stayup=false)
{}
#endif

// callbacks & thread functions
void loop();
void copy_to_lcd(void);
void test_dsp();
void reset(void);
void reset_irq(void);
void qei_cb(int dir);
void end_splashscreen(void);
void show(uint8_t, const char*, uint8_t);

/*
#if defined(HAVE_PC)
FileHandle *mbed::mbed_override_console(int fd)
{
    return static_cast<FileHandle*> (&pc);
}
#endif
*/

void setup() {
#if defined(HAVE_PC)
#if   defined(TARGET_NUCLEO_F446RE)
  pc.set_baud(115200);
#endif

/*
#if  defined(TARGET_HP34970_FP_F303RD)
  pc.init();
  pc.connect();
#endif
*/
#endif

  printf("\n\nSETUP\n");
  printf("  System Core Clock = %.3f MHZ\r\n",
     (float)SystemCoreClock/1000000);

  /*
#if defined(HAS_LED)
  printf("Attaching Led 1: %d\n", LED1);
  blinker.attach(callback(timeout_h), 0.5f);
#endif
  */

  hp = NULL;
#if defined(TARGET_NUCLEO_F446RE)
  printf("Serial communication pins\r\n");
  printf("     USBRX=%d\r\n", USBRX);
  printf("     USBTX=%d\r\n", USBTX);
#endif
#if defined(TARGET_HP34970_FP_F303RD)
  printf("Serial communication via USB\r\n");
#endif

  printf("Setup HP communication pins\r\n");
  printf("     HP_RX=%d\r\n", HP_RX);
  DigitalIn(HP_RX).mode(PullDown);
  printf("     HP_TX=%d\r\n", HP_TX);
  DigitalOut(HP_TX).write(1);
  printf("     HP_RST=%d\r\n", HP_RST);
  DigitalIn(HP_RST).mode(PullDown);

  printf("  setup QEI pins\r\n");
  printf("     ENC1=%d\r\n", KP_ENC1);
  DigitalIn(KP_ENC1).mode(PullDown);
  printf("     ENC2=%d\r\n", KP_ENC2);
  DigitalIn(KP_ENC2).mode(PullDown);
  qenc.attach(&qei_cb);

  printf("  setup Keypad\r\n");
  //cur_keycode.keyevent = KEY_NONE;

  kpad = new Keypad(KP_NROWS, kp_rows, KP_NCOLS, kp_columns);
  printf("  attach Keypad callbacks\r\n");
  kpad->attach(&kp_cb, &kr_cb);
  printf("  start Keypad\r\n");
  kpad->start();

  printf("Setup OLED display\r\n");
  // init the LCD
  printf("     DSP_MOSI=%d\r\n", DSP_MOSI);
  printf("     DSP_MISO=%d\r\n", DSP_MISO);
  printf("     DSP_SCLK=%d\r\n", DSP_SCLK);
  printf("     DSP_CS=%d\r\n", DSP_CS);
  printf("     DSP_RST=%d\r\n", DSP_RST);
  printf("     DSP_DC=%d\r\n", DSP_DC);
  dsp = new SSD1322(20000000, DSP_MOSI, DSP_MISO, DSP_SCLK, DSP_CS,
        DSP_RST, DSP_DC, "SSD1322");

  printf("  configure DSP\r\n");
  dsp->background(Black);    // set background to black
  dsp->foreground(0xF);
  dsp->cls();

  //curcmd = 0xFF;
  curchar = 0;
  nchars = 0;

  for (uint8_t i=0; i<sizeof(table)/sizeof(table[0]); ++i)
    memset(table[i].buffer, 0, MAX_BUFF+1);

  printf("  display splash screen\r\n");
  dsp->locate(30, 10);
  dsp->set_font((unsigned char*)Mono19x27);
  dsp->printf("HP34970A");
  dsp->set_font((unsigned char*)Terminal6x8);
  dsp->locate(90, 40);
  dsp->printf("David Douard");
  dsp->locate(0, 52);
  dsp->printf("Clock = %d ", SystemCoreClock);

  RCC_OscInitTypeDef cfg;
  HAL_RCC_GetOscConfig(&cfg);
  if (cfg.HSEState == RCC_HSE_BYPASS)
    dsp->printf("HSE:EXT ");
  else if (cfg.HSEState == RCC_HSE_ON)
    dsp->printf("HSE:XTAL ");
  else
    dsp->printf("HSE:OFF ");

  if (cfg.HSIState == RCC_HSI_ON)
    dsp->printf("HSI:ON ");
  else
    dsp->printf("HSI:OFF ");

  dsp->copy_to_lcd();

  printf("Starting LCD thread\r\n");
  tdsp.start(&copy_to_lcd);

  printf("Starting Event thread\r\n");
  tloop.start(&loop);

  /*
  dsp->clrbuff();
  show(0x00, "HH:MM:\tSS\t:mmmm", 15); // main dsp
  show(0x0C, "888", 3); // channel dsp
  show(0x0A, "\xFF\xFF\xFF\xFF", 4); // all flags
  */

  printf("Attaching timers\r\n");
  splashscreen = true;
  splashscreen_timer.attach(callback(&end_splashscreen), 2);
  rst.fall(&reset_irq);

  printf("SETUP DONE\r\n");
}

void end_splashscreen(void)
{
  // print is forbidden here because we are in an ISR context here
  //printf("End of splash screen CB\r\n");
  splashscreen = false;
}

void reset_irq(void)
{
  rst_delay.attach(callback(&reset), 0.1);
}

void reset(void)
{
  if (DigitalIn(HP_RST).read() == 0) {
    if (hp == NULL) {
      printf("setup HP communication handler\r\n");
      hp = new HPSerial(HP_TX, HP_RX);
    }

    printf("!! RST !! (gstate=%d, state=%d)\r\n",
     hp->gstate(), hp->state());
    //printf("Value is ... %X\n", hp->search());
    hp->startup();
  }
}

void copy_to_lcd(void) {
  //uint8_t mask=1;

  while(1) {
    pulse(0, true);
    if ((splashscreen == false) && (must_refresh)) {
      must_refresh = 0;
      //Thread::wait(20); // give a bit of time for some more cmds
      dsp->copy_to_lcd();
    }

    /*
    if (must_refresh & mask) {
      for(uint8_t i=0; i<sizeof(zones)/sizeof(zones[0]); i++)
  if (zones[i].flag == mask) {
    dsp->copy_to_lcd(zones[i].x0/4, (zones[i].x1+3)/4,
        zones[i].y0,   zones[i].y1);
    must_refresh &= ~mask;
    break;
  }
    }
    mask = mask << 1;
    if (mask == 0) {
      mask = 1;
    }
    */
    pulse(0, false);

  ThisThread::sleep_for(30);
  }
}

void show(uint8_t cmd, const char *intxt, uint8_t nchar=0)
{
  uint8_t i;
  // uint8_t len;
  uint16_t bgcolor, fgcolor;
  char *oldv;
  // char *txt;
  char *txtp;
  static char txt[256];


  if (cmd == 0xFF) // cls
  {
    dsp->clrbuff();
  }
  else
  {
    //txt = (char *)malloc(strlen(intxt)+1);
    strcpy(txt, intxt);
    txtp = txt;

    pulse(1, true);

    // len = MAX_BUFF;

    for (i=0; i<sizeof(table)/sizeof(table[0]); ++i) {
      if (table[i].cmd == cmd) {
        bgcolor = table[i].bgcolor;
        fgcolor = table[i].color;
        dsp->background(bgcolor);
        dsp->foreground(fgcolor);
        dsp->set_font((unsigned char*) table[i].font);
        oldv = table[i].buffer;

        dsp->locate(table[i].x0, table[i].y0);

        if (table[i].fmt & 0x01)  // ASCII text
        {
          if (strncmp(oldv, txt, table[i].maxsize) != 0)
          {
            if (table[i].width > 0)
              dsp->fillrect(table[i].x0,
                      table[i].y0,
                      table[i].x0 + table[i].width,
                      table[i].y0 + table[i].font[2],
                      bgcolor);
            for (uint8_t k=0; ;k++)
            {
              if (txtp[k] == 0x00)
              {
                dsp->printf(txtp);
                break;
              }
              if (txtp[k] == 0x09)
              { // \t is a special char for 'unselected' display value
                txtp[k] = 0x00;
                dsp->printf(txtp);

                if (fgcolor == table[i].color)
                  fgcolor /= 2;
                else
                  fgcolor = table[i].color;
                dsp->foreground(fgcolor);
                txtp = &(txtp[k+1]);
                k = 0;
              }
            }
            if (cmd == 0x00) // main area
              must_refresh |= 0x01;
            if (cmd == 0x0C) // channels area
              must_refresh |= 0x04;
          }
        }
        /*
          if (table[i].fmt & 0x02 ) {
          // hex
          for (uint8_t j=0;; j++) {
          if (txt[j] == 0x00)
          break;
          dsp->printf("%02X ", txt[j]);
          }
          for (uint8_t j=3*strlen(txt); j<table[i].maxsize; j++)
          dsp->printf(" ");
          }
        */
        if (table[i].fmt & 0x08 )  // flag indicators
        {
          // flags
          for (uint8_t j=0; j<max(nchar, table[i].maxsize) ; j++)
          {
            for (uint8_t k=0; k<8; k++)
            {
              if (1)
              { //(txt[j] & (1 << k) ) != (oldv[j] & (1 << k))) {
                for (uint8_t l=0;
                     l<(sizeof(flags)/sizeof(flags[0])); ++l)
                {
                  if (flags[l].flag == ((j<<4) + k)) {
                    if (txtp[j] & (1 << k))
                    {
                      dsp->foreground(flags[l].reverse ? bgcolor : fgcolor);
                      dsp->background(flags[l].reverse ? fgcolor : bgcolor);
                    }
                    else
                    {
                      dsp->foreground(bgcolor);
                      dsp->background(bgcolor);
                    }
                    if (flags[l].msg != NULL)
                    { // a string
                      dsp->locate(flags[l].x, flags[l].y);
                      dsp->printf(flags[l].msg);}
                    else
                    { // an icon
                      Bitmap_s pic = {9, 10, 2, (char*) flags[l].icon};
                      dsp->Bitmap_BW(pic, flags[l].x, flags[l].y);
                    }
                    must_refresh = 1; //|= zones[m].flag;
                    break;
                  }
                }
              }
            }
          }

          // draw frames (Alarm and Channel)
          for (uint8_t l=0;
               l<(sizeof(frames)/sizeof(frames[0])); ++l)
          {
            uint16_t color;
            if (frames[l].flag & txt[0]) // frame flags are on the 1st byte only
              color = fgcolor/6;
            else
              color = bgcolor;
            dsp->hline(frames[l].x0+1, frames[l].x0+3, frames[l].y0, color);
            dsp->hline(frames[l].x1-3, frames[l].x1-1, frames[l].y0, color);
            dsp->hline(frames[l].x0+1, frames[l].x1-1, frames[l].y1, color);

            dsp->vline(frames[l].x0, frames[l].y0+1, frames[l].y1-1, color);
            dsp->vline(frames[l].x1, frames[l].y0+1, frames[l].y1-1, color);
          }
        }

        for(uint8_t j=0; j<table[i].maxsize; j++)
          oldv[j] = txt[j];
        break;
      }
    }
    //free(txt);
    //dsp->copy_to_lcd();
    pulse(1, false);
  }
}

void test_dsp()
{
  const FRAME *z;
  printf("TEST DSP\r\n");
  dsp->cls();
  printf("TEST DSP #2\r\n");
  show(0x00, "8g8g8g8g8g8g8", 13); // main dsp
  show(0x0C, "888", 3); // channel dsp
  show(0x0A, "\xFF\xFF\xFF\xFF", 4); // all flags
  dsp->copy_to_lcd();
  ThisThread::sleep_for(3);
  dsp->cls();
  printf("TEST DSP #3\r\n");

  for (uint8_t i=0; i<(sizeof(zones)/sizeof(zones[0])); i++)
    {
      z = &zones[i];
      dsp->fillrect(z->x0, z->y0, z->x1, z->y1, 4+i);
      dsp->locate(z->x0+1, z->y0+1);
      dsp->printf("%d", i);
    }

  /*
  for (uint8_t i=0; i<(sizeof(zones)/sizeof(zones[0])); i++)
    {
      z = &zones[i];
      printf("Zone %d [%x]: %d, %d, %d, %d\n", i, z->flag,
    z->x0, z->y0, z->x1, z->y1);
      must_refresh = z->flag;
      wait(1);
    }
  printf("Done\n");
  wait(2);
  printf("Copy ALL\n");
  dsp->copy_to_lcd();
  */
  ThisThread::sleep_for(2);
  dsp->cls();
  printf("TEST DSP DONE\r\n");
}


void loop()
{ // run over and over
  keycode_t key;

  unsigned int err[8];
  for (uint8_t i=0; i<8; i++)
    err[i] = 0;
  int p, pp;  // rot encoder pulse counters
  p = 0;
  pp = 0;

  while(1) {
    p = qenc.getPulses();
    if (p != pp)
  {
    dsp->locate(0, 0);
    dsp->printf("Pulses = %d  ", p);
      dsp->copy_to_lcd();
    pp = p;
    }

    if (knob != 0)
  {
    if (hp != NULL)
    {
    printf("Sending keycode %X\r\n", knob);
    hp->sendkey(knob);
    printf("   DONE\r\n");
    }
    else
    {
      dsp->locate(70, 0);
      dsp->printf("Knob = %X  ", knob);
      dsp->copy_to_lcd();
    }
    knob = 0;
  }

    if (!key_buf.empty()) //cur_keycode.keyevent != KEY_NONE)
	{
	  key_buf.pop(key);
	  printf("Keycode %dx%d: %s\r\n",
			 key.row, key.col, key.keyevent==KEY_PRESSED?"pressed":"released");
	  if (hp != NULL) {
		hp->sendkey(kp_mapping[key.row][key.col]);
	  }
	  else
	  {
		dsp->locate(140, 0);
		dsp->printf("KC: %dx%d[%X] %s",
					key.row, key.col, kp_mapping[key.row][key.col],
					key.keyevent==KEY_PRESSED?"PRE":"REL");
		dsp->copy_to_lcd();
	  }
	  // cur_keycode.keyevent = KEY_NONE;
  }


    if ((hp != NULL) && (hp->cmd_available()))
      {
    HPSerial::CMD cmd;
    if (hp->pop(cmd))
        {
#if defined(HAS_LED)
      led = 1;
#endif
        for (uint8_t i=0; i<7; i++)
            if (hp->nerrors(i) > err[i]) {
            printf("ERR: %d/%d/%d/%d/%d/%d/%d\r\n",
               hp->nerrors(0),
               hp->nerrors(1),
               hp->nerrors(2),
               hp->nerrors(3),
               hp->nerrors(4),
               hp->nerrors(5),
               hp->nerrors(6)
               );
            break;
          }
          for (uint8_t i=0; i<7; i++)
            err[i] = hp->nerrors(i);

          printf("CMD[%d] %02X", (int)cmd.id, cmd.cmd);

          if ((cmd.cmd == 0x00) || (cmd.cmd == 0x0C))
            printf(": '%s'\r\n", cmd.value);
          else {
          printf(":");
            for (uint8_t i=0; i<cmd.size; i++)
            printf("%02x ", cmd.value[i]);
            printf("\r\n");
        }
          show(cmd.cmd, cmd.value, cmd.size);
#if defined(HAS_LED)
      led = 0;
#endif
        }
    }
  //else
  ThisThread::sleep_for(1);
  }
}

void qei_cb(int dir)
{
  if(dir == 1) // turn right
    knob = 0x80;
  else         // turn left
  knob = 0x81;  // 83?
}

void kp_cb(uint8_t row, uint8_t col)
{
  keycode_t key;
    key.row = row;
    key.col = col;
    key.keyevent = KEY_PRESSED;
  if(!key_buf.full())
    key_buf.push(key);
}

void kr_cb(uint8_t row, uint8_t col)
{
  keycode_t key;
    key.row = row;
    key.col = col;
    key.keyevent = KEY_RELEASED;
  if(!key_buf.full())
    key_buf.push(key);
}

int main()
{
  setup();
  printf("Main loop (noop)\r\n");
  while(1)
  {
    timeout_h();
    ThisThread::sleep_for(1);
  }
}

mercurial