#include <aspoutil.h>
#include <aspoprotocol.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#define LOG_BUFSZ 200
const size_t log_bufsz = LOG_BUFSZ;
char log_buffer[LOG_BUFSZ];

/****************************/

#define TIME (200 * 1000)

uint8_t req[S6400_MAXREQLEN];
#define RESSZ 4000
uint8_t res[RESSZ];
struct termios ttysave;
int fd = -1;
char *dev;
static uint32_t reader;
static struct openraw_t opts = { 8, 0, 1, };

/****************************/

static void Usage(void) {
  printf("Usage:\n\t%s serial_port\n", cmdline_pgm);
  exit(1);
}

static void Close(void) {
  /*NOTICE("Stopping %s", cmdline_pgm); */
  LOG_VIF( (fd = tty_close(fd, &ttysave, dev, getpid())) < 0, LOG_ERR, " dev = %s fd = %d", dev, fd) { }
}

static int doio(const void *obuf, size_t olen, void *ibuf, ssize_t ilen, int check ) {
  ssize_t ret;
  uint16_t code;
  const char *err1;
  const char *err2;

  LOG_IF( tcflush(fd, TCIOFLUSH) < 0, LOG_ERR) { }
  if (obuf && olen > 0) {
    LOG_IF( (ret = tty_write(fd, obuf, olen) != (ssize_t) olen), LOG_NOTICE) return -1;
  }
  usleep(TIME); /* this don't check for signal interruptions */
  bzero( ibuf, ilen);  
  LOG_IF( (ret = tty_read(fd, ibuf, ilen)) < 0, LOG_ERR) return -1;

  if (obuf && olen && !ret) {
    s6400_prpkg("no response for", obuf, olen);
    return 0;
  }
  if (check) {
    printf("Request:  ");
    s6400_prpkg(NULL, obuf, olen);
    printf("Response: ");
    s6400_prpkg(NULL, ibuf, ret);
    if (s6400_validate(ibuf, ret)   < 0) goto doio_err;
    if (s6400_check_error_res(ibuf, &code, &err1, &err2) < 0 || code) {
      if (code == 0x0201) return 0; /* no transponder found */
      if (code == 0x0206) return 0; /* for some reasons, sometimes tag crc error is reported */
      (void) s6400_check_error_report(code, err1, err2);
      goto doio_err;
    }
  }

  return ret;

doio_err:
  s6400_prpkg("doio req: ", obuf, olen);
  s6400_prpkg("doio res: ", ibuf, ret);
  return -1;
}

int main(int argc, char *argv[]) {
  int val;
  int baudrate = B38400;
  /*sigset_t unblock_set; */
  int count;

  (void) cmdline_extrpgm(argv);
  log_open("", 2, 0); /* log to stdout */
  if (argc != 2) Usage();
  dev = argv[1];

  LOG_VIF( (fd = tty_openraw(&ttysave, dev, baudrate, &opts)) < 0, LOG_ERR, " dev = %s", dev ) Usage();
  LOG_IF( atexit(Close) < 0, LOG_ERR) return -1;
  /*LOG_IF( setvbuf(stdout, (char *) NULL, _IOLBF, 0), LOG_NOTICE) { } // too bad, but we'll continue */
  LOG_IF( doio(NULL, (size_t) 0, res, RESSZ, 0) < 0, LOG_ERR) return -1;

  val = s6400_reader_version_req( req, S6400_MAXREQLEN, 0);
  LOG_IF( doio(req, (size_t) val, res, RESSZ, 1) < 0, LOG_ERR) return -1;
  LOG_IF( s6400_reader_version_res(res, NULL, NULL, &reader), LOG_ERR) return -1;
  printf("Reader found:     %07u\n", reader);

  printf("\n");
  printf("set Wiegang mode\n");
  val = s6400_reader_mode_wieg_req( req, S6400_MAXREQLEN, 0, S6400_MODE_64BITS, 0);
  LOG_IF( doio(req, (size_t) val, res, RESSZ, 1) < 0, LOG_ERR) return -1;
  LOG_IF( s6400_reader_setup_res(res, NULL, NULL, NULL, NULL, NULL), LOG_ERR) return -1;

  printf("\n");
  printf("set led and buzzer\n");
  val = s6400_reader_mode_req( req, S6400_MAXREQLEN, 0, S6400_MODE_LEDAUDIO, 0 | /*S6400_MODE_LED | */ S6400_MODE_AUDIO);
  LOG_IF( (count = doio(req, (size_t) val, res, RESSZ, 1)) < 0, LOG_ERR) return -1;
  {
    uint8_t mode1, mode2;
    LOG_IF( s6400_reader_setup_res(res, &mode1, &mode2, NULL, NULL, NULL), LOG_ERR) return -1;
    printf("mode 1 & 2: 0x%02x 0x%02x\n", mode1, mode2);
  }

  /*return 0; */
  printf("\n");
  printf("set led on-time\n");
  /*val = s6400_activate_led_req(req, S6400_MAXREQLEN, 0, 2, 20); */
  val = s6400_activate_led_req(req, S6400_MAXREQLEN, 0, 2, 0);
  LOG_IF( doio(req, (size_t) val, res, RESSZ, 1) < 0, LOG_ERR) return -1;

  /*Close(); */
  return 0;
}
