src/main.cpp

Tue, 13 Sep 2016 21:32:48 +0200

author
David Douard <david.douard@logilab.fr>
date
Tue, 13 Sep 2016 21:32:48 +0200
changeset 4
219766126afb
parent 3
a3233abe730e
child 5
f1c85c2500f2
permissions
-rw-r--r--

another attempt using a more complete support of the protocol and async serial stuff

#include "stdio.h"

#include "mbed.h"
#include "string"
#include "CircularBuffer.h"

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

#include "SSD1322.h"

Serial pc(USBTX, USBRX);

//BufferedSerial hp(NC, PA_1, 64, 0); // serial4
#define HP_SERIAL_TX PC_7 // serial6 RX
#define HP_SERIAL_RX PA_1 // serial4 RX

SSD1322 dsp(SPI_8, 10000000, PB_15, PB_14, PB_13, PB_12, D11, D12, "SSD1322", 256, 64); 

#define BUF_SIZE 32
#define MAX_BUFF 15
#define MAX_ERRS 10
uint8_t curchar;
uint8_t cmd;
uint8_t nchars;
char buffer[MAX_BUFF+1];

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

static DSP table[] =
{
  { 0x00, 0xF,   0x0,  0,  0, 0, MAX_BUFF, 245, Mono19x27}, // main display
  { 0x0C, 0xF,   0x0,204, 38, 0, 3,        45, Mono15x22}, // channels display
  { 0x01, 0xF,   0x0,  0,  0, 4, MAX_BUFF, 0, Terminal6x8}, 
  { 0x02, 0xF,   0x0,  0,  0, 4, MAX_BUFF, 0, Terminal6x8},
  { 0x0A, 0xF,   0x0,  0, 57, 2, 4,        0, Terminal6x8},
  { 0x0A, 0xF,   0x0,  0,  0, 3, 4,        0, Terminal6x8}, // flags
  { 0xFF, 0xF,   0x0,  0,  0, 4, 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;
  uint8_t x;
  uint8_t y;
  const char* msg;
  const unsigned char* icon;
} FLAG;

static const FLAG flags[] =
  {
    //{ 0x00, 160, 30, "Alarm"},  // for the 'alarm' box
    { 0x00, 246, 0,  NULL, icon_alarm},      // F1.1
    { 0x01, 246, 11, NULL, icon_curve},      // F1.2
    { 0x03, 204, 30, "Channel"},    // F1.4
    { 0x14, 68,  44, "4W"},         // F2.5
    { 0x33, 40, 44,  "VIEW"},       // F4.4
    { 0x34, 0, 30,   "MON"},        // F4.5
    { 0x36, 0, 44,   "CONFIG"},     // F4.7
    
    { 0xFF, 0, 0,  "SCAN"},  // F4.6 or F4.3
    { 0xFF, 0, 0,  "*"},
    { 0xFF, 0, 0,  "ADRS"},
    { 0xFF, 0, 0,  "RMT"},
    { 0xFF, 0, 0,  "ERROR"},
    { 0xFF, 0, 0,  "EXT"},
    { 0xFF, 0, 0,  "ONCE"},
    { 0xFF, 0, 0,  "AUTO"},
    { 0xFF, 0, 0,  "MEM"},
    { 0xFF, 0, 0,  "LAST"},
    { 0xFF, 0, 0,  "MIN"},
    { 0xFF, 0, 0,  "MAX"},
    { 0xFF, 0, 0,  "AVG"},
    { 0xFF, 0, 0,  "OC"},

    { 0xFF, 0, 0,  "H"},
    { 0xFF, 0, 0,  "1"},
    { 0xFF, 0, 0,  "2"},
    { 0xFF, 0, 0,  "3"},
    { 0xFF, 0, 0,  "4"},
    { 0xFF, 0, 0,  "L"},
    
  };


#ifdef DEBUG
#define DBGPIN PC_0

DigitalOut dbgpin(DBGPIN);
inline void DebugPulse(uint8_t count=1)
{
  while (count--)
  {
    dbgpin = 1;
    dbgpin = 0;
  }
}
#else
inline void DebugPulse(uint8_t count=1)
{}
#endif



/***** HP 34970A communication class ***/

class HPSerial {

public:
  enum TrState {
        Idle = 0,
        Tx,
        Rx,
    };
  typedef struct _CMD
  {
    TrState direction;
    uint8_t cmd;
    uint8_t size;
    char value[MAX_BUFF+1];
    unsigned long id;
  } CMD;


  
  HPSerial(): ncmd(0), serial_tx(NC, HP_SERIAL_TX), serial_rx(NC, HP_SERIAL_RX) {
    pc.printf("HPSerial init\n");
    for(uint8_t i=0; i<MAX_ERRS; i++)
      errs[i] = 0;
    reset();

    serial_tx.baud(187500);
    serial_tx.attach(this, &HPSerial::txIrq, Serial::RxIrq); //sic!

    serial_rx.baud(187500);
    serial_rx.attach(this, &HPSerial::rxIrq, Serial::RxIrq);
  }

  bool cmd_available(void) {
    return !cmdbuf.empty();
  }

  bool pop(CMD& cmd) {
    return cmdbuf.pop(cmd);
  }

  bool cmd_buf_full(void) {
    return cmdbuf.full();
  }

  unsigned int nerrors(uint8_t errorno) {
    return errs[errorno];
  }
    
		     
  
private:
  void reset(uint8_t errorno=0xFF) {
    head = 0;
    tx_state = Idle;
    tx_cmd = 0xFF;
    tx_ack = false;
    tx_len = 0xFF;
    memset(buf, 0, BUF_SIZE);
    if (errorno != 0xFF)
      errs[errorno]++;
  }

  void handleAck(uint8_t val) {
    if (tx_ack == true)
      reset(0);

    else 
      if (tx_cmd == 0xFF) // still at the beginning of a packet, expect 0x99 as ack
	if (val == 0x99)
	  tx_ack = true;
	else 
	  reset(1);

      else // expect 0x00 as ack
	if (val == 0x00)
	  tx_ack = true;
	else
	  reset(2);
  }

  void pushCmd(TrState direction, uint8_t cmd, uint8_t size, char *payload) {
    CMD val;
    uint8_t i;
    val.id = ncmd++;
    val.direction = direction;
    val.cmd = cmd;
    val.size = size;
    for(i=0; i<size; i++)
      val.value[i] = payload[i];
    val.value[i] = 0x00;
    cmdbuf.push(val);
  }
  
  void handleChar(uint8_t val) {
    if (tx_ack == false)
      reset(3);
    else // remaining of the state machine
      if (tx_cmd == 0xFF) {
	// begin of transmission, expect a cmd
	tx_cmd = val;
	tx_ack = false;
	tx_len = 0xFF;
      }
      else if (tx_len == 0xFF) {
	// got a cmd, expect a payload size
	tx_len = val;
	tx_ack = false;
      }
      else if (tx_len > 0) {
	// a payload char
	buf[head++] = val;
	tx_len--;
	tx_ack = false;
      }
      else {
	uint8_t cur_state = tx_state;
	pushCmd(tx_state, tx_cmd, head, buf); 
	reset();
	
	if (val != 0x55) { // not an end of transmission
	  // should be another cmd I think
	  tx_cmd = val;
	  tx_state = cur_state;
	}
      }
  }

  
  void rxIrq(void) {
    uint8_t val;
    if(serial_rx.readable()) { // no reason why we would end here without this condition, but hey
      val = serial_rx.getc();
      
      if (tx_state == Idle)
	if (val == 0x66) {
	  // no transmission in progress, expect a start of transmission
	  tx_state = Rx;
	  tx_ack = false;
	}
	else
	  reset(4);
    
      else if (tx_state == Tx)  // manage the acks
	handleAck(val);
      
      else 
	handleChar(val);
    }
  }
  
  void txIrq(void) {
    uint8_t val;
    if(serial_tx.readable()) { // no reason why we would end here without this condition, but hey
      val = serial_tx.getc();
      
      if (tx_state == Idle)
	if (val == 0x66) {
	  // no transmission in progress, expect a start of transmission
	  tx_state = Tx;
	  tx_ack = false;
	}
	else
	  reset(5);
    
      else if (tx_state == Rx)  // manage the acks
	handleAck(val);
      
      else 
	handleChar(val);
    }
  }
  
private:
  RawSerial serial_tx;
  RawSerial serial_rx;
  uint8_t buf[BUF_SIZE];
  uint8_t head;
  uint8_t tx_state;
  uint8_t tx_cmd;
  uint8_t tx_len;
  bool tx_ack;
  CircularBuffer<CMD, 32> cmdbuf;
  unsigned long ncmd;
  unsigned int errs[MAX_ERRS];
};


HPSerial hp;
Ticker dsp_refresher;
volatile bool must_refresh;

void copy_to_lcd(void);
void test_dsp();

void setup() {
    // init the LCD

    //dsp.set_orientation(3);
    pc.baud (115200);
    pc.printf("\n\nSystem Core Clock = %.3f MHZ\r\n",
          (float)SystemCoreClock/1000000);

    // 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();
    dsp.locate(0, 0);
    dsp.set_font(Mono19x27);
    
    cmd = 0xFF;
    curchar = 0;
    nchars = 0;

    
    dsp.printf("HP34970A");
    dsp.set_font(Terminal6x8);
    for(uint8_t i=0; i<4;  i++) {
      dsp.locate(160, i*8);
      dsp.printf("Lg %d", i+1);
      dsp.locate(208, (3-i)*8);
      dsp.printf("Lg %d", i+1);
    }
    dsp.copy_to_lcd();
    wait(2);
    dsp.cls();
    
    dsp_refresher.attach(&copy_to_lcd, 0.1);
    test_dsp();
    wait(2);
    dsp.cls();
    
}

void copy_to_lcd(void) {
  if (must_refresh)
    dsp.copy_to_lcd();
}

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

  must_refresh = false;
  
  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.locate(table[i].x0, table[i].y0);
      dsp.set_font((unsigned char*) table[i].font);
      oldv = table[i].buffer;
      
      switch (table[i].fmt) {
      case 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);
	dsp.printf(txt);
	break;
      case 1: // 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(" ");
	break;
      case 2: // 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("]");
	break;
      case 3: // flags
	for (uint8_t j=0; j<max(nchar, table[i].maxsize) ; j++) {
	  for (uint8_t k=0; k<8; k++) {
	    if ((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(flags)/sizeof(flags[0])); ++l) {
		if (flags[l].flag == ((j<<4) + k)) {
		  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, flags[l].icon};
		    dsp.Bitmap_BW(pic, flags[l].x, flags[l].y);
		  }
		  break;
		}
	      }
	    }
	  }
	  oldv[j] = txt[j];
	}
	break;
      case 4: //ignore
	break;
      }
    }
  }
  must_refresh = true;
  //dsp.copy_to_lcd();
}

void test_dsp()
{
  show(0x00, "8g8g8g8g8g8g8", 13); // main dsp
  show(0x0C, "888", 3); // channel dsp
  show(0x0A, "\xFF\xFF\xFF\xFF", 4); // flags
}


void loop() { // run over and over
  if (hp.cmd_available())
    {
      HPSerial::CMD cmd;
      if (hp.pop(cmd))
	{
	  pc.printf("CMD[%s:%d %d/%d/%d/%d/%d/%d] %X\n", (cmd.direction==HPSerial::Rx)?"Rx":"Tx", cmd.id,
		    hp.nerrors(0), 
		    hp.nerrors(1), 
		    hp.nerrors(2), 
		    hp.nerrors(3), 
		    hp.nerrors(4), 
		    hp.nerrors(5), 
		    cmd.cmd);

	  if (cmd.direction == HPSerial::Rx) {
	    if ((cmd.cmd == 0x00) || (cmd.cmd == 0x0C))
	      pc.printf("  data=%s\n", cmd.value);
	    show(cmd.cmd, cmd.value, cmd.size);
	    
	  }
	}
    }
}

int main()
{
  setup();
  while(1)
    loop();
}

mercurial