/*
 USB descriptor strings: setup. Since the strings must be in Unicode,
 here we have a function usb_setup_strings() that at runtime copies
 all the necessary strings into proper descriptor structures.
 
 Copyright (c) 2008 Dimtel, Inc., All Rights Reserved

 $Id: usb_desc_strings.c,v 1.2 2013/06/05 05:05:35 dim Exp $
 $Date: 2013/06/05 05:05:35 $
 $Author: dim $
 $Revision: 1.2 $
 $Log: usb_desc_strings.c,v $
 Revision 1.2  2013/06/05 05:05:35  dim
 Added support for LLRF4.6

 Revision 1.1  2012/11/11 01:24:32  dim
 Moved from BxB, adapted to compile for both LLRF4 and IGP12

 Revision 1.1  2011/12/27 19:31:47  dim
 Updated to remove deprecated constructs (at, sfr, xdata, sbit)


*/
#include "usb_descriptors.h"
#ifdef LLRF4
#include "desc_size_LLRF4.h"
#endif
#ifdef LLRF46
#include "desc_size_LLRF46.h"
#endif
#ifdef IGP12
#include "desc_size_IGP12.h"
#endif
#include "hwdef.h"
#include "i2c.h"
#include "../include/usb_defs.h"
#include "../include/board_ids.h"
#include "../include/eeprom.h"

extern __xdata char padding1;

#ifdef DEBUG
__xdata uchar *dbg;
#endif

__xdata usb_string * __xdata string_ptrs[N_DESC_STRINGS];

/* Copy a string to Unicode, return length */
static uchar str2unicode(__xdata uchar *dest, char *src)
{
  uchar length = 0;

#ifdef DEBUG
  *dbg++ = 0xaa;
  *dbg++ = (ushort)dest >> 8;
  *dbg++ = (ushort)dest & 0xff;
  *dbg++ = (ushort)src >> 8;
  *dbg++ = (ushort)src & 0xff;
#endif

  while (*src != 0)
  {
    *dest++ = *src++;
    *dest++ = 0;
    length++;
  }
  
#ifdef DEBUG
  *dbg++ = length;
  *dbg++ = 0xee;
#endif
  return length<<1;
}

static uchar setup_descriptor(__xdata usb_string *desc, char *string)
{
  desc->bDescriptorType = USB_DT_STRING;
  desc->bLength = 2 + str2unicode((__xdata uchar *)desc + 2, string);
  
  
#ifdef DEBUG
  *dbg++ = 0xbb;
  *dbg++ = desc->bLength;
  *dbg++ = 0xff;
#endif
  return desc->bLength;
}

/* Set up string descriptors */
void usb_setup_strings(void)
{
  __bit sflag = 1;
  __xdata uchar ser_len = 0;
  __xdata uchar *p;
  ushort cnt = 1;
  __xdata usb_string *desc;
  __xdata uchar serial[USBDESC_SERIAL_MAX+1];

#ifdef DEBUG  
  dbg = (__xdata uchar *)0x3100;
#endif
  
  desc = (__xdata usb_string *)(&padding1 + 1);
  
  desc->bLength         = 6;
  desc->bDescriptorType = USB_DT_STRING;
  p = &desc->wData;
  *p++ = 0;
  *p++ = 0;
  *(__xdata ushort *)p = 0x0409; /* US English */
  p += 2;
  
  string_ptrs[0] = desc;

  string_ptrs[cnt++] = (__xdata usb_string *)p;

  p += setup_descriptor((__xdata usb_string *)p, iManufacturer);
  
  string_ptrs[cnt++] = (__xdata usb_string *)p;
  p += setup_descriptor((__xdata usb_string *)p, iProduct);
  
  string_ptrs[cnt++] = (__xdata usb_string *)p;
  
  /* Read serial number from the EEPROM */
  
  /* Set address */
  serial[0] = (ushort)EEPROM_SERIAL>>8;
  serial[1] = (ushort)EEPROM_SERIAL & 0xff;
  if (i2c_write(I2C_EEPROM_ADDR, serial, 2) == 0)
    sflag = 0;

  if (!sflag || !i2c_read(I2C_EEPROM_ADDR, serial, 2))
    sflag = 0;

  /* Check the header */
  if (!sflag || (serial[0] != EEPROM_SERIAL_HDR1) || (serial[1] != EEPROM_SERIAL_HDR2))
    sflag = 0;
    
  if (!sflag || !i2c_read(I2C_EEPROM_ADDR, &ser_len, 1))
    sflag = 0;
    
  if (!sflag || (ser_len > USBDESC_SERIAL_MAX))
    sflag = 0;
    
  if (!sflag || !i2c_read(I2C_EEPROM_ADDR, serial, ser_len))
    sflag = 0;
    
  if (sflag)
  {
    /* Terminator */
    serial[ser_len] = 0;
    p += setup_descriptor((__xdata usb_string *)p, serial);
  }
  else
    p += setup_descriptor((__xdata usb_string *)p, iSerial);

  string_ptrs[cnt++] = (__xdata usb_string *)p;
  p += setup_descriptor((__xdata usb_string *)p, iInter0Alt0HS);

  string_ptrs[cnt++] = (__xdata usb_string *)p;
  p += setup_descriptor((__xdata usb_string *)p, iInter0Alt1HS);

  string_ptrs[cnt++] = (__xdata usb_string *)p;
  p += setup_descriptor((__xdata usb_string *)p, iInter0Alt0FS);

  string_ptrs[cnt] = (__xdata usb_string *)p;
  p += setup_descriptor((__xdata usb_string *)p, iInter0Alt1FS);
}
