src/main.cpp

Mon, 05 Nov 2018 23:18:37 +0100

author
David Douard <david.douard@logilab.fr>
date
Mon, 05 Nov 2018 23:18:37 +0100
changeset 21
9ffa9d727d80
parent 19
a52d60613cf7
child 22
2f51221af82d
permissions
-rw-r--r--

wip

#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"

/******************************************************/
/*                 L432KC                             */
/******************************************************/
#if (defined STM32L432xx)
// display
#define DSP_MOSI PA_7 //A6
#define DSP_MISO PA_6 //A5
#define DSP_SCLK PA_5 //A4
#define DSP_CS   PB_0 //D3
#define DSP_RST  PB_5 //D11
#define DSP_DC   PB_4 //D12

// UART for RX (CPU->DP) and TX (DP->CPU) combined
#define HP_TX PA_9 // serial1 TX
#define HP_RX PA_10 // serial1 RX

// RST pin (handle this by hand)
#define HP_RST PA_0

// misc
#define DBGPIN NC

// encoder
#define KP_ENC1 PA_8
#define KP_ENC2 PA_11

// keypad
#define KP_R0 PA_1
#define KP_R1 PA_3
#define KP_R2 PA_4
#define KP_R3 PA_12

#define KP_C0 D4
#define KP_C1 D5
#define KP_C2 D6
#define KP_C3 D7
#define KP_C4 D8

/******************************************************/
/*                 F446RE                             */
/******************************************************/
#elif defined STM32F446xx
// UART
// USBTX PA_2
// USBRX PA_3
// display
#define DSP_MOSI PB_15 // blue
#define DSP_MISO NC
#define DSP_SCLK PB_13 // yellow
#define DSP_CS   PB_12 // green
#define DSP_RST  PB_5 // green
#define DSP_DC   PB_4 // red

// UART for RX (CPU->DP)
#define HP_RX PC_11 // serial3 RX
#define HP_TX PC_10 // serial3 TX

// RST pin (handle this by hand)
#define HP_RST PC_12

// encoder
#define KP_ENC1 PC_4
#define KP_ENC2 PC_5

// keypad
#define KP_R0 PC_0   //  I-6
#define KP_R1 PC_1   // II-5
#define KP_R2 PC_2   //  I-5
#define KP_R3 PC_3   // II-4


#define KP_C0 PB_0   //  I-4
#define KP_C1 PA_6   //  I-2
#define KP_C2 PA_7   //  I-3
#define KP_C3 PA_5   //  I-1
#define KP_C4 PD_2   // II-1

// misc
#define DBGPIN PC_6

#endif

#ifdef HAVE_PC
Serial pc(USBTX, USBRX);
#endif

SSD1322 *dsp;
HPSerial *hp;
volatile uint8_t must_refresh;
Thread tdsp, tloop;
Ticker blinker;
Timeout rst_delay;
Timeout splashscreen_timer;
DigitalOut led(LED1);
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;

PinName kp_rows[] = {
  KP_R0,
  KP_R1,
  KP_R2,
  KP_R3
};

PinName kp_colums[] = {
  KP_C0, KP_C1,
  KP_C2, KP_C3,
  KP_C4
};

DigitalIn kp_in[] = {
  KP_R0,
  KP_R1,
  KP_R2,
  KP_R3
};

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

uint8_t kp_nrows = sizeof(kp_in)/sizeof(kp_in[0]);
uint8_t kp_ncols = sizeof(kp_out)/sizeof(kp_out[0]);

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 cmd;
uint8_t nchars;
char buffer[MAX_BUFF+1];

void timeout_h() {
  led = !led;
}

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,204, 38, 0x01, 3,        45,  Mono15x22}, // channels display
  //  { 0x01, 0xF,   0x0,  0,  0, 0x80, MAX_BUFF, 0, Terminal6x8},
  //  { 0x02, 0xF,   0x0,  0,  0, 0x80, MAX_BUFF, 0, Terminal6x8},
  { 0x0A, 0xF,   0x0,  0, 57, 0x0C, 4,        0, Terminal6x8}, // flags + bits
  //  { 0xFF, 0xF,   0x0,  0,  0, 0x80, MAX_BUFF, 0, Terminal6x8},
};

