#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <usb.h>
#include <ftdi.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include "usbio_test.h"

#define FILENAME "mem.dat"
time_t mtime;

void read_mem(usbio_context *ctxt)
{
  char buf[1024], *s;
  unsigned int addr;
  unsigned int val;
  FILE *f;

  f = fopen(FILENAME, "r");
  if (f == NULL)
  {
    printf("File open failed\n");
    return;
  }
  while ((s = fgets(buf, 256, f)) != NULL)
  {
    addr = strtoul(buf, &s, 0);
    if (addr < 0 || addr >= MEMSIZE)
    {
      fprintf(stderr, "Error: address %d\n", addr);
      exit(255);
    }
    val  = strtoul(s, NULL, 0);
    ctxt->mem[addr] = val;
  }
  fclose(f);
}

usbio_context *usbio_open(int flag)
{
  usbio_context *ctxt;
  struct stat st;
  
  ctxt = (usbio_context *)malloc(sizeof(usbio_context));
  if (ctxt == NULL)
    return ctxt;
    
  ctxt->mem = (unsigned int *)malloc(MEMSIZE*sizeof(unsigned int));
  if (ctxt->mem == NULL)
  {
    free(ctxt);
    return NULL;
  }
  
  pthread_mutex_init(&ctxt->usbio_mutex, NULL);

  /* Read R/W memory data, R/O memory data, init
     memory space */
  stat(FILENAME, &st);
  mtime = st.st_mtime;
  read_mem(ctxt);
  return ctxt;
}

void usbio_close(usbio_context *ctxt)
{
  free(ctxt);
}

int usbio_if_reset(usbio_context *ctxt)
{
  return 0;
}

int usbio_write(usbio_context *ctxt, int addr, int data)
{
  if (addr < 0 || addr >= MEMSIZE)
  {
    fprintf(stderr, "Error: address %d\n", addr);
    exit(255);
  }
  pthread_mutex_lock(&ctxt->usbio_mutex);
  ctxt->mem[addr] = data;
  pthread_mutex_unlock(&ctxt->usbio_mutex);
/*  printf("mem[0x%06x] <= 0x%04x\n", addr, data); */
  return 1;
}

int usbio_block_write(usbio_context *ctxt, int addr, 
                      unsigned int *data, int count)
{
  if (ctxt == NULL)
    return -1;

  if (addr < 0 || (addr + count) >= MEMSIZE)
  {
    fprintf(stderr, "Error: address %d\n", addr);
    exit(255);
  }

  pthread_mutex_lock(&ctxt->usbio_mutex);
  memcpy(ctxt->mem + addr, data, count*sizeof(unsigned int));
  pthread_mutex_unlock(&ctxt->usbio_mutex);
  
  return count;
}

int usbio_block_read(usbio_context *ctxt, int addr, 
                     unsigned int *data, int count)
{
  struct stat st;
  
  if (ctxt == NULL)
    return -1;

  pthread_mutex_lock(&ctxt->usbio_mutex);
  stat(FILENAME, &st);
  if (st.st_mtime != mtime)
  {
    mtime = st.st_mtime;
    read_mem(ctxt);
  }
  if (addr < 0 || (addr + count) >= MEMSIZE)
  {
    fprintf(stderr, "Error: address %d\n", addr);
    exit(255);
  }
  memcpy(data, ctxt->mem + addr, count * sizeof(unsigned int));
  pthread_mutex_unlock(&ctxt->usbio_mutex);
/*  if (count == 1)
    printf("mem[0x%06x] => 0x%04x\n", addr, *data); */
  
  return count;
}

int usbio_mult_write(usbio_context *ctxt, int *addr, unsigned int *data,
                     int count)
{
  int i;
  
  if (ctxt == NULL)
    return -1;

  pthread_mutex_lock(&ctxt->usbio_mutex);
  for (i=0; i < count; i++)
    ctxt->mem[addr[i]] = data[i];
  pthread_mutex_unlock(&ctxt->usbio_mutex);

  return count;
}
