#include <fcntl.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
void hex2bin(const char *in, size_t len, unsigned char *out) {

  static const unsigned char TBL[] = {
      0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  58, 59, 60, 61,
      62, 63, 64, 10, 11, 12, 13, 14, 15, 71, 72, 73, 74, 75,
      76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
      90, 91, 92, 93, 94, 95, 96, 10, 11, 12, 13, 14, 15};

  static const unsigned char *LOOKUP = TBL - 48;

  const char *end = in + len;

  while (in < end)
    *(out++) = LOOKUP[*(in++)] << 4 | LOOKUP[*(in++)];
}

int open_port(const char *port) {
  int fd;

  fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1) {
    return -1;
  } else
    fcntl(fd, F_SETFL, 0);
  usleep(2000000);
  struct termios options;

  tcgetattr(fd, &options);

  cfsetispeed(&options, B115200);
  cfsetospeed(&options, B115200);

  options.c_cflag |= (CLOCAL | CREAD);
  options.c_cflag &= ~PARENB;
  options.c_cflag &= ~CSIZE;
  options.c_cflag &= ~CSTOPB;
  options.c_cflag |= CS8;
  options.c_cflag &= ~CRTSCTS;

  options.c_cc[VTIME] = 5;
  options.c_cc[VMIN] = 1;

  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

  options.c_iflag &= ~(IXON | IXOFF | IXANY);

  options.c_oflag &= ~OPOST;
  
  tcsetattr(fd, TCSANOW, &options);
  if (tcsetattr(fd, TCSAFLUSH, &options)) {
    close(fd);
    return -1;
  }
  usleep(2000000);


  return (fd);
}

pthread_t thread_id;
int fd;

void *serialDataIn(void *);

void *serialDataIn(void *vargp) {

  int inL = 0;

  unsigned char com_recv[25];
  unsigned char in_buf[25];
  unsigned char inChar;
  int in_buf_i = 0;
  uint16_t com_len;

  pthread_yield();

  while (1) {
    inL = read(fd, &inChar, 1);
    printf("%x\n", inChar);
  }
}

int main(int argc, char **argv) {
  int l = 0;
  fd = open_port(argv[1]);
  if (fd < 0)
    return 0;
  usleep(2000000);

  pthread_create(&thread_id, NULL, serialDataIn, NULL);
  unsigned char buffer[32];
  char in_string[64];

  while (1) {

    fgets(in_string, 64, stdin);
    if (in_string[0] == 'q') {
      pthread_cancel(thread_id);
      close(fd);
      return 0;
    }

    l = strlen(in_string) / 2;
    hex2bin(in_string, 2 * l, buffer);

    int n = write(fd, buffer, l);
  }
}