// 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;
  uint16_t zone;
  uint8_t x;
  uint8_t y;
  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, msg, icon
    // right-side icons area
    { 0x00, 0x02, 0, 0,  NULL, icon_alarm}, // F1.0
    { 0x01, 0x02, 0, 11, NULL, icon_curve}, // F1.1
    // F1.2 == Channel frame
    { 0x03, 0x04, 1, 2, "Channel"},  // F1.3
	// F1.7 == Alarm frame

    // col 1
    { 0x34, 0x10, 0,  0,  "MON"},    // F4.4
    { 0x33, 0x10, 0,  8,  "VIEW"},   // F4.3
    { 0x35, 0x10, 0,  16, "SCAN"},   // F4.5

    //col 2
    { 0x32, 0x20, 0, 0,   "*"},      // F4.2
    { 0x36, 0x20, 0, 8,   "CFG"},    // F4.6
    { 0x27, 0x20, 0, 16,  "ERR"},    // F3.7

    // col 3
    { 0x41, 0x040, 0, 0,  "ADRS"},   // F4.1
    { 0x40, 0x040, 0, 8,  "RMT"},    // F4.0

    // col 4
    { 0x26, 0x080, 0, 0,  "EXT"},    // F3.6
    { 0x25, 0x080, 0, 8,  "ONCE"},   // F3.5

    { 0x23, 0x080, 0, 16, "MEM"},    // F3.3


    // col 5
    { 0x14, 0x100, 0, 0,  "4W"},     // F2.4
    { 0x15, 0x100, 0, 8,  "OC"},     // F2.5
    { 0x22, 0x100, 0, 16, "LST"},    // F3.2
    { 0x21, 0x100, 0, 16, "MIN"},    // F3.1
    { 0x20, 0x100, 0, 16, "MAX"},    // F3.0
    { 0x17, 0x100, 0, 16, "AVG"},    // F2.7

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

  };

