HW/DAS/USBscopes/usbtm/lib/lantronix.c

#include <asm/types.h>
#include "lantronix.h"

#define NOT_FOUND ((unsigned short)-1)

int debug = 0;
int lx_error = LX_ERROR_NO_ERROR;
unsigned char read_queue[NQUEUE][QUEUELEN];
size_t queue_len[NQUEUE] = {0};


struct commstr {
  __u16  _dummy;
  __u16  len;
  __u32  acc;
  __u32  sid;
  __u8   code;
  __u8   d0B;
  __u16  datalen;
  __u16  d0E;
  __u16  d10;
  __u16  d12;
  __u16  d14;
  __u32  did;
  __u32  d1A;
  __u16  d1E;
  __u16  d20;
  __u8   data[];
};

struct devinfo {
  __u16  len;
  __u16  type;
  __u16  vid;
  __u16  pid;
  __u32  port;
  char   client[0x40];
  char   name1[0x20];
  __u8   ip[4];
  __u16  d70;
  __u8   d72;
  __u8   d73;
  __u8   d74[4];
  __u8   d78[4];
  __u8   d7C[2];
  __u16  d7E;
  __u8   d80[0x18];
  char   sn[0x20];
  __u16  dB8;
  char   name2[0x20];
  __u16  dDA;
};

struct cliinfo {
  __u16 len;
  __u16 type;
  char  name[0x60];
  __u8  ip[4];
  __u8  d68[6];
  char  d6E[0x20];
};

struct udppacket {
  __u32  sn;
  __u32  firm_ver;
  __u32  firm_rev;
  __u8   code1;
  __u8   code2;
  __u16  tcp_port;
  __u16  d10;
  __u16  d12;
  __u16  d14;
  __u16  ord;
  __u32  d18;
  __u16  vid;
  __u16  pid;
  __u32  usb_port;
};


int sock = 0;
struct commstr *salloc = NULL;

void freeall() {        /* pro atexit() */
  if(salloc) free(salloc);
  salloc = NULL;
  if(sock) close(sock);
  sock = 0;
}


int initsock(char *ip) {
  struct hostent *host;
  struct sockaddr_in sin;
  int s;
  if((host = gethostbyname((void*)ip)) == NULL) return -1;
  if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) return -1;
  sin.sin_family = AF_INET;
  sin.sin_port = htons(10010);
  memcpy(&(sin.sin_addr), host->h_addr, host->h_length);
  if((connect(s, (struct sockaddr*)&sin, sizeof(sin))) == -1) return -1;
  return s;
}


void setupstr(struct commstr *str, unsigned char code, unsigned acc, unsigned short d0E,
    unsigned short d10, unsigned short d12, unsigned short datalen) {
  memset(str, 0, sizeof(struct commstr));
  str->code = code;
  str->acc = htonl(acc);
  str->d0E = htons(d0E);
  str->d10 = htons(d10);
  str->d12 = htons(d12);
  str->datalen = htons(datalen);
  str->len = htons(datalen + 32);
  memset(str->data, 0, datalen);
}


void sendstr(struct commstr *str) {
  unsigned char *stream = (unsigned char*)str + 2;
  if(debug > 1) {
    int i;
    for(i = 0; i < 34 + ntohs(str->datalen); i++)
      printf("%02X ", (int)(stream[i]));
    puts("");
  }
  if(send(sock, (void*)stream, 34 + ntohs(str->datalen), 0) < 0) exit(RETVAL_SEND);
}


void sendsimple(unsigned char code, unsigned acc, unsigned short d0E,
    unsigned short d10, unsigned short d12) {
  setupstr(salloc, code, acc, d0E, d10, d12, 0);
  sendstr(salloc);
}


void sendpacket_va(unsigned char code, unsigned acc, unsigned short d0E,
    unsigned short d10, unsigned short d12, unsigned short datalen, va_list ap) {
  int i;
  setupstr(salloc, code, acc, d0E, d10, d12, datalen);
  for(i = 0; i < datalen; i++)
    salloc->data[i] = (unsigned char)va_arg(ap, unsigned);
  sendstr(salloc);
}


void sendpacket(unsigned char code, unsigned acc, unsigned short d0E,
    unsigned short d10, unsigned short d12, unsigned short datalen, ...) {
  va_list ap;
  if(datalen) {
    va_start(ap, datalen);
    sendpacket_va(code, acc, d0E, d10, d12, datalen, ap);
    va_end(ap);
  } else {
    sendsimple(code, acc, d0E, d10, d12);
  }
}


void sendconfig(unsigned acc, unsigned short datalen, ...) {
  va_list ap;
  va_start(ap, datalen);
  sendpacket_va(0x41, acc, 1,0,0, datalen, ap);
  va_end(ap);
  free(waitpacket(0x51));
}


