src/hp34comm.cpp

Sat, 29 Oct 2016 23:44:31 +0200

author
David Douard <david.douard@logilab.fr>
date
Sat, 29 Oct 2016 23:44:31 +0200
changeset 18
4fd621551d55
parent 16
c5e5bdc5ef49
child 19
a52d60613cf7
permissions
-rw-r--r--

[full replacement] implement a state machine for Rx

#include "hp34comm.h"
#include "mbed.h"
#include "CircularBuffer.h"

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

#ifdef DEBUG2

DigitalOut inrx(D9);
DigitalOut intx(D5);
DigitalOut ack(D6);
DigitalOut staterx(A0);
DigitalOut statetx(D10);

#endif

DigitalOut lled(LED1);



HPSerial::HPSerial(PinName tx, PinName rx):
  serial(tx, rx)
{
  cur_state = do_state_initial(&rx_data, 0x00);
  serial.baud(187500);
  serial.attach(this, &HPSerial::rxIrq, Serial::RxIrq);
}

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

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

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

unsigned int HPSerial::nerrors(uint8_t errorno) {
  return errs[errorno];
}

void HPSerial::pushCmd(uint8_t cmd, uint8_t size, char *payload) {
  CMD val;
  uint8_t i;
  val.id = ncmd++;
  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 HPSerial::send_ack(uint8_t c) {
  timeouter.attach(this, &HPSerial::timeout, 0.001); // if nothing else happen in the next ms, reset
  serial.putc(c);
}

HPSerial::state_t HPSerial::do_state_initial(HPSerial::instance_data_t *data,
				   uint8_t c)
{
  // go back to initial state
  data->cmd = 0xFF;
  data->size = 0;
  data->received = 0;
  timeouter.detach();
  return HPSerial::STATE_IDLE;
}

HPSerial::state_t HPSerial::do_state_handcheck(HPSerial::instance_data_t *data,
				     uint8_t c)
{
  // we are idle, incoming char is a handcheck
  // knwon handcheck values are 0x66 and 0x33
  switch (c) {
  case 0x33:
    send_ack(0xCC);
    return HPSerial::STATE_PAYLOAD_SIZE;
    break;
  case 0x66:
    send_ack(0x99);
    return HPSerial::STATE_COMMAND;
    break;
  default:
    return do_state_initial(data, 0x00);
  }
}

HPSerial::state_t HPSerial::do_state_command(HPSerial::instance_data_t *data,
					     uint8_t c)
{
  if (c == 0x55) { // EoT
    return do_state_initial(data, 0x00);
  }

  data->cmd = c;
  data->size = 0;
  send_ack(0x00);
  return HPSerial::STATE_PAYLOAD_SIZE;
}

HPSerial::state_t HPSerial::do_state_payload_size(HPSerial::instance_data_t *data,
						  uint8_t c)
{
  data->size = c;
  data->received = 0;
  send_ack(0x00);
  return HPSerial::STATE_PAYLOAD;
}

HPSerial::state_t HPSerial::do_state_payload(HPSerial::instance_data_t *data,
					uint8_t c)
{
  data->payload[data->received++] = c;
  send_ack(0x00);
  if (data->received >= data->size) {
    pushCmd(data->cmd, data->size, data->payload);
    return HPSerial::STATE_COMMAND;
  }
  return HPSerial::STATE_PAYLOAD;
}

HPSerial::state_t HPSerial::run_state(HPSerial::state_t cur_state,
				      HPSerial::instance_data_t *data,
				      uint8_t c)
{
  return (this->*(HPSerial::state_table[cur_state]))(data, c);
};

void HPSerial::rxIrq(void) {
  uint8_t val;
  if(serial.readable()) { // no reason why we would end here without
			  // this condition, but hey
#ifdef DEBUG2
    inrx=1;
#endif
    lled = 1;
    val = serial.getc();
    cur_state = run_state(cur_state, &rx_data, val);
    lled = 0;
#ifdef DEBUG2
    inrx=0;
#endif
  }
}


void HPSerial::timeout(void) {
  cur_state = do_state_initial(&rx_data, 0x00);
}

mercurial