static const FRAME zones[] =
  {
    { 0x001, 0,   0, 245, 27}, // main display area
    { 0x002, 246, 0, 255, 27}, // right notif area
    { 0x004, 203, 28, 255, 54}, // 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, 203, 35, 255, 54}, // F1.2 - channel frame
    { 0x07, 160, 28, 202, 54}, // 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 setup() {
#ifdef HAVE_PC
  pc.baud (115200);
#endif

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

  //printf("Attaching Led 1: %d\n", LED1);
  //blinker.attach(callback(timeout_h), 0.5f);

  hp = NULL;
  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(PullUp);
  printf("     ENC2=%d\r\n", KP_ENC2);
  DigitalIn(KP_ENC2).mode(PullUp);
  qenc.attach(&qei_cb);

  printf("  setup Keypad\r\n");
  cur_keycode.keyevent = KEY_NONE;
  uint8_t nrows = sizeof(kp_rows)/sizeof(kp_rows[0]);
  uint8_t ncols = sizeof(kp_colums)/sizeof(kp_colums[0]);

  kpad = new Keypad(nrows, kp_in, ncols, kp_out);
  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");
  splashscreen = true;
  // 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");
  //dsp.set_orientation(3);
  printf("  configure DSP\r\n");
  // myLCD.set_font((unsigned char*) Terminal6x8);
  // myLCD.claim(stdout);      // send stdout to the LCD display
  // myLCD.claim(stderr);      // send stderr to the LCD display
  dsp->background(Black);    // set background to black
  dsp->foreground(0xF);
  dsp->cls();

  cmd = 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->copy_to_lcd();

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

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

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

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

void end_splashscreen(void)
{
  printf("End of splash screen\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);
    Thread::wait(30);
  }
}

void show(uint8_t cmd, const char *intxt, uint8_t nchar=0) {
  uint8_t i, len;
  uint16_t bgcolor, fgcolor;
  char *oldv;
  char *txt;


  txt = (char *)malloc(strlen(intxt)+1);
  strcpy(txt, intxt);
  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 ) {
	if (strncmp(oldv, txt, table[i].maxsize) != 0) {
	  // ascii
	  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 (txt[k] == 0x00)
	      {
		dsp->printf(txt);
		break;
	      }
	    if (txt[k] == 0x09) { // \t is a special char for 'unselected' display value
	      txt[k] = 0x00;
	      dsp->printf(txt);

	      if (fgcolor == table[i].color)
		fgcolor /= 2;
	      else
		fgcolor = table[i].color;
	      dsp->foreground(fgcolor);
	      txt = &(txt[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 & 0x04 ) {
      // binary
	dsp->foreground(fgcolor);
	dsp->printf(" [");
	for (uint8_t j=0; j<max(nchar, table[i].maxsize) ; j++) {
	  if (j>0) {
	    dsp->foreground(fgcolor);
	    dsp->printf(" | ");
	  }
	  for (uint8_t k=0; k<8; k++) {
	    if (txt[j] & (1 << (7-k)))
	      dsp->foreground(fgcolor);
	    else
	      dsp->foreground(bgcolor);
	    dsp->printf("%d", (8-k));
	  }
	}
	dsp->foreground(fgcolor);
	dsp->printf("]");
	must_refresh |= 0x8000;
      }

      if (table[i].fmt & 0x08 ) {
      // 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))) {

	      if (txt[j] & (1 << k))
		dsp->foreground(fgcolor);
	      else
		dsp->foreground(bgcolor);

	      /*
	      for (uint8_t l=0;
		   l<(sizeof(frames)/sizeof(frames[0])); ++l) {
		if (frames[l].flag & ((j<<4) + k))
		  dsp->fillrect(frames[l].x0, frames[l].y0,
			       frames[l].x1, frames[l].y1,
			       fgcolor/8);
		else
		  dsp->fillrect(frames[l].x0, frames[l].y0,
			       frames[l].x1, frames[l].y1,
			       bgcolor);

	      }
	      */

	      for (uint8_t l=0;
		   l<(sizeof(flags)/sizeof(flags[0])); ++l) {
		if (flags[l].flag == ((j<<4) + k)) {
		  for (uint8_t m=0; m<(sizeof(zones)/sizeof(zones[0])); m++) {
		    if (flags[l].zone == zones[m].flag) {
		      if (flags[l].msg != NULL) { // a string
			dsp->locate(flags[l].x + zones[m].x0,
				   flags[l].y + zones[m].y0);
			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 + zones[m].x0,
				      flags[l].y + zones[m].y0);
		      }
		      must_refresh |= zones[m].flag;
		      break;
		    }
		  }
		  break;
		}
	      }
	    }
	  }
	}
      }

      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;
  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();
  wait(3);
  dsp->cls();


  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();
  */
  wait(2);
  dsp->cls();
}


void loop()
{ // run over and over
  unsigned int err[8];
  for (uint8_t i=0; i<8; i++)
    err[i] = 0;
  int p, pp;
  p = 0;
  pp = 0;
  while(1) {
    if (knob != 0)
	{
	  if (hp != NULL)
	  {
		printf("Sending keycode %X\r\n", knob);
		hp->sendkey(knob);
		printf("   DONE\r\n");
	  }
	  knob = 0;
	}

    if (cur_keycode.keyevent != KEY_NONE)
	{
	  printf("Keycode %dx%d: %s\r\n",
			 cur_keycode.row, cur_keycode.col,
			 cur_keycode.keyevent==KEY_PRESSED?"pressed":"released");
	  cur_keycode.keyevent = KEY_NONE;
	}

    p = qenc.getPulses();
    if (p != pp)
	{
      printf("Pulses = %d\r\n", p);
      pp = p;
    }

    if ((hp != NULL) && (hp->cmd_available()))
      {
		HPSerial::CMD cmd;
		if (hp->pop(cmd))
    	  {
			led = 1;
    		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);
			led = 0;
    	  }
	  }
	//else
	Thread::wait(1);
  }
}

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

void kp_cb(uint8_t row, uint8_t col)
{
    cur_keycode.row = row;
    cur_keycode.col = col;
    cur_keycode.keyevent = KEY_PRESSED;
}

void kr_cb(uint8_t row, uint8_t col)
{
    cur_keycode.row = row;
    cur_keycode.col = col;
    cur_keycode.keyevent = KEY_RELEASED;
}

int main()
{
  setup();
  printf("Main loop (noop)\r\n");
  while(1)
    wait(.1);
}

mercurial