struct commstr *readpacket(int sock) {
  int r, len, o;
  struct commstr *str;
  unsigned char *buf;
  unsigned short prebuf;
  r = recv(sock, &prebuf, 2, 0);
  if(r <= 0) exit(RETVAL_RECV);
  len = ntohs(prebuf)+2;
  o = 2;
  str = malloc(len+2);    /* Nezapomente uvolnit! */
  if(!str) exit(RETVAL_MALLOC);
  buf = (unsigned char*)str + 2;
  memcpy(buf, &prebuf, 2);
  do {
    r = recv(sock, buf+o, len-o, 0);
    if(r <= 0) { free(str); exit(RETVAL_RECV); }
    else o += r;
  } while(o < len);
  if(debug > 1) {
    int i;
    for(i = 0; i < len; i++) {
      printf("%02X ", (int)(buf[i]));
      if(i == 1000) puts("");
    }
    puts("");
  }
  return str;
}


void dispatch(struct commstr *str) {
  struct devinfo *di;
  struct cliinfo *ci;
  struct udppacket *udp;
  int off, q;
  switch(str->code) {
    case 0x57:
    case 0x12:
    case 0x15:
      /* ignore */
      break;
    case 0x52:
      if(str->d12 == 0x0) {
        q = ntohl(str->acc);
        if(queue_len[q] + ntohs(str->datalen) > QUEUELEN) exit(RETVAL_QUEUE);
        memcpy(read_queue[q]+queue_len[q], str->data, ntohs(str->datalen));
        queue_len[q] += ntohs(str->datalen);
      }
      break;
    case 0x18:
      if(debug) {
        printf("\n=== 0x18 ===\nPočet zařízení: %i\nPočet klientů: %i\n",
            ntohs(str->d0E), ntohs(str->d10));
        for(off = 0; ; off += ntohs(*(unsigned short*)(str->data+off))) {
          switch(str->data[off+2]) {
            case 0x04:
              di = (struct devinfo*)(str->data+off);
              printf("port %i:  %04X/%04X  %s\t%s",
                  ntohl(di->port)-1, ntohs(di->vid), ntohs(di->pid), di->name1, di->sn);
              if(di->ip[0]) printf("  [%i.%i.%i.%i %s]",
                  di->ip[0], di->ip[1], di->ip[2], di->ip[3], di->client);
              printf("\n");
              break;
            case 0x05:
              ci = (struct cliinfo*)(str->data+off);
              printf("%s\t%i.%i.%i.%i\n", ci->name, ci->ip[0], ci->ip[1], ci->ip[2], ci->ip[3]);
              break;
            case 0x00:
              break;
          }
          if(str->data[off+2] == 0x00) {
            off += 4;
            break;
          }
        }
        printf("\n");
      }
      break;
    case 0x61:
      udp = (struct udppacket*)(str->data);
      if(debug) {
        printf("\n=== 0x61: %02X%02X ===\n", udp->code1, udp->code2);
        switch(udp->code1) {
          case 0x01:
            if(udp->d14 == 0)
              sendsimple(0x05, 0,0,0,0);
            else puts("Zbytečnost");
            break;
          case 0x02:
          case 0x03:
            printf("Zařízení %04X/%04X na portu %i: požadavek na %s\n",
                ntohs(udp->vid), ntohs(udp->pid), ntohl(udp->usb_port),
                udp->code1==2 ? "aktivaci":"deaktivaci");
            break;
          case 0x06:
            printf("Zařízení %04X/%04X na portu %i ",
                ntohs(udp->vid), ntohs(udp->pid), ntohl(udp->usb_port));
            switch(udp->code2) {
              case 0x00:
                if(udp->d10) puts("připojeno");
                else puts("odpojeno");
                break;
              case 0x01:
                puts("připraveno");
                break;
              case 0x02:
                puts("aktivováno");
            }
            break;
        }
      }
      break;
    default:
      if(debug) printf("\n=== 0x%02X ===\n", str->code);
      break;
  }
  free(str);
}


struct commstr *waitpacket(unsigned char code) {
  struct commstr *ret;
  time_t b = time(NULL);
  for(ret = readpacket(sock); ret->code != code; ret = readpacket(sock)) {
    dispatch(ret);
    if(time(NULL)-b > MAXWAIT) exit(RETVAL_WAIT);
  }
  return ret;
}


