src/main.cpp

Sun, 01 Nov 2020 22:21:19 +0100

author
David Douard <david.douard@sdf3.org>
date
Sun, 01 Nov 2020 22:21:19 +0100
changeset 44
b3c3d54d2c7c
parent 38
ffef9bbb345d
child 48
fc55f6eaa8bc
permissions
-rw-r--r--

Many improvements

- add support for dimm-based selection,
- add support for poweroff (at least power thr display off),
- add support for the initial key pressed during initialization sequence,
- fix a race condition (sending a keycode while receiving a message)
- add support for the shift button
- many code cleanups and improvements

#include "stdio.h"

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

#include "hp34comm.h"
#include "display.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"


Display *dsp;
volatile bool splashscreen;
HPSerial *hp;
Thread tdsp(osPriorityNormal, OS_STACK_SIZE, nullptr, "DSP");
Ticker dsp_refresh;
Timeout rst_delay;
Timeout splashscreen_timer;
Timeout byescreen_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
bool must_reset;
bool must_shutdown;

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;


#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}
};

#define KC_SHIFT 0x0C

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

Keypad *kpad;
keycode_t last_key = {0, 0, KEY_NONE};

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

void refresh_display(void);

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

#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 reset(void);
void reset_irq(void);
void qei_cb(int dir);
void end_splashscreen(void);


#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_HP34970_FP_F303RD)
  pc.init();
  pc.connect();
  #endif
*/
#endif

  printf("\n\nSETUP\n");
  printf("  System Core Clock = %ld MHZ\r\n", 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");

  shift = false;
  must_reset = false;
  must_shutdown = 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 Display(20000000, DSP_MOSI, DSP_MISO, DSP_SCLK, DSP_CS,
            DSP_RST, DSP_DC, "SSD1322");

  //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->show_splashscreen();

  printf("Starting LCD thread\r\n");
  // does not compile...
  // dsp_refresh.attach(callback(dsp, &Display::copy_to_lcd), 50ms);
  tdsp.start(&refresh_display);

  printf("Attaching timers\r\n");
  splashscreen = true;
  splashscreen_timer.attach(callback(&end_splashscreen), 2ms);
  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_tmr(void)
{
	must_reset = true;
}

void reset_irq(void)
{
	rst_delay.attach(callback(&reset_irq_tmr), 50ms);
}

void reset(void)
{
  // this should be called as a result of the HP_RST pin going LO
  printf("Reset connection to the main unit\n");
  if (DigitalIn(HP_RST).read() == 0) {
    if (hp == NULL) {
      printf("setup HP communication handler\r\n");
      hp = new HPSerial(HP_TX, HP_RX);
    }
	else {
		printf("Connection already initialized\n");
	}

    printf("!! RST !! (gstate=%d, state=%d)\r\n",
           hp->gstate(), hp->state());
    //printf("Value is ... %X\n", hp->search());
	dsp->power_on();
	dsp->cls();
    printf("Initiate startup sequence\n");
	if (last_key.keyevent == KEY_PRESSED)
		hp->startup(kp_mapping[last_key.row][last_key.col]);
	else
		hp->startup();
  }
  else
  {
	  printf("HP_RST is not LOW, skipping\n");
  }
}

void refresh_display(void) {
	while(1) { //!must_shutdown) {
		dsp->copy_to_lcd();
		ThisThread::sleep_for(50ms);
	}
}

void shutdown(void)
{
  must_shutdown = true;
}

void mainloop()
{ // run over and over
  keycode_t key = {0, 0, KEY_NONE};
  uint8_t keycode;  // actual sent value to the CPU
  HPSerial::CMD cmd;
  unsigned int nkeys = 0;
  unsigned int err[8];
  for (uint8_t i=0; i<8; i++)
    err[i] = 0;

  while(1) {
	if (must_reset) {
	  must_reset = false;
	  reset();
	}
	if (must_shutdown) {
		//tdsp.join();
		//dsp_refresh.detach();
		must_shutdown = false;
		dsp->power_off();
	}

    if (knob != 0)
    {
      if (hp != NULL)
      {
        printf("KEY[%d] %s%X\n", nkeys++, knob<0x0F ? "0" : "", knob);
        hp->sendkey(knob);
      }
      else
      {
        dsp->locate(70, 0);
        dsp->printf("Knob = %X  ", knob);
        dsp->copy_to_lcd();
      }
      knob = 0;
    }

    if (!key_buf.empty())
    {
      key_buf.pop(key);
	  keycode = kp_mapping[key.row][key.col];

	  if ((keycode == KC_SHIFT) && (key.keyevent == KEY_PRESSED))
	  {
		  shift = true;
		  dsp->shift_on();
	  }

      if (hp != NULL) {
        if ((shift) && (keycode != KC_SHIFT))
		{
          keycode |= 0x20;  // bit 5: key shifted
		  shift = false;
		  dsp->shift_off();
		}
        if (key.keyevent == KEY_RELEASED)
          keycode |= 0x40;  // bit 6: key relased
        printf("KEY[%d] %s%X\n", nkeys++, keycode<0x0F ? "0" : "", keycode);
        hp->sendkey(keycode);
      }
      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();
      }
    }

	// at each loop iteration, send buffered keycodes, if any
	if (hp != NULL)
	  hp->send_key_when_idle();

    if ((hp != NULL) && (hp->cmd_available()))
    {
      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: %X/%X/%X/%X/%X/%X/%X\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] %s%X", (int)cmd.id, cmd.cmd<0x10 ? "0" : "", cmd.cmd);

        // 0x00: main display
        // 0x0C: channel display
        if ((cmd.cmd == 0x00) || (cmd.cmd == 0x0C))
          printf(": '%s'\n", cmd.value);
        else {
          printf(": ");
          for (uint8_t i=0; i<cmd.size; i++)
			  printf("%s%X ", cmd.value[i] < 0x10 ? "0" : "", cmd.value[i]);
          printf("\n");
        }

        if (cmd.cmd == 0x01) {
          // clear a flag
          if (cmd.value[0] == 0x0E) {
            // clear the Shift flag
            shift = false;
			dsp->shift_off();
          }
        } else if (cmd.cmd == 0x86) {
			// shutdown
			dsp->show_byescreen();
			byescreen_timer.attach(callback(&shutdown), 2s);
         } else {
          // display related commands
          dsp->show(cmd.cmd, cmd.value, cmd.size);
        }
#if defined(HAS_LED)
        led = 0;
#endif
      }
    }
    //else
    ThisThread::sleep_for(1ms);
  }
}


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)
{
  last_key.row = row;
  last_key.col = col;
  last_key.keyevent = KEY_PRESSED;
  if(!key_buf.full())
    key_buf.push(last_key);
}

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

int main()
{
  setup();
  printf("Main loop (noop)\r\n");
  mainloop();
}

mercurial