src/hp34comm.h

Mon, 09 Nov 2020 23:05:24 +0100

author
David Douard <david.douard@sdf3.org>
date
Mon, 09 Nov 2020 23:05:24 +0100
changeset 49
c146d19101a3
parent 44
b3c3d54d2c7c
child 50
279868684eb3
permissions
-rw-r--r--

Refactor HPSerial to get rid of packet collision misbehavior

completely split the key sending code from the irq-based receiveing logic.
When sending keycodes, disable the RxIrq callback and handle send and recv
of bytes synchronously.

The keycode sending routine rus in a dedicated thread.

#ifndef HP34COMM_H
#define HP34COMM_H

#include <mbed.h>
#include <CircularBuffer.h>

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

#define MAX_ERRS 10
#define MAX_BUFF 16
#define BUF_SIZE 16



class HPSerial {

public:
  typedef struct _CMD
  {
    uint8_t cmd;
    uint8_t size;
    char value[MAX_BUFF+1];
    unsigned long id;
  } CMD;

  HPSerial(PinName tx, PinName rx);

  bool cmd_available(void);
  bool pop(CMD& cmd);
  bool cmd_buf_full(void);
  unsigned int nerrors(uint8_t errorno);

  void startup(uint8_t keycode=0xFF);
  void sendkey(uint8_t keycode);
  void send_key_when_idle();
  void send_startup_seq();
  void send_startup_seq(uint8_t keycode);

private:
  void pushCmd(uint8_t cmd, uint8_t size, char *payload);
  void rx_irq(void);
  void timeout(void);
  void set_timer(Kernel::Clock::duration_u32 v=0ms) {
    timeouter.detach();
    if (v > 0ms)
      timeouter.attach(callback(this, &HPSerial::timeout), v);
  };

 private:
  UnbufferedSerial serial;
  uint8_t buf[BUF_SIZE];
  uint8_t head;
  CircularBuffer<CMD, 32> cmdbuf;
  CircularBuffer<uint8_t, 32> sendbuf;
  unsigned long ncmd;
  unsigned int errs[MAX_ERRS];
  Ticker timeouter;

  Thread send_thread;
  void send_pending_key();
  bool wait_for(uint8_t);


 public:
  // global state machine
  typedef enum {
    GSTATE_STARTING,
    GSTATE_IDLE,
    GSTATE_TX,
    GSTATE_RX,
    NUM_GSTATES} gstate_t;
  gstate_t gstate() {return cur_gstate;};
  /* gstate_t do_start(); */
  /* gstate_t do_send(); */
  /* gstate_t do_receive(); */

  /* typedef gstate_t(HPSerial::*gstatemethod)(); */
  /* statemethod const gstate_table[NUM_GSTATES] = { */
  /*     &HPSerial::do_start, */
  /*     &HPSerial::do_send, */
  /*     &HPSerial::do_receive, */
  /* }; */

  /* gstate_t run_gstate(gstate_t cur_state); */
 private:
  gstate_t cur_gstate;

 public:
  // transmission state machine
  typedef enum {
    STATE_IDLE,
    STATE_COMMAND,
    STATE_PAYLOAD_SIZE,
    STATE_PAYLOAD,
    STATE_SENDING,
    NUM_STATES} state_t;
  state_t state() {return cur_state;};

 private:
  typedef struct state_data {
    uint8_t cmd;
    uint8_t size;
    uint8_t pos;
    char payload[MAX_BUFF];
  } state_data_t;

  void _startup(void);
  state_t do_state_initial(uint8_t c=0x00);
  state_t do_state_command(uint8_t c);
  state_t do_state_payload_size(uint8_t c);
  state_t do_state_payload(uint8_t c);
  state_t do_state_sending(uint8_t c=0x00);

  void send_ack(uint8_t c);

  typedef state_t(HPSerial::*statemethod)(uint8_t c);
  static  statemethod state_table[NUM_STATES];
  state_t run_state(state_t cur_state, uint8_t c);

  state_t cur_state;
  state_data_t tr_data;
};


#endif

mercurial