src/main.cpp

Sun, 25 Oct 2020 23:00:17 +0100

author
David Douard <david.douard@sdf3.org>
date
Sun, 25 Oct 2020 23:00:17 +0100
changeset 36
a6c7292742a0
parent 35
b2dca6b935bb
child 37
07e8ca2bdf6d
permissions
-rw-r--r--

Add support for the shift flag

#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;
bool shift;  // true when kp is shifted, cleared by command 0x01 from Unit
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
};

/* key mapping
   RxC   code   name
	 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] = {
		{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;

	shift = false;
	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) {
				uint8_t keycode = kp_mapping[key.row][key.col];
				if (key.keyevent == KEY_RELEASED)
					keycode |= 0x40;  // bit 6: key relased
				if (shift)
					keycode |= 0x20;  // bit 5: key shifted

				hp->sendkey(kp_mapping[key.row][key.col]);
			}
			else
			{
				dsp->locate(140, 0);
				dsp->printf("KC: %dx%d[0x%s%X] %s",
										key.row, key.col,
										kp_mapping[key.row][key.col] <= 0x0F ? "0" : "",
										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);

				// 0x00: main display
				// 0x0C: channel display
				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");
				}

				if (cmd.cmd == 0x01) {
          // clear a flag
					if (cmd.value[0] == 0x0E) {
            // clear the Shift flag
						shift = false;
					}
				} else if (cmd.cmd == 0x86) {
          // shutdown
					// TODO
				} else {
          // display related commands
					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