struct commstr *waitpacket61(unsigned short code) {
  struct commstr *ret;
  struct udppacket *udp;
  time_t b = time(NULL);
  for(;;) {
    for(ret = readpacket(sock); ret->code != 0x61; ret = readpacket(sock))
      dispatch(ret);
    udp = (struct udppacket*)(ret->data);
    if(256 * udp->code1 + udp->code2 == code) break;
    dispatch(ret);
    if(time(NULL)-b > MAXWAIT) exit(RETVAL_WAIT);
  }
  return ret;
}


struct commstr *waitpacket_sid(unsigned sid) {
  struct commstr *ret;
  time_t b = time(NULL);
  for(ret = readpacket(sock); ntohl(ret->sid) != sid; ret = readpacket(sock)) {
    dispatch(ret);
    if(time(NULL)-b > MAXWAIT) exit(RETVAL_WAIT);
  }
  return ret;
}


int write_lx(unsigned acc, void *buf, size_t count) {
  struct commstr *ret;
  setupstr(salloc, 0x43, acc, 1,count,1, count);
  memcpy(salloc->data, buf, count);
  salloc->sid = htonl(1);
  sendstr(salloc);
  ret = waitpacket_sid(1);
  if((int)ntohl(ret->did) < 0) exit(RETVAL_WRITE);
  dispatch(ret);
  return ntohs(ret->d12);
}


int read_lx(unsigned acc, void *buf, size_t count) {
  size_t len;
  while(!queue_len[acc]) dispatch(waitpacket(0x52));
  len = MIN(queue_len[acc], count);
  memcpy(buf, read_queue[acc], len);
  queue_len[acc] -= len;
  memmove(read_queue[acc], read_queue[acc]+len, queue_len[acc]);
  sendsimple(0x42, acc, 1,0x1000,0);
  return len;
}



unsigned short finddev_lx(int addr) {
  struct commstr *ret;
  struct devinfo *di;
  unsigned short ord;
  int off, ex = 0;
  sendsimple(0x08, 0, 2,3,0);
  ret = waitpacket(0x18);
  ord = 0;
  for(off = 0; ; off += ntohs(*(unsigned short*)(ret->data+off))) {
    switch(ret->data[off+2]) {
      case 0x04:
        di = (struct devinfo*)(ret->data+off);
        if(ntohl(di->port) == addr+1) {
          if(debug) {
            printf("finddev - port %i:  %04X/%04X  %s\t%s",
                ntohl(di->port), ntohs(di->vid), ntohs(di->pid), di->name1, di->sn);
            if(di->ip[0]) printf("  [%i.%i.%i.%i %s]",
                di->ip[0], di->ip[1], di->ip[2], di->ip[3], di->client);
            printf("\n");
          }
          ex = 1;
          break;
        }
        ord++;
        break;
      case 0x00:
        if(debug) {
          printf("finddev: na portu %i neni pripojeno zadne zarizeni!\n", addr);
        }
        ord = NOT_FOUND;
        ex = 1;
        break;
    }
    if(ex) break;
  }
  free(ret);
  return ord;
}



