src/main.cpp

Thu, 15 Oct 2020 01:11:03 +0200

author
David Douard <david.douard@sdfa3.org>
date
Thu, 15 Oct 2020 01:11:03 +0200
changeset 26
86f099bda525
parent 23
daf26b083899
child 28
424d792fea4f
permissions
-rw-r--r--

Several stuff

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


/******************************************************/
/*                 F446RE                             */
/******************************************************/
#if defined STM32F446xx
// UART
// USBTX PA_2
// USBRX PA_3
// display
#define DSP_MOSI PB_15 // blue
#define DSP_MISO PB_14 // 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_10   //  I-1
#define KP_C4 PD_2   // II-1

// misc
#define DBGPIN PC_6

#elif defined STM32F303xE  // HP34970 replacement PCB

#define DSP_MOSI PA_7
#define DSP_MISO PA_6 // NC
#define DSP_SCLK PA_5
#define DSP_CS   PA_2
#define DSP_RST  PA_3
#define DSP_DC   PA_4

// UART for RX (CPU->DP)
#define HP_RX PC_5
#define HP_TX PC_4

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

// encoder
#define KP_ENC1 PA_0
#define KP_ENC2 PA_1

// keypad
#define KP_R0 PB_5
#define KP_R1 PB_6
#define KP_R2 PB_7
#define KP_R3 PB_8

#define KP_C0 PC_2
#define KP_C1 PC_1
#define KP_C2 PC_0
#define KP_C3 PB_4
#define KP_C4 PB_0

#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 curcmd;
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,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);



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("Serial communication pins\r\n");
  printf("     USBRX=%d\r\n", USBRX);
  printf("     USBTX=%d\r\n", USBTX);

  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");
  // 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->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
  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
	ThisThread::sleep_for(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)
  {
	  timeout_h();
	  ThisThread::sleep_for(1);
  }
}

mercurial