int opendev_lx(int addr, int *acc) {
  struct commstr *ret;
  struct udppacket *udp;
  unsigned short ord, port, vid, pid;

  lx_error = LX_ERROR_NO_ERROR;
  if(!acc) {
    lx_error = LX_ERROR_MEMORY;
    return 0;
  }
  if(!salloc) {
    salloc = malloc(sizeof(struct commstr) + MAXDATA);
    if(!salloc) {
      lx_error = LX_ERROR_MEMORY;
      return 0;
    }
  }
  if(!sock) {
    sock = initsock(LX_ADDRESS/*"10.3.4.72"*/);
    if(sock == -1) {
      lx_error = LX_ERROR_NETWORK;
      return 0;
    }
    atexit(freeall);
  }

  setupstr(salloc, 0x01, 0, 2,1,0, 1+strlen(ID_COMPUTER)/*6*/);
  salloc->did = htonl(LX_SERIAL/*0xA38A13A2*/);
  strcpy((char*)salloc->data, ID_COMPUTER/*"VASEK"*/);
  sendstr(salloc);

  free(waitpacket(0x11));

  ord = finddev_lx(addr);
  if(ord == NOT_FOUND) {
    lx_error = LX_ERROR_NOT_FOUND;
    return 0;
  }

  if(debug) printf("Aktivuji zařízení s pořadím %i\n", ord);
  sendsimple(0x09, 0, ord,0,0);

  for(;;) {
    for(ret = readpacket(sock); ret->code != 0x19 && ret->code != 0x61; ret = readpacket(sock))
      dispatch(ret);
    if(ret->code == 0x19) break;
    udp = (struct udppacket*)(ret->data);
    if(udp->code1 == 0x02 && udp->code2 == 0x02) {
      vid = ntohs(udp->vid);
      pid = ntohs(udp->pid);
      port = ntohl(udp->usb_port);
    }
    dispatch(ret);
  }
  if(ret->did == 0) {
    if(debug) printf("Aktivace proběhla úspěšně.\n");
  } else {
    fprintf(stderr, "Aktivace se nezdařila, chybový kód: %i.\n", (int)(ntohl(ret->did)));
    free(ret);
    lx_error = LX_ERROR_ACTIVATE;
    return 0;
  }
  free(ret);

  setupstr(salloc, 0x02, 0, vid, pid, 0, 0);
  salloc->did = htonl(port);
  sendstr(salloc);

  ret = waitpacket(0x12);
  *acc = ntohl(ret->acc);
  if(debug) printf("  ord = %i: acc = %i\n", ord, *acc);
  free(ret);

  sendsimple(0x08, 0, 2,3,0);
  dispatch(waitpacket(0x18));

  if(debug) printf("Nastavuji parametry RS232\n");

  sendconfig(*acc, 8, 0x41,0x11,0,0,0,0,0,0);     /* Reset */
  sendconfig(*acc, 8, 0x41,0,0x01,0,0,0,0,0);     /* UART enable */
  sendconfig(*acc, 24, 0x41,0x13,0,0,0,0,0x10,0,0x01,0,0,0,0x40,0,0,0,0,0,0,0,0,0,0,0);   /* "set flow" */
  sendconfig(*acc, 8, 0xC1,0x0F,0,0,0,0,0x40,0x02);       /* "get props" */
  sendconfig(*acc, 8, 0xC1,0x08,0,0,0,0,0x01,0);          /* "get mdmsts" */
  sendconfig(*acc, 8, 0x02,0x01,0,0,0x81,0,0,0);  /* ??? */
  sendsimple(0x47, *acc, 1,1,0);
  sendconfig(*acc, 8, 0x41,0x01,0x04,0,0,0,0,0);  /* Baud 921600 */
  sendsimple(0x42, *acc, 1,0x1000,0);
  sendconfig(*acc, 8, 0x41,0x07,0x02,0x02,0,0,0,0);       /* RTS */
  sendconfig(*acc, 8, 0x41,0x07,0x01,0x01,0,0,0,0);       /* DTR */
  sendconfig(*acc, 8, 0x41,0x03,0x00,0x08,0,0,0,0);       /* 8 data bits, 1 stop bit, parity off */
  sendconfig(*acc, 14, 0x41,0x19,0,0,0,0,0x06,0,0,0,0,0,0x11,0x13);       /* "special chars" */
  sendconfig(*acc, 24, 0x41,0x13,0,0,0,0,0x10,0,0x01,0,0,0,0x40,0,0,0,0,0x70,0,0,0,0x1C,0,0);     /* "set flow" */
  sendsimple(0x42, *acc, 1,0x1000,0);
  sendsimple(0x42, *acc, 1,0x1000,0);
  sendconfig(*acc, 8, 0x41,0x05,0x01,0,0,0,0,0);  /* Break on */
  sendconfig(*acc, 8, 0x41,0x05,0x01,0,0,0,0,0);  /* Break on */
  sendconfig(*acc, 8, 0x41,0x05,0x00,0,0,0,0,0);  /* Break off */

  queue_len[*acc] = 0;
  return 1;
}


int closedev_lx(int addr) {
  unsigned short ord;

  ord = finddev_lx(addr);
  if(ord == NOT_FOUND) return 1;

  usleep(500000);
  if(debug) printf("Deaktivuji zařízení s pořadím %i\n", ord);
  sendsimple(0x0C, 0, ord,0,0);
  free(waitpacket(0x1C));

  dispatch(waitpacket61(0x0600));
  dispatch(waitpacket61(0x0600));

  sendsimple(0x08, 0, 2,3,0);
  dispatch(waitpacket(0x18));

  return 1;
}



char *deverror_lx(int addr) {
  static char msg[200];
  int off;
  off = sprintf(msg, "Nepodarilo se pripojit k zarizeni na portu c. %i.\n", addr);
  switch(lx_error) {
    case LX_ERROR_MEMORY:
      sprintf(msg+off, "Chyba pri inicializaci programu.\n");
      break;
    case LX_ERROR_NETWORK:
      sprintf(msg+off, "Chyba sitove komunikace.\n");
      break;
    case LX_ERROR_NOT_FOUND:
      sprintf(msg+off, "Zkontrolujte prosim, zda je zarizeni pripojeno na tomto portu.\n");
      break;
    case LX_ERROR_ACTIVATE:
      sprintf(msg+off, "Zarizeni odmita pozadavek na aktivaci.\n");
      break;
  }
  return msg;
}