Return to Snippet

Revision: 20875
at November 29, 2009 01:17 by jimfred


Updated Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq; // for SequenceEqual (array comparison).
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices; // for DllImport
using System.Diagnostics; // for Assert
using System.Threading; // for Thread.Sleep


namespace CypressEepromUtility
{
   public partial class MainForm : Form
   {
      // This is the main form for a utility to read, write, verify and erase the EEPROM on a Cypress FX2 processor board.
      // Some of the code was taken from the EzMr (CyConsole) utility which used the EzUsb driver.
      // Calls are made to deviceIoControl to access the EzUsb driver.

      #region Vend_AX firmware array.
      // This array was generated from C:\Cypress\USB\Examples\FX2LP\Vend_ax\Vend_Ax.hex.
      // The .hex was was reconstituted into a binary buffer and then written to a text file and its contents included here.
      // The code used to create the text file is testIntelHexToByteArray().
      // The AA bytes are gaps that are untouched by the .hex contents.
      // The original VendAx array taken from Vend_Ax.h in the EzMr project 
      // caused random Windows driver errors, crashes and PC lock-ups when coming out of reset.
      // It would fail about 1 out of 5 startups and would otherwise run normally.

      public static byte[] VendAxCode = new byte[]
      {
         #region fwCode
         0x02, 0x07, 0xF3, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,  0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,  0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,  0xAA, 0x02, 0x0D, 0x60, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x02, 0x08, 0x00,  0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0x02, 0x08, 0x00, 0xAA, 0xAA, 0xAA, 0xAA,  0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,  0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x90, 0xE6,  0xB9, 0xE0, 0x24, 0x5E, 0xB4, 0x0B, 0x00, 0x40, 0x03, 0x02, 
         0x03, 0x98, 0x90, 0x00, 0x9C, 0x75, 0xF0, 0x03, 0xA4, 0xC5,  0x83, 0x25, 0xF0, 0xC5, 0x83, 0x73, 0x02, 0x01, 0x92, 0x02, 
         0x01, 0x92, 0x02, 0x01, 0x0D, 0x02, 0x00, 0xBD, 0x02, 0x00,  0xD7, 0x02, 0x00, 0xF3, 0x02, 0x01, 0x3C, 0x02, 0x01, 0x8C, 
         0x02, 0x01, 0x16, 0x02, 0x01, 0x29, 0x02, 0x01, 0x62, 0x90,  0xE7, 0x40, 0xE5, 0x19, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 
         0x90, 0xE6, 0x8B, 0x04, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44,  0x80, 0xF0, 0x02, 0x03, 0x98, 0x90, 0xE6, 0x0A, 0xE0, 0x90, 
         0xE7, 0x40, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6,  0x8B, 0x04, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 
         0x02, 0x03, 0x98, 0x90, 0xE7, 0x40, 0x74, 0x0F, 0xF0, 0xE4,  0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 0x90, 
         0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 0x02, 0x03, 0x98, 0x90,  0xE6, 0xBA, 0xE0, 0xF5, 0x17, 0x02, 0x03, 0x98, 0x90, 0xE6, 
         0x7A, 0xE0, 0x54, 0xFE, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0,  0x90, 0xE6, 0x8B, 0xF0, 0x02, 0x03, 0x98, 0x90, 0xE6, 0x7A, 
         0xE0, 0x44, 0x01, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90,  0xE6, 0x8B, 0xF0, 0x02, 0x03, 0x98, 0x90, 0xE7, 0x40, 0x74, 
         0x07, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B,  0x04, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 0x7F, 
         0xE8, 0x7E, 0x03, 0x12, 0x07, 0xAD, 0xD2, 0x04, 0x12, 0x0B,  0x87, 0x02, 0x03, 0x98, 0x90, 0xE6, 0xB5, 0xE0, 0x54, 0xFE, 
         0xF0, 0x90, 0xE6, 0xBF, 0xE0, 0x90, 0xE6, 0x8A, 0xF0, 0x90,  0xE6, 0xBE, 0xE0, 0x90, 0xE6, 0x8B, 0xF0, 0x90, 0xE6, 0xBB, 
         0xE0, 0x90, 0xE6, 0xB3, 0xF0, 0x90, 0xE6, 0xBA, 0xE0, 0x90,  0xE6, 0xB4, 0xF0, 0x02, 0x03, 0x98, 0x75, 0x19, 0x01, 0x43, 
         0x17, 0x01, 0x90, 0xE6, 0xBA, 0xE0, 0x75, 0x31, 0x00, 0xF5,  0x32, 0xA3, 0xE0, 0xFE, 0xE4, 0xEE, 0x42, 0x31, 0x90, 0xE6, 
         0xBE, 0xE0, 0x75, 0x33, 0x00, 0xF5, 0x34, 0xA3, 0xE0, 0xFE,  0xE4, 0xEE, 0x42, 0x33, 0x90, 0xE6, 0xB8, 0xE0, 0x64, 0xC0, 
         0x60, 0x03, 0x02, 0x02, 0x82, 0xE5, 0x34, 0x45, 0x33, 0x70,  0x03, 0x02, 0x03, 0x98, 0x90, 0xE6, 0xA0, 0xE0, 0x20, 0xE1, 
         0xF9, 0xC3, 0xE5, 0x34, 0x94, 0x40, 0xE5, 0x33, 0x94, 0x00,  0x50, 0x08, 0x85, 0x33, 0x35, 0x85, 0x34, 0x36, 0x80, 0x06, 
         0x75, 0x35, 0x00, 0x75, 0x36, 0x40, 0x90, 0xE6, 0xB9, 0xE0,  0xB4, 0xA3, 0x35, 0xE4, 0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 
         0x38, 0x95, 0x36, 0xE5, 0x37, 0x95, 0x35, 0x50, 0x60, 0xE5,  0x32, 0x25, 0x38, 0xF5, 0x82, 0xE5, 0x31, 0x35, 0x37, 0xF5, 
         0x83, 0xE0, 0xFF, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4,  0x34, 0xE7, 0xF5, 0x83, 0xEF, 0xF0, 0x05, 0x38, 0xE5, 0x38, 
         0x70, 0x02, 0x05, 0x37, 0x80, 0xD0, 0xE4, 0xF5, 0x37, 0xF5,  0x38, 0xC3, 0xE5, 0x38, 0x95, 0x36, 0xE5, 0x37, 0x95, 0x35, 
         0x50, 0x18, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34,  0xE7, 0xF5, 0x83, 0x74, 0xCD, 0xF0, 0x05, 0x38, 0xE5, 0x38, 
         0x70, 0x02, 0x05, 0x37, 0x80, 0xDD, 0xAD, 0x36, 0x7A, 0xE7,  0x79, 0x40, 0x7E, 0xE7, 0x7F, 0x40, 0xAB, 0x07, 0xAF, 0x32, 
         0xAE, 0x31, 0x12, 0x08, 0xB8, 0xE4, 0x90, 0xE6, 0x8A, 0xF0,  0x90, 0xE6, 0x8B, 0xE5, 0x36, 0xF0, 0x25, 0x32, 0xF5, 0x32, 
         0xE5, 0x35, 0x35, 0x31, 0xF5, 0x31, 0xC3, 0xE5, 0x34, 0x95,  0x36, 0xF5, 0x34, 0xE5, 0x33, 0x95, 0x35, 0xF5, 0x33, 0x02, 
         0x01, 0xBD, 0x90, 0xE6, 0xB8, 0xE0, 0x64, 0x40, 0x60, 0x03,  0x02, 0x03, 0x98, 0xE5, 0x1A, 0x70, 0x05, 0x12, 0x09, 0x67, 
         0x8F, 0x1A, 0xE5, 0x34, 0x45, 0x33, 0x70, 0x03, 0x02, 0x03,  0x98, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0xF0, 
         0x90, 0xE6, 0xA0, 0xE0, 0x20, 0xE1, 0xF9, 0x90, 0xE6, 0x8B,  0xE0, 0x75, 0x35, 0x00, 0xF5, 0x36, 0x90, 0xE6, 0xB9, 0xE0, 
         0xB4, 0xA3, 0x38, 0xE4, 0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5,  0x38, 0x95, 0x36, 0xE5, 0x37, 0x95, 0x35, 0x40, 0x03, 0x02, 
         0x03, 0x7C, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34,  0xE7, 0xF5, 0x83, 0xE0, 0xFF, 0xE5, 0x32, 0x25, 0x38, 0xF5, 
         0x82, 0xE5, 0x31, 0x35, 0x37, 0xF5, 0x83, 0xEF, 0xF0, 0x05,  0x38, 0xE5, 0x38, 0x70, 0x02, 0x05, 0x37, 0x80, 0xCD, 0xE4, 
         0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 0x38, 0x95, 0x36, 0xE5,  0x37, 0x95, 0x35, 0x50, 0x75, 0x85, 0x1A, 0x39, 0xE5, 0x1A, 
         0x64, 0x01, 0x60, 0x44, 0xE5, 0x32, 0x25, 0x38, 0xFF, 0xE5,  0x31, 0x35, 0x37, 0xFE, 0xE5, 0x1A, 0x24, 0xFF, 0xFD, 0xE4, 
         0x34, 0xFF, 0x5E, 0xFE, 0xEF, 0x5D, 0x4E, 0x60, 0x10, 0xE5,  0x32, 0x25, 0x38, 0xFF, 0xE5, 0x1A, 0x14, 0x5F, 0xFF, 0xC3, 
         0xE5, 0x1A, 0x9F, 0xF5, 0x39, 0xC3, 0xE5, 0x36, 0x95, 0x38,  0xFF, 0xE5, 0x35, 0x95, 0x37, 0xFE, 0xC3, 0xEF, 0x95, 0x39, 
         0xEE, 0x94, 0x00, 0x50, 0x07, 0xC3, 0xE5, 0x36, 0x95, 0x38,  0xF5, 0x39, 0xE5, 0x32, 0x25, 0x38, 0xFF, 0xE5, 0x31, 0x35, 
         0x37, 0xFE, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34,  0xE7, 0xAD, 0x82, 0xFC, 0xAB, 0x39, 0x12, 0x0A, 0x9C, 0xE5, 
         0x39, 0x25, 0x38, 0xF5, 0x38, 0xE4, 0x35, 0x37, 0xF5, 0x37,  0x80, 0x80, 0xE5, 0x36, 0x25, 0x32, 0xF5, 0x32, 0xE5, 0x35, 
         0x35, 0x31, 0xF5, 0x31, 0xC3, 0xE5, 0x34, 0x95, 0x36, 0xF5,  0x34, 0xE5, 0x33, 0x95, 0x35, 0xF5, 0x33, 0x02, 0x02, 0x96, 
         0xC3, 0x22, 0x90, 0xE6, 0xB9, 0xE0, 0x70, 0x03, 0x02, 0x04,  0x85, 0x14, 0x70, 0x03, 0x02, 0x05, 0x2E, 0x24, 0xFE, 0x70, 
         0x03, 0x02, 0x05, 0xC4, 0x24, 0xFB, 0x70, 0x03, 0x02, 0x04,  0x7F, 0x14, 0x70, 0x03, 0x02, 0x04, 0x79, 0x14, 0x70, 0x03, 
         0x02, 0x04, 0x6D, 0x14, 0x70, 0x03, 0x02, 0x04, 0x73, 0x24,  0x05, 0x60, 0x03, 0x02, 0x06, 0x39, 0x12, 0x0D, 0x68, 0x40, 
         0x03, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xBB, 0xE0, 0x24, 0xFE,  0x60, 0x3B, 0x14, 0x60, 0x56, 0x24, 0xFD, 0x60, 0x16, 0x14, 
         0x60, 0x40, 0x24, 0x06, 0x70, 0x75, 0xE5, 0x0A, 0x90, 0xE6,  0xB3, 0xF0, 0xE5, 0x0B, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x06, 
         0x45, 0x12, 0x0D, 0x33, 0x50, 0x0F, 0xE5, 0x12, 0x90, 0xE6,  0xB3, 0xF0, 0xE5, 0x13, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x02, 0x06,  0x45, 0xE5, 0x0C, 0x90, 0xE6, 0xB3, 0xF0, 0xE5, 0x0D, 0x90, 
         0xE6, 0xB4, 0xF0, 0x02, 0x06, 0x45, 0xE5, 0x0E, 0x90, 0xE6,  0xB3, 0xF0, 0xE5, 0x0F, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xBA, 0xE0, 0xFF, 0x12, 0x0B, 0xE2, 0xAA,  0x06, 0xA9, 0x07, 0x7B, 0x01, 0xEA, 0x49, 0x4B, 0x60, 0x0D, 
         0xEE, 0x90, 0xE6, 0xB3, 0xF0, 0xEF, 0x90, 0xE6, 0xB4, 0xF0,  0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 
         0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0,  0x02, 0x06, 0x45, 0x12, 0x0C, 0xF1, 0x02, 0x06, 0x45, 0x12, 
         0x0D, 0x50, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x48, 0x02, 0x06,  0x45, 0x12, 0x0C, 0xDF, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x6A, 
         0x40, 0x03, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xB8, 0xE0, 0x24,  0x7F, 0x60, 0x2B, 0x14, 0x60, 0x3C, 0x24, 0x02, 0x60, 0x03, 
         0x02, 0x05, 0x24, 0xA2, 0x00, 0xE4, 0x33, 0xFF, 0x25, 0xE0,  0xFF, 0xA2, 0x02, 0xE4, 0x33, 0x4F, 0x90, 0xE7, 0x40, 0xF0, 
         0xE4, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B,  0x74, 0x02, 0xF0, 0x02, 0x06, 0x45, 0xE4, 0x90, 0xE7, 0x40, 
         0xF0, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B,  0x74, 0x02, 0xF0, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xBC, 0xE0, 
         0x54, 0x7E, 0xFF, 0x7E, 0x00, 0xE0, 0xD3, 0x94, 0x80, 0x40,  0x06, 0x7C, 0x00, 0x7D, 0x01, 0x80, 0x04, 0x7C, 0x00, 0x7D, 
         0x00, 0xEC, 0x4E, 0xFE, 0xED, 0x4F, 0x24, 0x3E, 0xF5, 0x82,  0x74, 0x0D, 0x3E, 0xF5, 0x83, 0xE4, 0x93, 0xFF, 0x33, 0x95, 
         0xE0, 0xFE, 0xEF, 0x24, 0xA1, 0xFF, 0xEE, 0x34, 0xE6, 0x8F,  0x82, 0xF5, 0x83, 0xE0, 0x54, 0x01, 0x90, 0xE7, 0x40, 0xF0, 
         0xE4, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B,  0x74, 0x02, 0xF0, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 
         0x44, 0x01, 0xF0, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x6C, 0x40,  0x03, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xB8, 0xE0, 0x24, 0xFE, 
         0x60, 0x1D, 0x24, 0x02, 0x60, 0x03, 0x02, 0x06, 0x45, 0x90,  0xE6, 0xBA, 0xE0, 0xB4, 0x01, 0x05, 0xC2, 0x00, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x02, 0x06,  0x45, 0x90, 0xE6, 0xBA, 0xE0, 0x70, 0x59, 0x90, 0xE6, 0xBC, 
         0xE0, 0x54, 0x7E, 0xFF, 0x7E, 0x00, 0xE0, 0xD3, 0x94, 0x80,  0x40, 0x06, 0x7C, 0x00, 0x7D, 0x01, 0x80, 0x04, 0x7C, 0x00, 
         0x7D, 0x00, 0xEC, 0x4E, 0xFE, 0xED, 0x4F, 0x24, 0x3E, 0xF5,  0x82, 0x74, 0x0D, 0x3E, 0xF5, 0x83, 0xE4, 0x93, 0xFF, 0x33, 
         0x95, 0xE0, 0xFE, 0xEF, 0x24, 0xA1, 0xFF, 0xEE, 0x34, 0xE6,  0x8F, 0x82, 0xF5, 0x83, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0xE6, 
         0xBC, 0xE0, 0x54, 0x80, 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F,  0xFF, 0xE0, 0x54, 0x0F, 0x2F, 0x90, 0xE6, 0x83, 0xF0, 0xE0, 
         0x44, 0x20, 0xF0, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0,  0x44, 0x01, 0xF0, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x6E, 0x50, 
         0x7C, 0x90, 0xE6, 0xB8, 0xE0, 0x24, 0xFE, 0x60, 0x20, 0x24,  0x02, 0x70, 0x5B, 0x90, 0xE6, 0xBA, 0xE0, 0xB4, 0x01, 0x04, 
         0xD2, 0x00, 0x80, 0x65, 0x90, 0xE6, 0xBA, 0xE0, 0x64, 0x02,  0x60, 0x5D, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x80, 
         0x54, 0x90, 0xE6, 0xBC, 0xE0, 0x54, 0x7E, 0xFF, 0x7E, 0x00,  0xE0, 0xD3, 0x94, 0x80, 0x40, 0x06, 0x7C, 0x00, 0x7D, 0x01, 
         0x80, 0x04, 0x7C, 0x00, 0x7D, 0x00, 0xEC, 0x4E, 0xFE, 0xED,  0x4F, 0x24, 0x3E, 0xF5, 0x82, 0x74, 0x0D, 0x3E, 0xF5, 0x83, 
         0xE4, 0x93, 0xFF, 0x33, 0x95, 0xE0, 0xFE, 0xEF, 0x24, 0xA1,  0xFF, 0xEE, 0x34, 0xE6, 0x8F, 0x82, 0xF5, 0x83, 0xE0, 0x44, 
         0x01, 0xF0, 0x80, 0x15, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01,  0xF0, 0x80, 0x0C, 0x12, 0x00, 0x80, 0x50, 0x07, 0x90, 0xE6, 
         0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44,  0x80, 0xF0, 0x22, 0xE4, 0xF5, 0x2C, 0xF5, 0x2B, 0xF5, 0x2A, 
         0xF5, 0x29, 0xC2, 0x03, 0xC2, 0x00, 0xC2, 0x02, 0xC2, 0x01,  0x12, 0x0C, 0x6C, 0x7E, 0x0A, 0x7F, 0x00, 0x8E, 0x0A, 0x8F, 
         0x0B, 0x75, 0x12, 0x0A, 0x75, 0x13, 0x12, 0x75, 0x08, 0x0A,  0x75, 0x09, 0x1C, 0x75, 0x10, 0x0A, 0x75, 0x11, 0x4A, 0x75, 
         0x14, 0x0A, 0x75, 0x15, 0x78, 0xEE, 0x54, 0xC0, 0x70, 0x03,  0x02, 0x07, 0x52, 0x75, 0x2D, 0x00, 0x75, 0x2E, 0x80, 0x8E, 
         0x2F, 0x8F, 0x30, 0xC3, 0x74, 0x9A, 0x9F, 0xFF, 0x74, 0x0A,  0x9E, 0xCF, 0x24, 0x02, 0xCF, 0x34, 0x00, 0xFE, 0xE4, 0x8F, 
         0x28, 0x8E, 0x27, 0xF5, 0x26, 0xF5, 0x25, 0xF5, 0x24, 0xF5,  0x23, 0xF5, 0x22, 0xF5, 0x21, 0xAF, 0x28, 0xAE, 0x27, 0xAD, 
         0x26, 0xAC, 0x25, 0xAB, 0x24, 0xAA, 0x23, 0xA9, 0x22, 0xA8,  0x21, 0xC3, 0x12, 0x0D, 0x03, 0x50, 0x37, 0xE5, 0x30, 0x25, 
         0x24, 0xF5, 0x82, 0xE5, 0x2F, 0x35, 0x23, 0xF5, 0x83, 0xE0,  0xFF, 0xE5, 0x2E, 0x25, 0x24, 0xF5, 0x82, 0xE5, 0x2D, 0x35, 
         0x23, 0xF5, 0x83, 0xEF, 0xF0, 0xE4, 0xFA, 0xF9, 0xF8, 0xE5,  0x24, 0x24, 0x01, 0xF5, 0x24, 0xEA, 0x35, 0x23, 0xF5, 0x23, 
         0xE9, 0x35, 0x22, 0xF5, 0x22, 0xE8, 0x35, 0x21, 0xF5, 0x21,  0x80, 0xB3, 0x85, 0x2D, 0x0A, 0x85, 0x2E, 0x0B, 0x74, 0x00, 
         0x24, 0x80, 0xFF, 0x74, 0x0A, 0x34, 0xFF, 0xFE, 0xC3, 0xE5,  0x13, 0x9F, 0xF5, 0x13, 0xE5, 0x12, 0x9E, 0xF5, 0x12, 0xC3, 
         0xE5, 0x0D, 0x9F, 0xF5, 0x0D, 0xE5, 0x0C, 0x9E, 0xF5, 0x0C,  0xC3, 0xE5, 0x0F, 0x9F, 0xF5, 0x0F, 0xE5, 0x0E, 0x9E, 0xF5, 
         0x0E, 0xC3, 0xE5, 0x09, 0x9F, 0xF5, 0x09, 0xE5, 0x08, 0x9E,  0xF5, 0x08, 0xC3, 0xE5, 0x11, 0x9F, 0xF5, 0x11, 0xE5, 0x10, 
         0x9E, 0xF5, 0x10, 0xC3, 0xE5, 0x15, 0x9F, 0xF5, 0x15, 0xE5,  0x14, 0x9E, 0xF5, 0x14, 0xD2, 0xE8, 0x43, 0xD8, 0x20, 0x90, 
         0xE6, 0x68, 0xE0, 0x44, 0x09, 0xF0, 0x90, 0xE6, 0x5C, 0xE0,  0x44, 0x3D, 0xF0, 0xD2, 0xAF, 0x90, 0xE6, 0x80, 0xE0, 0x54, 
         0xF7, 0xF0, 0x53, 0x8E, 0xF8, 0xC2, 0x03, 0x12, 0x07, 0xFF,  0x30, 0x01, 0x05, 0x12, 0x03, 0x9A, 0xC2, 0x01, 0x30, 0x03, 
         0xF2, 0x12, 0x0D, 0x64, 0x50, 0xED, 0xC2, 0x03, 0x12, 0x0C,  0x0D, 0x20, 0x00, 0x16, 0x90, 0xE6, 0x82, 0xE0, 0x30, 0xE7, 
         0x04, 0xE0, 0x20, 0xE1, 0xEF, 0x90, 0xE6, 0x82, 0xE0, 0x30,  0xE6, 0x04, 0xE0, 0x20, 0xE0, 0xE4, 0x12, 0x0B, 0xB6, 0x12, 
         0x0D, 0x66, 0x80, 0xC7, 0x22, 0x8E, 0x3A, 0x8F, 0x3B, 0x90,  0xE6, 0x00, 0xE0, 0x54, 0x18, 0x70, 0x12, 0xE5, 0x3B, 0x24, 
         0x01, 0xFF, 0xE4, 0x35, 0x3A, 0xC3, 0x13, 0xF5, 0x3A, 0xEF,  0x13, 0xF5, 0x3B, 0x80, 0x15, 0x90, 0xE6, 0x00, 0xE0, 0x54, 
         0x18, 0xFF, 0xBF, 0x10, 0x0B, 0xE5, 0x3B, 0x25, 0xE0, 0xF5,  0x3B, 0xE5, 0x3A, 0x33, 0xF5, 0x3A, 0xE5, 0x3B, 0x15, 0x3B, 
         0xAE, 0x3A, 0x70, 0x02, 0x15, 0x3A, 0x4E, 0x60, 0x05, 0x12,  0x0C, 0x21, 0x80, 0xEE, 0x22, 0x78, 0x7F, 0xE4, 0xF6, 0xD8, 
         0xFD, 0x75, 0x81, 0x41, 0x02, 0x06, 0x4D, 0x22, 0x02, 0x0C,  0x32, 0x00, 0x02, 0x0C, 0xB3, 0x00, 0x02, 0x0C, 0x9D, 0x00, 
         0x02, 0x0C, 0x85, 0x00, 0x02, 0x0B, 0x19, 0x00, 0x02, 0x0B,  0x50, 0x00, 0x02, 0x09, 0xFF, 0x00, 0x02, 0x0D, 0x70, 0x00, 
         0x02, 0x0D, 0x71, 0x00, 0x02, 0x0D, 0x72, 0x00, 0x02, 0x0D,  0x73, 0x00, 0x02, 0x0D, 0x74, 0x00, 0x02, 0x0D, 0x75, 0x00, 
         0x02, 0x0D, 0x76, 0x00, 0x02, 0x0D, 0x77, 0x00, 0x02, 0x0D,  0x78, 0x00, 0x02, 0x0D, 0x79, 0x00, 0x02, 0x0D, 0x70, 0x00, 
         0x02, 0x0D, 0x7A, 0x00, 0x02, 0x0D, 0x7B, 0x00, 0x02, 0x0D,  0x7C, 0x00, 0x02, 0x0D, 0x7D, 0x00, 0x02, 0x0D, 0x7E, 0x00, 
         0x02, 0x0D, 0x7F, 0x00, 0x02, 0x0D, 0x80, 0x00, 0x02, 0x0D,  0x70, 0x00, 0x02, 0x0D, 0x70, 0x00, 0x02, 0x0D, 0x70, 0x00, 
         0x02, 0x0D, 0x81, 0x00, 0x02, 0x0D, 0x82, 0x00, 0x02, 0x0D,  0x83, 0x00, 0x02, 0x0D, 0x84, 0x00, 0x02, 0x0D, 0x85, 0x00, 
         0x02, 0x0D, 0x86, 0x00, 0x02, 0x0D, 0x87, 0x00, 0x02, 0x0D,  0x88, 0x00, 0x02, 0x0D, 0x89, 0x00, 0x02, 0x0D, 0x8A, 0x00, 
         0x02, 0x0D, 0x8B, 0x00, 0x02, 0x0D, 0x8C, 0x00, 0x02, 0x0D,  0x8D, 0x00, 0x02, 0x0D, 0x8E, 0x00, 0x02, 0x0D, 0x8F, 0x00, 
         0x02, 0x0D, 0x90, 0x00, 0x02, 0x0D, 0x91, 0x00, 0x02, 0x0D,  0x92, 0x00, 0x8E, 0x3C, 0x8F, 0x3D, 0x8D, 0x3E, 0x8A, 0x3F, 
         0x8B, 0x40, 0x12, 0x0D, 0x58, 0x12, 0x0D, 0x24, 0x12, 0x0C,  0xC9, 0x50, 0x01, 0x22, 0xE5, 0x19, 0x60, 0x0C, 0xE5, 0x3C, 
         0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0C, 0xC9, 0x50, 0x01, 0x22,  0xE5, 0x3D, 0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0C, 0xC9, 0x50, 
         0x01, 0x22, 0x90, 0xE6, 0x78, 0x74, 0x80, 0xF0, 0xE5, 0x17,  0x25, 0xE0, 0x44, 0x01, 0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0D, 
         0x14, 0x50, 0x01, 0x22, 0x90, 0xE6, 0x79, 0xE0, 0xF5, 0x41,  0x12, 0x0D, 0x14, 0x50, 0x01, 0x22, 0xE4, 0xF5, 0x41, 0xE5, 
         0x3E, 0x14, 0xFF, 0xE5, 0x41, 0xC3, 0x9F, 0x50, 0x1C, 0x90,  0xE6, 0x79, 0xE0, 0xFF, 0xE5, 0x40, 0x25, 0x41, 0xF5, 0x82, 
         0xE4, 0x35, 0x3F, 0xF5, 0x83, 0xEF, 0xF0, 0x12, 0x0D, 0x14,  0x50, 0x01, 0x22, 0x05, 0x41, 0x80, 0xDA, 0x90, 0xE6, 0x78, 
         0x74, 0x20, 0xF0, 0x12, 0x0D, 0x14, 0x50, 0x01, 0x22, 0x90,  0xE6, 0x79, 0xE0, 0xFF, 0xE5, 0x40, 0x25, 0x41, 0xF5, 0x82, 
         0xE4, 0x35, 0x3F, 0xF5, 0x83, 0xEF, 0xF0, 0x12, 0x0D, 0x14,  0x50, 0x01, 0x22, 0x90, 0xE6, 0x78, 0x74, 0x40, 0xF0, 0x90, 
         0xE6, 0x79, 0xE0, 0xF5, 0x41, 0xC3, 0x22, 0xE5, 0x19, 0x70,  0x03, 0x7F, 0x01, 0x22, 0x7A, 0x10, 0x7B, 0x40, 0x7D, 0x40, 
         0xE4, 0xFF, 0xFE, 0x12, 0x08, 0xB8, 0xE4, 0xF5, 0x3A, 0x74,  0x00, 0x25, 0x3A, 0xF5, 0x82, 0xE4, 0x34, 0x10, 0xF5, 0x83, 
         0xE5, 0x3A, 0xF0, 0x05, 0x3A, 0xE5, 0x3A, 0xB4, 0x40, 0xEB,  0x7C, 0x10, 0x7D, 0x00, 0x7B, 0x40, 0xE4, 0xFF, 0xFE, 0x12, 
         0x0A, 0x9C, 0xE4, 0xF5, 0x3A, 0xE5, 0x3A, 0xF4, 0xFF, 0x74,  0x00, 0x25, 0x3A, 0xF5, 0x82, 0xE4, 0x34, 0x10, 0xF5, 0x83, 
         0xEF, 0xF0, 0x05, 0x3A, 0xE5, 0x3A, 0xB4, 0x40, 0xE8, 0x7A,  0x10, 0x7B, 0x00, 0x7D, 0x40, 0xE4, 0xFF, 0xFE, 0x12, 0x08, 
         0xB8, 0x90, 0x10, 0x00, 0xE0, 0xF5, 0x3A, 0xE5, 0x3A, 0x30,  0xE0, 0x05, 0x75, 0x3B, 0x01, 0x80, 0x08, 0x63, 0x3A, 0x3F, 
         0x05, 0x3A, 0x85, 0x3A, 0x3B, 0xE4, 0xF5, 0x3A, 0xE5, 0x3A,  0xC3, 0x94, 0x40, 0x50, 0x15, 0xAF, 0x3A, 0x7E, 0x00, 0x7C, 
         0x10, 0x7D, 0x40, 0xAB, 0x3B, 0x12, 0x0A, 0x9C, 0xE5, 0x3B,  0x25, 0x3A, 0xF5, 0x3A, 0x80, 0xE4, 0xAF, 0x3B, 0x22, 0x32, 
         0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xB4, 0x04,  0x04, 0x10, 0x00, 0x00, 0x01, 0x02, 0x00, 0x01, 0x0A, 0x06, 
         0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x09, 0x02,  0x2E, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 
         0x00, 0x04, 0xFF, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02,  0x00, 0x02, 0x00, 0x07, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, 
         0x07, 0x05, 0x86, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x88,  0x02, 0x00, 0x02, 0x00, 0x09, 0x02, 0x2E, 0x00, 0x01, 0x01, 
         0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 0x00, 0x04, 0xFF, 0x00,  0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 
         0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x86, 0x02,  0x40, 0x00, 0x00, 0x07, 0x05, 0x88, 0x02, 0x40, 0x00, 0x00, 
         0x04, 0x03, 0x09, 0x04, 0x10, 0x03, 0x43, 0x00, 0x79, 0x00,  0x70, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 
         0x0E, 0x03, 0x45, 0x00, 0x5A, 0x00, 0x2D, 0x00, 0x55, 0x00,  0x53, 0x00, 0x42, 0x00, 0x00, 0x00, 0x8E, 0x3C, 0x8F, 0x3D, 
         0x8C, 0x3E, 0x8D, 0x3F, 0x8B, 0x40, 0xC2, 0x87, 0x43, 0xB2,  0x80, 0x12, 0x0D, 0x58, 0x12, 0x0D, 0x24, 0x12, 0x0C, 0xC9, 
         0x50, 0x04, 0xD2, 0x04, 0x80, 0x59, 0xE5, 0x19, 0x60, 0x0F,  0xE5, 0x3C, 0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0C, 0xC9, 0x50, 
         0x04, 0xD2, 0x04, 0x80, 0x46, 0xE5, 0x3D, 0x90, 0xE6, 0x79,  0xF0, 0x12, 0x0C, 0xC9, 0x50, 0x04, 0xD2, 0x04, 0x80, 0x37, 
         0xE4, 0xF5, 0x41, 0xE5, 0x41, 0xC3, 0x95, 0x40, 0x50, 0x21,  0x05, 0x3F, 0xE5, 0x3F, 0xAE, 0x3E, 0x70, 0x02, 0x05, 0x3E, 
         0x14, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x90, 0xE6, 0x79, 0xF0,  0x12, 0x0D, 0x14, 0x50, 0x04, 0xD2, 0x04, 0x80, 0x10, 0x05, 
         0x41, 0x80, 0xD8, 0x90, 0xE6, 0x78, 0xE0, 0x44, 0x40, 0xF0,  0x12, 0x0C, 0x51, 0xC2, 0x04, 0x53, 0xB2, 0x7F, 0xA2, 0x04, 
         0x22, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x90, 0xE6, 0x80,  0xE0, 0x30, 0xE7, 0x0E, 0x85, 0x08, 0x0C, 0x85, 0x09, 0x0D, 
         0x85, 0x10, 0x0E, 0x85, 0x11, 0x0F, 0x80, 0x0C, 0x85, 0x10,  0x0C, 0x85, 0x11, 0x0D, 0x85, 0x08, 0x0E, 0x85, 0x09, 0x0F, 
         0x53, 0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 0x10, 0xF0, 0xD0,  0x82, 0xD0, 0x83, 0xD0, 0xE0, 0x32, 0xC0, 0xE0, 0xC0, 0x83, 
         0xC0, 0x82, 0x90, 0xE6, 0x80, 0xE0, 0x30, 0xE7, 0x0E, 0x85,  0x08, 0x0C, 0x85, 0x09, 0x0D, 0x85, 0x10, 0x0E, 0x85, 0x11, 
         0x0F, 0x80, 0x0C, 0x85, 0x10, 0x0C, 0x85, 0x11, 0x0D, 0x85,  0x08, 0x0E, 0x85, 0x09, 0x0F, 0x53, 0x91, 0xEF, 0x90, 0xE6, 
         0x5D, 0x74, 0x20, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0,  0x32, 0x30, 0x04, 0x09, 0x90, 0xE6, 0x80, 0xE0, 0x44, 0x0A, 
         0xF0, 0x80, 0x07, 0x90, 0xE6, 0x80, 0xE0, 0x44, 0x08, 0xF0,  0x7F, 0xDC, 0x7E, 0x05, 0x12, 0x07, 0xAD, 0x90, 0xE6, 0x5D, 
         0x74, 0xFF, 0xF0, 0x90, 0xE6, 0x5F, 0xF0, 0x53, 0x91, 0xEF,  0x90, 0xE6, 0x80, 0xE0, 0x54, 0xF7, 0xF0, 0x22, 0x90, 0xE6, 
         0x82, 0xE0, 0x30, 0xE0, 0x04, 0xE0, 0x20, 0xE6, 0x0B, 0x90,  0xE6, 0x82, 0xE0, 0x30, 0xE1, 0x19, 0xE0, 0x30, 0xE7, 0x15, 
         0x90, 0xE6, 0x80, 0xE0, 0x44, 0x01, 0xF0, 0x7F, 0x14, 0x7E,  0x00, 0x12, 0x07, 0xAD, 0x90, 0xE6, 0x80, 0xE0, 0x54, 0xFE, 
         0xF0, 0x22, 0xA9, 0x07, 0xAE, 0x14, 0xAF, 0x15, 0x8F, 0x82,  0x8E, 0x83, 0xA3, 0xE0, 0x64, 0x03, 0x70, 0x17, 0xAD, 0x01, 
         0x19, 0xED, 0x70, 0x01, 0x22, 0x8F, 0x82, 0x8E, 0x83, 0xE0,  0x7C, 0x00, 0x2F, 0xFD, 0xEC, 0x3E, 0xFE, 0xAF, 0x05, 0x80, 
         0xDF, 0xE4, 0xFE, 0xFF, 0x22, 0x90, 0xE6, 0x82, 0xE0, 0x44,  0xC0, 0xF0, 0x90, 0xE6, 0x81, 0xF0, 0x43, 0x87, 0x01, 0x00, 
         0x00, 0x00, 0x00, 0x00, 0x22, 0x74, 0x00, 0xF5, 0x86, 0x90,  0xFD, 0xA5, 0x7C, 0x05, 0xA3, 0xE5, 0x82, 0x45, 0x83, 0x70, 
         0xF9, 0x22, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x90, 0xE6,  0xB5, 0xE0, 0x44, 0x01, 0xF0, 0xD2, 0x01, 0x53, 0x91, 0xEF, 
         0x90, 0xE6, 0x5D, 0x74, 0x01, 0xF0, 0xD0, 0x82, 0xD0, 0x83,  0xD0, 0xE0, 0x32, 0x12, 0x0D, 0x58, 0x12, 0x0D, 0x24, 0x12, 
         0x0D, 0x14, 0x90, 0xE6, 0x78, 0xE0, 0x44, 0x40, 0xF0, 0x12,  0x0D, 0x58, 0x90, 0xE6, 0x78, 0xE0, 0x30, 0xE1, 0xE9, 0x22, 
         0xD2, 0x00, 0xE4, 0xF5, 0x1A, 0x90, 0xE6, 0x78, 0xE0, 0x54,  0x10, 0xFF, 0xC4, 0x54, 0x0F, 0x44, 0x50, 0xF5, 0x17, 0x13, 
         0xE4, 0x33, 0xF5, 0x19, 0x22, 0xC0, 0xE0, 0xC0, 0x83, 0xC0,  0x82, 0xD2, 0x03, 0x53, 0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 
         0x08, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 0x32, 0xC0,  0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x53, 0x91, 0xEF, 0x90, 0xE6, 
         0x5D, 0x74, 0x04, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0,  0x32, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x53, 0x91, 0xEF, 
         0x90, 0xE6, 0x5D, 0x74, 0x02, 0xF0, 0xD0, 0x82, 0xD0, 0x83,  0xD0, 0xE0, 0x32, 0x90, 0xE6, 0x78, 0xE0, 0xFF, 0x30, 0xE0, 
         0xF8, 0xEF, 0x30, 0xE2, 0x02, 0xD3, 0x22, 0xEF, 0x20, 0xE1,  0x02, 0xD3, 0x22, 0xC3, 0x22, 0x90, 0xE7, 0x40, 0xE5, 0x18, 
         0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04,  0xF0, 0xD3, 0x22, 0x90, 0xE7, 0x40, 0xE5, 0x16, 0xF0, 0xE4, 
         0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 0xD3,  0x22, 0xEB, 0x9F, 0xF5, 0xF0, 0xEA, 0x9E, 0x42, 0xF0, 0xE9, 
         0x9D, 0x42, 0xF0, 0xE8, 0x9C, 0x45, 0xF0, 0x22, 0x90, 0xE6,  0x78, 0xE0, 0xFF, 0x30, 0xE0, 0xF8, 0xEF, 0x30, 0xE2, 0x02, 
         0xD3, 0x22, 0xC3, 0x22, 0x90, 0xE6, 0x78, 0x74, 0x80, 0xF0,  0xE5, 0x17, 0x25, 0xE0, 0x90, 0xE6, 0x79, 0xF0, 0x22, 0x90, 
         0xE5, 0x0D, 0xE0, 0x30, 0xE4, 0x02, 0xC3, 0x22, 0xD3, 0x22,  0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 
         0x90, 0xE6, 0xBA, 0xE0, 0xF5, 0x18, 0xD3, 0x22, 0x90, 0xE6,  0xBA, 0xE0, 0xF5, 0x16, 0xD3, 0x22, 0x90, 0xE6, 0x78, 0xE0, 
         0x20, 0xE6, 0xF9, 0x22, 0x53, 0xD8, 0xEF, 0x32, 0xD3, 0x22,  0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,  0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,  0x32, 0x32, 0x32, 0x32, 0x32, 0xAA, 
         // The original array was padded to a size divisible by 16 but apparently that is not required.
         #endregion 
      };
      
      #endregion

      #region DLL APIs

      // CreateFile - Used to get access to a USB device
      [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
      public static extern Microsoft.Win32.SafeHandles.SafeFileHandle CreateFile(
            string lpFileName,
            uint   dwDesiredAccess,
            uint   dwShareMode,
            IntPtr SecurityAttributes,
            uint   dwCreationDisposition,
            uint   dwFlagsAndAttributes,
            IntPtr hTemplateFile
      );

      // public const uint FILE_ATTRIBUTE_NORMAL = 0x80; // not used
      // public const uint FILE_INVALID_HANDLE_VALUE = -1; // not used
      // Taken from WinNt.h. These could be enum-ized for type-safety.
      public const uint FILE_GENERIC_READ  = 0x80000000;
      public const uint FILE_GENERIC_WRITE = 0x40000000;
      public const uint FILE_SHARE_WRITE   = 0x00000002;
      public const uint FILE_CREATE_NEW    = 1;
      public const uint FILE_CREATE_ALWAYS = 2;
      public const uint FILE_OPEN_EXISTING = 3;

      #region multiple DeviceIoControl definitions

      // DeviceIoControl. outbuf as IntPtr
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.VENDOR_REQUEST_IN lpInBuffer,
         [In] int nInBufferSize,
         IntPtr lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.VENDOR_REQUEST_IN lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.ANCHOR_DOWNLOAD_CONTROL lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. intbuf and outbuf as Usb_Device_Descriptor
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.Usb_Device_Descriptor lpInBuffer,
         [In] int nInBufferSize,
         ref EzUsbSys.Usb_Device_Descriptor lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         byte[] lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      #endregion

      /*
         // since I'm using SafeFileHandle, don't call CloseHandle(hOut);
         [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
         [return: MarshalAs(UnmanagedType.Bool)]
         public static extern bool CloseHandle(Microsoft.Win32.SafeHandles.SafeFileHandle hObject);
      */

      #endregion

      #region Other Interop defines

      // Taken from EzUsbSys.h
      public class EzUsbSys
      {
         // These values were taken from EzUsbSys.h which were defined using the CTL_CODE macro defined in WinIoCtl.h
         // lic static uint IOCTL_Ezusb_GET_PIPE_INFO           = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  0, Method.BUFFERED,  FileAccess.ANY );
         public static uint IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR   = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  1, Method.BUFFERED,  FileAccess.ANY );
         public static uint IOCTL_Ezusb_VENDOR_REQUEST          = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  5, Method.BUFFERED,  FileAccess.ANY );
         // lic static uint IOCTL_Ezusb_ANCHOR_DOWNLOAD         = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  7, Method.BUFFERED,  FileAccess.ANY );
         public static uint IOCTL_EZUSB_ANCHOR_DOWNLOAD         = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX + 27, Method.IN_DIRECT, FileAccess.ANY );
         public static uint IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX + 22, Method.IN_DIRECT, FileAccess.ANY );

         enum FileDevice : uint
         {
            UNKNOWN = 0x00000022, // taken from FILE_DEVICE_UNKNOWN in WinIoCtl.h
         };

         enum Method : uint
         {
            BUFFERED = 0, // METHOD_BUFFERED in WinIoCtl.h 
            IN_DIRECT = 1,
            OUT_DIRECT = 2,
            NEITHER = 3,
         };

         enum FileAccess : uint
         {
            ANY = 0, // FILE_ANY_ACCESS in WinIoCtl.h 
         };

         // CTL_CODE macro defined in WinIoCtl.h
         // c# does not allow macros with parameters therefore this function was created.
         // For improved type-safety, the parameters are defined as enums based on uint.
         private static uint CTL_CODE(FileDevice deviceType, uint function, Method method, FileAccess access)
         {
            return ((uint)deviceType << 16) | ((uint)access << 14) | ((uint)function << 2) | (uint)method;
         }

         private const uint Ezusb_IOCTL_INDEX = 0x0800; // taken from Ezusb_IOCTL_INDEX in EzUsbSys.h.

         private static bool testOk = TestOk(); // Run test at startup.

         static bool TestOk()
         {
            // Make sure that this implementation results in the same values seen in EzUsb.
            Debug.Assert(
               IOCTL_Ezusb_VENDOR_REQUEST == 0x00222014 &&
               IOCTL_EZUSB_ANCHOR_DOWNLOAD == 0x0022206D &&
               IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST == 0x00222059
            );
            return true;
         }

         public enum VendAxCmd : byte
         {
            ANCHOR_LOAD_INTERNAL = 0xA0, // ANCHOR_LOAD_INTERNAL in EzUsbSys.h. R+W internal memory. Executed by USB core rather than firmware.
            RwEepromSmall        = 0xA2, // Couldn't find A2 in EzUsbSys.h. It R&W small EEPROM.
            ANCHOR_LOAD_EXTERNAL = 0xA3, // ANCHOR_LOAD_EXTERNAL
            GetEepromSize        = 0xA5, // Couldn't find this in EzUsbSys.h. Consider using this to check EEPROM size.
            RwEepromBig          = 0xA9, // R&W a 'large' EEPROM. I'm assuming that we'll use only the large EEPROM.
         };

         public enum RequestType : byte
         {
            Class = 1,
            Vendor = 2
         };

         public enum Recipient : byte
         {
            Device = 0,
            Interface = 1,
            Endpoint = 2,
            Other = 3
         };

         public enum Direction : byte
         {
            HostToDevice = 0,
            DeviceToHost = 1
         }

         // structs taken from EzUsbSys.h
         // I'll keep the structure definitions as close as possible to the original definitions.
         // A constructor is added for better type-safety.

         public struct VENDOR_REQUEST_IN // from EzUsbSys.h
         {
            public byte   bRequest;
            public UInt16 wValue;
            public UInt16 wIndex;
            public UInt16 wLength;
            public byte   direction;
            public byte   bData;

            public VENDOR_REQUEST_IN(
               VendAxCmd bRequest, 
               int       offset, 
               UInt16    wIndex, 
               int       wLength, 
               Direction direction, 
               byte      bData)
            {
               this.bRequest  = (byte)bRequest;
               this.wValue    = (UInt16)offset;
               this.wIndex    = wIndex;
               this.wLength   = (UInt16)wLength;
               this.direction = (byte)direction;
               this.bData     = bData;
            }

         };

         // Structure used with IOCTL_EZUSB_ANCHOR_DOWNLOAD (but not IOCTL_Ezusb_ANCHOR_DOWNLOAD).
         public struct ANCHOR_DOWNLOAD_CONTROL // From EzUsbSys.h
         {
            UInt16 offset;

            public ANCHOR_DOWNLOAD_CONTROL(UInt16 offset)
            {
               this.offset = offset;
            }
         };


         public struct VENDOR_OR_CLASS_REQUEST_CONTROL // From EzUsbSys.h
         {
            public byte   direction;   // transfer direction (0=host to device, 1=device to host)
            public byte   requestType; // request type (1=class, 2=vendor)
            public byte   recepient;   // recipient (0=device,1=interface,2=endpoint,3=other)
            public byte   requestTypeReservedBits;
            public byte   request;
            public UInt16 value;
            public UInt16 index;

            public VENDOR_OR_CLASS_REQUEST_CONTROL(
               Direction   direction,
               RequestType requestType,
               Recipient   recepient,
               VendAxCmd   request,
               int         value,
               UInt16      index)
            {
               Debug.Assert(value < 0x100000);

               this.direction               = (byte)direction;
               this.requestType             = (byte)requestType;
               this.recepient               = (byte)recepient;
               this.request                 = (byte)request;
               this.value                   = (UInt16)value;
               this.index                   = index;
               this.requestTypeReservedBits = 0;
            }
         };

         public struct Usb_Device_Descriptor // Taken from usb100.h
         {
            public byte   bLength;
            public byte   bDescriptorType;
            public ushort bcdUSB;
            public byte   bDeviceClass;
            public byte   bDeviceSubClass;
            public byte   bDeviceProtocol;
            public byte   bMaxPacketSize0;
            public ushort idVendor;
            public ushort idProduct;
            public ushort bcdDevice;
            public byte   iManufacturer;
            public byte   iProduct;
            public byte   iSerialNumber;
            public byte   bNumConfigurations;
         };

      } // EzUsbSys


      #endregion

      public const int EepromSizeBytes  = 0x8000; // The size of a 32 kB EEPROM.
      public const int UsbMaxPacketSize = 0x1000;

      static Microsoft.Win32.SafeHandles.SafeFileHandle hDevice;
      string iicFilename;
      EzUsbSys.Usb_Device_Descriptor deviceDescriptor = new EzUsbSys.Usb_Device_Descriptor();
      bool deviceOnline = false;
      bool vendAxLoaded = false;

      public MainForm()
      {
         InitializeComponent();
      }

      private void timer1_Tick(object sender, EventArgs e)
      {
         try
         {
            timer1.Stop();

            // This should be modififed to dynamically update a list of devices.
            if (txtDeviceName.Text.Length==0)
            {
               string[] list = GetUnopenedDevices();

               cmboDeviceList.Items.Clear();
               cmboDeviceList.Items.AddRange(list);

               txtQtyDevices.Text = string.Format("{0} device{1} available", list.Length, list.Length != 1 ? "s" : "");

               if (list.Length == 1)
               {
                  cmboDeviceList.SelectedIndex = 0;
               }
            }
            ping();
         }
         finally
         {
            timer1.Start();
         }
      }

      private void ping()
      {
         bool deviceOnlineNow = false;
         byte [] eeFirst8Bytes = null;
         try
         {
            Open();
            GetDeviceDescriptorDevIoCtl(ref deviceDescriptor);
            deviceOnlineNow = true;

            if (vendAxLoaded)
            {
               eeFirst8Bytes = EepromRead(8);
            }

            hDevice.Close();

            if (!vendAxLoaded)
            {
               downloadVendAx(); //  FirmwareDownloadDevIoCtl(VendAxCode);
            }

         }
         catch 
         {
            deviceOnlineNow = false;
         }

         // change in status.
         if (deviceOnline != deviceOnlineNow)
         {
            deviceOnline = deviceOnlineNow;

            txtIdVendor.Text = !deviceOnline ? "" :
               deviceDescriptor.idVendor.ToString("X04") + ( deviceDescriptor.idVendor==0x04B4 ?
               " (Cypress default)" : deviceDescriptor.idVendor==0x08b1 ? " (DCT)" : "" ) 
               ;

            txtDeviceName.Text = deviceOnline ? cmboDeviceList.Text : "";
            txtProductId.Text = deviceOnline ? deviceDescriptor.idProduct.ToString("X04") : "";
            txtDeviceId.Text = deviceOnline ? deviceDescriptor.bcdDevice.ToString("X04") : "";

            ProgressDone(deviceOnline ? "Connected" : "Disconnected");

         }

         if (!deviceOnline)
         {
            vendAxLoaded = false;
         }

         txtVendAxLoaded.Text = vendAxLoaded ? "Yes" : "No";

         if (deviceOnline && vendAxLoaded && eeFirst8Bytes != null)
         {
            txtEeFirst8Bytes.Text = BitConverter.ToString(eeFirst8Bytes).Replace("-", " "); ;
         }
         else
         {
            txtEeFirst8Bytes.Text = "";
         }

         btnDeviceToIicFile.Enabled = deviceOnline;
         btnEraseEeAfter8.Enabled = deviceOnline;
         IicDownload.Enabled = deviceOnline;
         btnVerifyIicFile.Enabled = deviceOnline;
         btnEraseEeprom.Enabled = deviceOnline;
         cmboDeviceToIicFileSize.Enabled = deviceOnline;

         cmboDeviceList.Visible = cmboDeviceList.Items.Count > 1;

      }


      void GetDeviceDescriptorDevIoCtl(ref EzUsbSys.Usb_Device_Descriptor arg)
      {

         Debug.Assert(hDevice != null);

         int pBytesReturned = 0;
         bool bOk;

         bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR,
            ref arg,
            Marshal.SizeOf(arg),
            ref arg,
            Marshal.SizeOf(arg),
            ref pBytesReturned,
            IntPtr.Zero);

         if (!bOk || pBytesReturned != Marshal.SizeOf(arg)) { throw new Exception(); }

      }
      
      
      // taken from CEzMrView::Ezusb_DownloadIntelHex in EzMrView
      void downloadVendAx()
      {
         try
         {
            // EzMr had some sleeps that apparently are not necessary.
            // I'll parameterize the duration as a reminder that it might need to be revisited.
            int sleepDuration = 0; // 400

            ProgressInit(3, "Downloading FW");
            Open();
            SendOpReset();
            hDevice.Close();
            ProgressUpdate(1);

            Thread.Sleep(sleepDuration); // Sleep durations may not be necessary.
            
            Debug.Assert(VendAxCode.Length == 3476);
            ProgressUpdate(2);

            Open();
            vendAxLoaded = VendAxCode.SequenceEqual(IntRamRead(0, VendAxCode.Length));

            if (!vendAxLoaded)
            {
               FirmwareDownloadDevIoCtl(VendAxCode);
               vendAxLoaded = VendAxCode.SequenceEqual(IntRamRead(0, VendAxCode.Length));
               if (!vendAxLoaded) { throw new Exception("VendAx Verify Failed"); }
            }
            Thread.Sleep(sleepDuration);
            SendOpRun();
            hDevice.Close();
            ProgressUpdate(3);
            Thread.Sleep(sleepDuration);
            ProgressDone( "FW downloaded and verified" );
         }
         catch ( Exception ex ) 
         {
            ProgressDone( "FW downloaded Failed" );
         }
      }

      // Open a handle for the Cypress device.
      // The result is stored in this->hDevice.
      void Open()
      {
         hDevice = CreateFile(
            cmboDeviceList.Text,
            FILE_GENERIC_WRITE,
            FILE_SHARE_WRITE,
            IntPtr.Zero,
            FILE_OPEN_EXISTING,
            0,
            IntPtr.Zero);

         if (hDevice.IsInvalid ) throw( new Exception( "Open failed") );
      }

      byte[] EepromRead( int qty)
      {
         Debug.Assert(qty <= EepromSizeBytes);

         if (qty <= UsbMaxPacketSize)
         {
            return EepromReadDevIoCtl(0, qty);
         }

         byte[] buffer = new byte[qty];

         ProgressInit(buffer.Length, "Reading EEPROM");

         for (int remaining = qty, offset=0; remaining>0; )
         {
            int len = Math.Min(remaining, UsbMaxPacketSize);

            // Append smaller buffer onto larger buffer.
            Array.Copy(EepromReadDevIoCtl(offset, len), 0, buffer, offset, len);

            ProgressUpdate(offset);

            offset += len;
            remaining -= len;
         } // for

         ProgressDone("Done reading");
         
         return buffer;

      } // EepromRead

      byte[] EepromReadDevIoCtl(int offset, int qty)
      {
         Debug.Assert(qty <= UsbMaxPacketSize);
         Debug.Assert(offset <= EepromSizeBytes);
         
         byte[] buffer = new byte[qty];

         EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL myRequest = new EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL(
            EzUsbSys.Direction.DeviceToHost,
            EzUsbSys.RequestType.Vendor,
            EzUsbSys.Recipient.Device,
            EzUsbSys.VendAxCmd.RwEepromBig,
            offset, 
            0 );

         Debug.Assert(hDevice != null);

         int pBytesReturned = 0;

         bool bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST,
            ref myRequest,
            Marshal.SizeOf(myRequest),
            buffer,
            buffer.Length,
            ref pBytesReturned,
            IntPtr.Zero);

         if (!bOk) { throw new Exception("DeviceIoControl failed"); }
         if (!(pBytesReturned == qty)) { throw new Exception("DeviceIoControl failed"); }

         return buffer;

      } // EepromReadDevIoCtl

      void EepromWrite( byte[] buffer)
      {
         EepromWriteDevIoCtl(0, buffer);
      }

      void EepromWriteDevIoCtl(int offset, byte[] buffer )
      {

         Debug.Assert(offset <= EepromSizeBytes );
         Debug.Assert(buffer.Length <= UsbMaxPacketSize);

         EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL myRequest = new EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL(
            EzUsbSys.Direction.HostToDevice,
            EzUsbSys.RequestType.Vendor,
            EzUsbSys.Recipient.Device,
            EzUsbSys.VendAxCmd.RwEepromBig,
            offset,
            0);

         Debug.Assert(hDevice != null);

         int pBytesReturned = 0;

         bool bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST,
            ref myRequest,
            Marshal.SizeOf(myRequest),
            buffer,
            buffer.Length,
            ref pBytesReturned,
            IntPtr.Zero);

         if (!bOk) { throw new Exception("DeviceIoControl failed"); }
         if (!(pBytesReturned == buffer.Length)) { throw new Exception("DeviceIoControl failed"); }
         if (!buffer.SequenceEqual(EepromReadDevIoCtl(offset, buffer.Length))) { throw new Exception("Verify failed"); }

      }


      // Write a single byte to ram location specified.
      // To download firmware, see FirmwareDownloadDevIoCtl 
      // Typical usage:
      //    IntRamWrite(0xE600, 1); // write a 1 to address 0xE600 to enter reset.
      //    IntRamWrite(0xE600, 0); // write a 1 to address 0xE600 to enter reset.
      void IntRamWriteByteDevIoCtl(UInt16 offset, byte data)
      {

         EzUsbSys.VENDOR_REQUEST_IN myRequest = new EzUsbSys.VENDOR_REQUEST_IN(
            EzUsbSys.VendAxCmd.ANCHOR_LOAD_INTERNAL,
            offset, 
            0x00,
            0x01, // length of data.
            EzUsbSys.Direction.HostToDevice,
            data); 

         Debug.Assert(hDevice != null);

         int pBytesReturned = 0;

         bool bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_Ezusb_VENDOR_REQUEST,
            ref myRequest,
            Marshal.SizeOf(myRequest),
            IntPtr.Zero,
            0,
            ref pBytesReturned,
            IntPtr.Zero);

         if (!bOk) { throw new Exception("DeviceIoControl failed"); }
         if (!(pBytesReturned == 0)) { throw new Exception("DeviceIoControl failed"); }

      } // IntRamWriteByteDevIoCtl

      
      // Read internal memory. Used to determine if Vend_Ax is downloaded.
      byte[] IntRamRead(int offset, int qty)
      {
         byte data=0;

         EzUsbSys.VENDOR_REQUEST_IN myRequest = new EzUsbSys.VENDOR_REQUEST_IN(
            EzUsbSys.VendAxCmd.ANCHOR_LOAD_INTERNAL,
            offset, 
            0x00,
            qty, // length of data.
            EzUsbSys.Direction.DeviceToHost,
            data); 

         Debug.Assert(hDevice != null);

         byte[] buffer = new byte[qty];

         int pBytesReturned = 0;

         bool bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_Ezusb_VENDOR_REQUEST,
            ref myRequest,
            Marshal.SizeOf(myRequest),
            buffer,
            buffer.Length,
            ref pBytesReturned,
            IntPtr.Zero);

         if (!bOk) { throw new Exception("DeviceIoControl failed"); }
         Debug.Assert(pBytesReturned == qty);

         return buffer;

      }

      // Hold CPU in reset.
      void SendOpReset()
      {
         IntRamWriteByteDevIoCtl(0xE600, 1); // write a 1 to address 0xE600 to enter reset.
         return;
      }

      // Let CPU run.
      void SendOpRun()
      {
         IntRamWriteByteDevIoCtl(0xE600, 0); // write a 1 to address 0xE600 to enter reset.
         return;
      }

      // Download firmware.
      // See downloadVendAx for usage.
      // Typical usage:
      //    SendOpReset();
      //    FirmwareDownload(VendAxCode);
      //    SendOpRun();
      void FirmwareDownloadDevIoCtl( byte [] buffer )
      {
         Debug.Assert(buffer.Length < 7 * 1024); // The driver spec says the size must be less than 7 kB.

         EzUsbSys.ANCHOR_DOWNLOAD_CONTROL myRequest = new EzUsbSys.ANCHOR_DOWNLOAD_CONTROL(0);
         Debug.Assert(hDevice != null);

         int pBytesReturned = 0;
         bool bOk;

         bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_EZUSB_ANCHOR_DOWNLOAD,
            ref myRequest,
            Marshal.SizeOf(myRequest),
            buffer,
            buffer.Length,
            ref pBytesReturned,
            IntPtr.Zero);
      
         if (!bOk) { throw new Exception("DeviceIoControl failed"); }
         Debug.Assert(pBytesReturned == 0);

      }
      

      // Find all un-opened devices.
      // Check the ezusb driver, and the TsUsb.sys driver, for a list of available devices.
      // Typically, there would be a qty of 0 or 1. Rarely, there would be more.
      // It's assumed that there would be few devices.
      static string[] GetUnopenedDevices()
      {
         string [] driverList = new string[]{ "Tsusb2", "ezusb" };
         List<string> deviceList = new List<string>();

         foreach (string driverName in driverList)
         {
            // I didn't test this fully with the ezusb driver.
            // The Tsusb driver used 'funny' characters and didn't seem to work with character '\'.
            // I might be able to use characters > '\' but didn't think this would be very common.
            for (char c = '0'; c < '\\'; c++)
            {
               string deviceName = @"\\.\" + driverName + "-" + c;

               Microsoft.Win32.SafeHandles.SafeFileHandle hOut = CreateFile(
                  deviceName,
                  FILE_GENERIC_READ | FILE_GENERIC_WRITE,
                  0,
                  IntPtr.Zero,
                  FILE_OPEN_EXISTING,
                  0,
                  IntPtr.Zero);

               if (hOut.IsInvalid)
               {
                  hOut.Close();
                  continue;
               }
               else
               {
                  deviceList.Add(deviceName);
                  hOut.Close();
                  // if using SafeFileHandle, don't call CloseHandle(hOut);
                  // Why? hOut was getting closed 'safely' yet again which resulted in odd behavior.
               }
            } // for each device letter
         } // for each device driver


         return deviceList.ToArray();

      }

      // Download a .IIC file.
      // Prompt for the file to download.
      private void IicDownload_Click(object sender, EventArgs e)
      {
         try
         {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.FileName = iicFilename;
            dlg.Title = "Select .IIC file to load into EEPROM";
            dlg.CheckFileExists = true;
            dlg.Filter = "IIC files (*.iic)|*.iic|All files (*.*)|*.*";
            DialogResult result = dlg.ShowDialog();

            if (result != DialogResult.OK)
            {
               return;
            }

            iicFilename = dlg.FileName;

            byte [] buffer = System.IO.File.ReadAllBytes(iicFilename);

            const int packetSize = 0x100;

            ProgressInit( buffer.Length, "Writing EEPROM");

            Open();

            for ( int offset=0, remaining=buffer.Length; remaining>0; )
            {
               int length = Math.Min( packetSize, remaining );

               byte [] x = new byte[length];

               ProgressUpdate(buffer.Length - remaining);

               // extract smaller buffer from large buffer
               Array.Copy( buffer, offset, x, 0, length );

               EepromWriteDevIoCtl( offset, x );

               remaining -= length;
               offset += length;


            }

            Debug.Assert(buffer.SequenceEqual(EepromRead( buffer.Length)));

            hDevice.Close();

            ProgressDone( string.Format( "{0} bytes downloaded and verified", buffer.Length ));
         }
         catch (Exception ex)
         {
            ProgressDone( string.Format( "Download Error" ));
         }
      }

      private void btnEraseEeprom_Click(object sender, EventArgs e)
      {
         EraseEe( false );
      }

      private void btnDeviceToIicFile_Click(object sender, EventArgs e)
      {
         int size = 0;

         try
         {
            string s = cmboDeviceToIicFileSize.Text;
            s = s.Split(' ')[0];

            size = ( s.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) ? 
               Int32.Parse(s.Substring(2), System.Globalization.NumberStyles.HexNumber):
               Int32.Parse(s);

            size = Math.Min(size, EepromSizeBytes);
         }
         catch
         {
            MessageBox.Show("Invalid file size");
            return; // TODO:
         }

         SaveFileDialog dlg = new SaveFileDialog();
         dlg.Title = "Select .IIC file to write from EEPROM";
         dlg.RestoreDirectory = true;
         dlg.FileName = iicFilename;
         dlg.Filter = "IIC files (*.iic)|*.iic|All files (*.*)|*.*";
         DialogResult result = dlg.ShowDialog();

         if (result != DialogResult.OK)
         {
            return;
         }

         iicFilename = dlg.FileName;

         byte [] buffer = new byte[size];

         Open();

         ProgressInit(size, "Reading EEPROM");

         for ( int offset = 0; offset < size; offset += Math.Min( size, UsbMaxPacketSize))
         {
            ProgressUpdate(offset);

            byte[] x = EepromReadDevIoCtl(offset, Math.Min(size, UsbMaxPacketSize));

            x.CopyTo(buffer, offset);
         }
         
         hDevice.Close();

         ProgressDone( string.Format( "{0} bytes saved", size ) );

         System.IO.File.WriteAllBytes(iicFilename, buffer);

      }



      private void EraseEe( bool keepFirst8Bytes )
      {
         try
         {
            const int eraseSize = 0x100;
            const int eraseSizeTotal = EepromSizeBytes;

            byte[] buffer = new byte[eraseSize];
            for (int i = 0; i < buffer.Length; i++)
            {
               buffer[i] = 0xFF;
            }

            Open();

            ProgressInit(eraseSizeTotal, "Erasing EEPROM");

            for (int offset = 0; offset < eraseSizeTotal; offset += eraseSize)
            {
               ProgressUpdate(offset);
               EepromWriteDevIoCtl(offset == 0 && keepFirst8Bytes ? 8 : offset, buffer);
            }

            hDevice.Close();

            ProgressDone("EEPROM erased");
         }
         catch (Exception ex)
         {
            ProgressDone("EEPROM erase failed");
         }
      }

      private void btnEraseEeAfter8_Click(object sender, EventArgs e)
      {
         EraseEe( true );
      }



      private void ProgressInit(int maxArg, string txtArg)
      {
         // Initialize the progress bar on the statusbar for operations that might take a long time.
         toolStripStatusLabel1.Text = txtArg;
         toolStripStatusLabel1.Visible = true;
         toolStripProgressBar1.Maximum = maxArg; //
         toolStripProgressBar1.Visible = true;
      }

      private void ProgressUpdate(int offsetArg )
      {
         toolStripProgressBar1.Value = offsetArg;
         statusStrip1.Update();
      }

      private void ProgressDone( string txt )
      {
         toolStripProgressBar1.Visible = false;
         toolStripStatusLabel1.Text = txt;
      }
      
      private void cmboDeviceList_SelectedIndexChanged(object sender, EventArgs e)
      {
         // If there a multiple devices found, and the selection changes, disconnect the current device.
         deviceOnline = false;
      }

      private void btnVerifyIicFile_Click(object sender, EventArgs e)
      {
         OpenFileDialog dlg = new OpenFileDialog();
         dlg.FileName = iicFilename;
         dlg.Title = "Select .IIC file to compare with EEPROM";
         dlg.CheckFileExists = true;
         dlg.Filter = "IIC files (*.iic)|*.iic|All files (*.*)|*.*";
         DialogResult result = dlg.ShowDialog();

         if (result != DialogResult.OK)
         {
            return;
         }

         iicFilename = dlg.FileName;

         byte[] buffer = System.IO.File.ReadAllBytes(iicFilename);

         try
         {
            Open();
            if (!buffer.SequenceEqual(EepromRead(buffer.Length)))
            {
               throw new Exception();
            }
            hDevice.Close();
            ProgressDone("Verify OK");
         }
         catch
         {
            ProgressDone("Verify failed");
         }
      }


      private void MainForm_Load(object sender, EventArgs e)
      {
         //testIntelHexToByteArray();
         timer1.Start();
         cmboDeviceToIicFileSize.SelectedIndex = 0;
      } // btnVerifyIicFile_Click

      /*
      // Test/development code used to generate data to initialize the VendAxCode array.
      // It has one-time usage during development and isn't expected to be used unless the Vend_AX firmware should change.
      // This leaves a trail to re-create the data and is commented-out to reduce program size.
      void testIntelHexToByteArray()
      {
         // See http://en.wikipedia.org/wiki/.hex for .HEX record structure.
         // I'm assuming that the .hex file is simple, loads internal memory only.

         string[] hex = System.IO.File.ReadAllLines("vend_ax.hex");

         int maxAddress=0;

         // find max memory used.
         foreach (string record in hex )
         {
            Debug.Assert(record[0] == ':');

            byte recordType = byte.Parse(record.Substring(7, 2), System.Globalization.NumberStyles.HexNumber);
            if (recordType == 1)
            {
               break;
            }

            UInt16 recByteCount = UInt16.Parse(record.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
            UInt16 recAddress = UInt16.Parse(record.Substring(3, 4), System.Globalization.NumberStyles.HexNumber);

            Debug.Assert(recAddress < 0x2000); // If this fails, re-visit assumptions.

            byte checkSum = byte.Parse(record.Substring(9 + recByteCount * 2, 2), System.Globalization.NumberStyles.HexNumber);

            Debug.Assert(record.Length == 11 + recByteCount * 2);

            maxAddress = Math.Max( maxAddress, recAddress+recByteCount );

         }

         byte[] bin = new byte[maxAddress+1]; // allocate buffer to reconstitute .hex file into. +1 should result in an extra AA at the end.
         for ( int i=0; i<bin.Length; i++ ) { bin[i]=0xAA; } // Initialize buffer with 0xAA, just because the original Vend_Ax array did this.

         // For each record read from the .hex file, 
         foreach (string record in hex)
         {
            Debug.Assert(record[0] == ':');

            byte recordType = byte.Parse(record.Substring(7, 2), System.Globalization.NumberStyles.HexNumber);
            if (recordType == 1)
            {
               break;
            }

            UInt16 recByteCount = UInt16.Parse(record.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
            UInt16 recAddress = UInt16.Parse(record.Substring(3, 4), System.Globalization.NumberStyles.HexNumber);

            byte checkSum = byte.Parse(record.Substring(9 + recByteCount * 2, 2), System.Globalization.NumberStyles.HexNumber);
            // TODO: validate checksum.
            // In my tests, the firmware ran.

            Debug.Assert(record.Length == 11 + recByteCount * 2); // make sure the length is ok.

            // For each byte, represented as a 2-character hex number, store the byte in the binary buffer.
            for (int i = 0; i < recByteCount; i++)
            {
               byte b = byte.Parse(record.Substring(9 + i * 2, 2), System.Globalization.NumberStyles.HexNumber);
               bin[recAddress + i] = b;
            }
         } // foreach record in hex.

         // write to file
         // Create records of the form: 0x02, 0x07, 0xF3, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 

         // This resulting text will be used to initialize an array.
         System.IO.StreamWriter file = new System.IO.StreamWriter("vend_ax.txt");

         for (int i = 0; i < bin.Length; i++)
         {
            string s = string.Format( "0x{0:X02}, {1}", bin[i], i%10==9 ? "
" : "" );
            file.Write(s);
         }

         file.Close();

         return;
      }
      */


      private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
      {
         // Add a convenience link to the app to start the device manager in the control panel.
         System.Diagnostics.Process.Start("devmgmt.msc"); 
      }

      private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
      {
         // Add a convenience link to open the current working directoy.
         System.Diagnostics.Process.Start(System.IO.Directory.GetCurrentDirectory()); 
      }

   } // MainForm.
} // namespace CypressEepromUtility
// End of file

Revision: 20874
at November 28, 2009 23:42 by jimfred


Updated Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices; // for DllImport
using System.Diagnostics;
using System.Threading; // for Debug.Assert


namespace CypressEepromUtility
{
   public partial class MainForm : Form
   {
      #region Vend_AX firmware array.
      // This array was generated from C:\Cypress\USB\Examples\FX2LP\Vend_ax\Vend_Ax.hex.
      // The .hex was was reconstituted into a binary buffer and then written to a text file and its contents included here.
      // The code used to create the text file is testIntelHexToByteArray().
      // The AA bytes are gaps. 
      // The original VendAx array taken from Vend_Ax.h in the EzMr project caused random Windows driver errors, crashes and PC lock-ups.

      public static byte[] VendAxCode = new byte[]
      {
         #region fwCode
         0x02, 0x07, 0xF3, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0x02, 0x0D, 0x60, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x02, 0x08, 0x00, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0x02, 0x08, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x90, 0xE6, 
         0xB9, 0xE0, 0x24, 0x5E, 0xB4, 0x0B, 0x00, 0x40, 0x03, 0x02, 
         0x03, 0x98, 0x90, 0x00, 0x9C, 0x75, 0xF0, 0x03, 0xA4, 0xC5, 
         0x83, 0x25, 0xF0, 0xC5, 0x83, 0x73, 0x02, 0x01, 0x92, 0x02, 
         0x01, 0x92, 0x02, 0x01, 0x0D, 0x02, 0x00, 0xBD, 0x02, 0x00, 
         0xD7, 0x02, 0x00, 0xF3, 0x02, 0x01, 0x3C, 0x02, 0x01, 0x8C, 
         0x02, 0x01, 0x16, 0x02, 0x01, 0x29, 0x02, 0x01, 0x62, 0x90, 
         0xE7, 0x40, 0xE5, 0x19, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 
         0x90, 0xE6, 0x8B, 0x04, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 
         0x80, 0xF0, 0x02, 0x03, 0x98, 0x90, 0xE6, 0x0A, 0xE0, 0x90, 
         0xE7, 0x40, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 
         0x8B, 0x04, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 
         0x02, 0x03, 0x98, 0x90, 0xE7, 0x40, 0x74, 0x0F, 0xF0, 0xE4, 
         0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 0x90, 
         0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 0x02, 0x03, 0x98, 0x90, 
         0xE6, 0xBA, 0xE0, 0xF5, 0x17, 0x02, 0x03, 0x98, 0x90, 0xE6, 
         0x7A, 0xE0, 0x54, 0xFE, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 
         0x90, 0xE6, 0x8B, 0xF0, 0x02, 0x03, 0x98, 0x90, 0xE6, 0x7A, 
         0xE0, 0x44, 0x01, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 
         0xE6, 0x8B, 0xF0, 0x02, 0x03, 0x98, 0x90, 0xE7, 0x40, 0x74, 
         0x07, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 
         0x04, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 0x7F, 
         0xE8, 0x7E, 0x03, 0x12, 0x07, 0xAD, 0xD2, 0x04, 0x12, 0x0B, 
         0x87, 0x02, 0x03, 0x98, 0x90, 0xE6, 0xB5, 0xE0, 0x54, 0xFE, 
         0xF0, 0x90, 0xE6, 0xBF, 0xE0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 
         0xE6, 0xBE, 0xE0, 0x90, 0xE6, 0x8B, 0xF0, 0x90, 0xE6, 0xBB, 
         0xE0, 0x90, 0xE6, 0xB3, 0xF0, 0x90, 0xE6, 0xBA, 0xE0, 0x90, 
         0xE6, 0xB4, 0xF0, 0x02, 0x03, 0x98, 0x75, 0x19, 0x01, 0x43, 
         0x17, 0x01, 0x90, 0xE6, 0xBA, 0xE0, 0x75, 0x31, 0x00, 0xF5, 
         0x32, 0xA3, 0xE0, 0xFE, 0xE4, 0xEE, 0x42, 0x31, 0x90, 0xE6, 
         0xBE, 0xE0, 0x75, 0x33, 0x00, 0xF5, 0x34, 0xA3, 0xE0, 0xFE, 
         0xE4, 0xEE, 0x42, 0x33, 0x90, 0xE6, 0xB8, 0xE0, 0x64, 0xC0, 
         0x60, 0x03, 0x02, 0x02, 0x82, 0xE5, 0x34, 0x45, 0x33, 0x70, 
         0x03, 0x02, 0x03, 0x98, 0x90, 0xE6, 0xA0, 0xE0, 0x20, 0xE1, 
         0xF9, 0xC3, 0xE5, 0x34, 0x94, 0x40, 0xE5, 0x33, 0x94, 0x00, 
         0x50, 0x08, 0x85, 0x33, 0x35, 0x85, 0x34, 0x36, 0x80, 0x06, 
         0x75, 0x35, 0x00, 0x75, 0x36, 0x40, 0x90, 0xE6, 0xB9, 0xE0, 
         0xB4, 0xA3, 0x35, 0xE4, 0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 
         0x38, 0x95, 0x36, 0xE5, 0x37, 0x95, 0x35, 0x50, 0x60, 0xE5, 
         0x32, 0x25, 0x38, 0xF5, 0x82, 0xE5, 0x31, 0x35, 0x37, 0xF5, 
         0x83, 0xE0, 0xFF, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 
         0x34, 0xE7, 0xF5, 0x83, 0xEF, 0xF0, 0x05, 0x38, 0xE5, 0x38, 
         0x70, 0x02, 0x05, 0x37, 0x80, 0xD0, 0xE4, 0xF5, 0x37, 0xF5, 
         0x38, 0xC3, 0xE5, 0x38, 0x95, 0x36, 0xE5, 0x37, 0x95, 0x35, 
         0x50, 0x18, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34, 
         0xE7, 0xF5, 0x83, 0x74, 0xCD, 0xF0, 0x05, 0x38, 0xE5, 0x38, 
         0x70, 0x02, 0x05, 0x37, 0x80, 0xDD, 0xAD, 0x36, 0x7A, 0xE7, 
         0x79, 0x40, 0x7E, 0xE7, 0x7F, 0x40, 0xAB, 0x07, 0xAF, 0x32, 
         0xAE, 0x31, 0x12, 0x08, 0xB8, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 
         0x90, 0xE6, 0x8B, 0xE5, 0x36, 0xF0, 0x25, 0x32, 0xF5, 0x32, 
         0xE5, 0x35, 0x35, 0x31, 0xF5, 0x31, 0xC3, 0xE5, 0x34, 0x95, 
         0x36, 0xF5, 0x34, 0xE5, 0x33, 0x95, 0x35, 0xF5, 0x33, 0x02, 
         0x01, 0xBD, 0x90, 0xE6, 0xB8, 0xE0, 0x64, 0x40, 0x60, 0x03, 
         0x02, 0x03, 0x98, 0xE5, 0x1A, 0x70, 0x05, 0x12, 0x09, 0x67, 
         0x8F, 0x1A, 0xE5, 0x34, 0x45, 0x33, 0x70, 0x03, 0x02, 0x03, 
         0x98, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0xF0, 
         0x90, 0xE6, 0xA0, 0xE0, 0x20, 0xE1, 0xF9, 0x90, 0xE6, 0x8B, 
         0xE0, 0x75, 0x35, 0x00, 0xF5, 0x36, 0x90, 0xE6, 0xB9, 0xE0, 
         0xB4, 0xA3, 0x38, 0xE4, 0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 
         0x38, 0x95, 0x36, 0xE5, 0x37, 0x95, 0x35, 0x40, 0x03, 0x02, 
         0x03, 0x7C, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34, 
         0xE7, 0xF5, 0x83, 0xE0, 0xFF, 0xE5, 0x32, 0x25, 0x38, 0xF5, 
         0x82, 0xE5, 0x31, 0x35, 0x37, 0xF5, 0x83, 0xEF, 0xF0, 0x05, 
         0x38, 0xE5, 0x38, 0x70, 0x02, 0x05, 0x37, 0x80, 0xCD, 0xE4, 
         0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 0x38, 0x95, 0x36, 0xE5, 
         0x37, 0x95, 0x35, 0x50, 0x75, 0x85, 0x1A, 0x39, 0xE5, 0x1A, 
         0x64, 0x01, 0x60, 0x44, 0xE5, 0x32, 0x25, 0x38, 0xFF, 0xE5, 
         0x31, 0x35, 0x37, 0xFE, 0xE5, 0x1A, 0x24, 0xFF, 0xFD, 0xE4, 
         0x34, 0xFF, 0x5E, 0xFE, 0xEF, 0x5D, 0x4E, 0x60, 0x10, 0xE5, 
         0x32, 0x25, 0x38, 0xFF, 0xE5, 0x1A, 0x14, 0x5F, 0xFF, 0xC3, 
         0xE5, 0x1A, 0x9F, 0xF5, 0x39, 0xC3, 0xE5, 0x36, 0x95, 0x38, 
         0xFF, 0xE5, 0x35, 0x95, 0x37, 0xFE, 0xC3, 0xEF, 0x95, 0x39, 
         0xEE, 0x94, 0x00, 0x50, 0x07, 0xC3, 0xE5, 0x36, 0x95, 0x38, 
         0xF5, 0x39, 0xE5, 0x32, 0x25, 0x38, 0xFF, 0xE5, 0x31, 0x35, 
         0x37, 0xFE, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34, 
         0xE7, 0xAD, 0x82, 0xFC, 0xAB, 0x39, 0x12, 0x0A, 0x9C, 0xE5, 
         0x39, 0x25, 0x38, 0xF5, 0x38, 0xE4, 0x35, 0x37, 0xF5, 0x37, 
         0x80, 0x80, 0xE5, 0x36, 0x25, 0x32, 0xF5, 0x32, 0xE5, 0x35, 
         0x35, 0x31, 0xF5, 0x31, 0xC3, 0xE5, 0x34, 0x95, 0x36, 0xF5, 
         0x34, 0xE5, 0x33, 0x95, 0x35, 0xF5, 0x33, 0x02, 0x02, 0x96, 
         0xC3, 0x22, 0x90, 0xE6, 0xB9, 0xE0, 0x70, 0x03, 0x02, 0x04, 
         0x85, 0x14, 0x70, 0x03, 0x02, 0x05, 0x2E, 0x24, 0xFE, 0x70, 
         0x03, 0x02, 0x05, 0xC4, 0x24, 0xFB, 0x70, 0x03, 0x02, 0x04, 
         0x7F, 0x14, 0x70, 0x03, 0x02, 0x04, 0x79, 0x14, 0x70, 0x03, 
         0x02, 0x04, 0x6D, 0x14, 0x70, 0x03, 0x02, 0x04, 0x73, 0x24, 
         0x05, 0x60, 0x03, 0x02, 0x06, 0x39, 0x12, 0x0D, 0x68, 0x40, 
         0x03, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xBB, 0xE0, 0x24, 0xFE, 
         0x60, 0x3B, 0x14, 0x60, 0x56, 0x24, 0xFD, 0x60, 0x16, 0x14, 
         0x60, 0x40, 0x24, 0x06, 0x70, 0x75, 0xE5, 0x0A, 0x90, 0xE6, 
         0xB3, 0xF0, 0xE5, 0x0B, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x06, 
         0x45, 0x12, 0x0D, 0x33, 0x50, 0x0F, 0xE5, 0x12, 0x90, 0xE6, 
         0xB3, 0xF0, 0xE5, 0x13, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x02, 0x06, 
         0x45, 0xE5, 0x0C, 0x90, 0xE6, 0xB3, 0xF0, 0xE5, 0x0D, 0x90, 
         0xE6, 0xB4, 0xF0, 0x02, 0x06, 0x45, 0xE5, 0x0E, 0x90, 0xE6, 
         0xB3, 0xF0, 0xE5, 0x0F, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xBA, 0xE0, 0xFF, 0x12, 0x0B, 0xE2, 0xAA, 
         0x06, 0xA9, 0x07, 0x7B, 0x01, 0xEA, 0x49, 0x4B, 0x60, 0x0D, 
         0xEE, 0x90, 0xE6, 0xB3, 0xF0, 0xEF, 0x90, 0xE6, 0xB4, 0xF0, 
         0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 
         0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 
         0x02, 0x06, 0x45, 0x12, 0x0C, 0xF1, 0x02, 0x06, 0x45, 0x12, 
         0x0D, 0x50, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x48, 0x02, 0x06, 
         0x45, 0x12, 0x0C, 0xDF, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x6A, 
         0x40, 0x03, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xB8, 0xE0, 0x24, 
         0x7F, 0x60, 0x2B, 0x14, 0x60, 0x3C, 0x24, 0x02, 0x60, 0x03, 
         0x02, 0x05, 0x24, 0xA2, 0x00, 0xE4, 0x33, 0xFF, 0x25, 0xE0, 
         0xFF, 0xA2, 0x02, 0xE4, 0x33, 0x4F, 0x90, 0xE7, 0x40, 0xF0, 
         0xE4, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 
         0x74, 0x02, 0xF0, 0x02, 0x06, 0x45, 0xE4, 0x90, 0xE7, 0x40, 
         0xF0, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 
         0x74, 0x02, 0xF0, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xBC, 0xE0, 
         0x54, 0x7E, 0xFF, 0x7E, 0x00, 0xE0, 0xD3, 0x94, 0x80, 0x40, 
         0x06, 0x7C, 0x00, 0x7D, 0x01, 0x80, 0x04, 0x7C, 0x00, 0x7D, 
         0x00, 0xEC, 0x4E, 0xFE, 0xED, 0x4F, 0x24, 0x3E, 0xF5, 0x82, 
         0x74, 0x0D, 0x3E, 0xF5, 0x83, 0xE4, 0x93, 0xFF, 0x33, 0x95, 
         0xE0, 0xFE, 0xEF, 0x24, 0xA1, 0xFF, 0xEE, 0x34, 0xE6, 0x8F, 
         0x82, 0xF5, 0x83, 0xE0, 0x54, 0x01, 0x90, 0xE7, 0x40, 0xF0, 
         0xE4, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 
         0x74, 0x02, 0xF0, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 
         0x44, 0x01, 0xF0, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x6C, 0x40, 
         0x03, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xB8, 0xE0, 0x24, 0xFE, 
         0x60, 0x1D, 0x24, 0x02, 0x60, 0x03, 0x02, 0x06, 0x45, 0x90, 
         0xE6, 0xBA, 0xE0, 0xB4, 0x01, 0x05, 0xC2, 0x00, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xBA, 0xE0, 0x70, 0x59, 0x90, 0xE6, 0xBC, 
         0xE0, 0x54, 0x7E, 0xFF, 0x7E, 0x00, 0xE0, 0xD3, 0x94, 0x80, 
         0x40, 0x06, 0x7C, 0x00, 0x7D, 0x01, 0x80, 0x04, 0x7C, 0x00, 
         0x7D, 0x00, 0xEC, 0x4E, 0xFE, 0xED, 0x4F, 0x24, 0x3E, 0xF5, 
         0x82, 0x74, 0x0D, 0x3E, 0xF5, 0x83, 0xE4, 0x93, 0xFF, 0x33, 
         0x95, 0xE0, 0xFE, 0xEF, 0x24, 0xA1, 0xFF, 0xEE, 0x34, 0xE6, 
         0x8F, 0x82, 0xF5, 0x83, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0xE6, 
         0xBC, 0xE0, 0x54, 0x80, 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 
         0xFF, 0xE0, 0x54, 0x0F, 0x2F, 0x90, 0xE6, 0x83, 0xF0, 0xE0, 
         0x44, 0x20, 0xF0, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 
         0x44, 0x01, 0xF0, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x6E, 0x50, 
         0x7C, 0x90, 0xE6, 0xB8, 0xE0, 0x24, 0xFE, 0x60, 0x20, 0x24, 
         0x02, 0x70, 0x5B, 0x90, 0xE6, 0xBA, 0xE0, 0xB4, 0x01, 0x04, 
         0xD2, 0x00, 0x80, 0x65, 0x90, 0xE6, 0xBA, 0xE0, 0x64, 0x02, 
         0x60, 0x5D, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x80, 
         0x54, 0x90, 0xE6, 0xBC, 0xE0, 0x54, 0x7E, 0xFF, 0x7E, 0x00, 
         0xE0, 0xD3, 0x94, 0x80, 0x40, 0x06, 0x7C, 0x00, 0x7D, 0x01, 
         0x80, 0x04, 0x7C, 0x00, 0x7D, 0x00, 0xEC, 0x4E, 0xFE, 0xED, 
         0x4F, 0x24, 0x3E, 0xF5, 0x82, 0x74, 0x0D, 0x3E, 0xF5, 0x83, 
         0xE4, 0x93, 0xFF, 0x33, 0x95, 0xE0, 0xFE, 0xEF, 0x24, 0xA1, 
         0xFF, 0xEE, 0x34, 0xE6, 0x8F, 0x82, 0xF5, 0x83, 0xE0, 0x44, 
         0x01, 0xF0, 0x80, 0x15, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 
         0xF0, 0x80, 0x0C, 0x12, 0x00, 0x80, 0x50, 0x07, 0x90, 0xE6, 
         0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 
         0x80, 0xF0, 0x22, 0xE4, 0xF5, 0x2C, 0xF5, 0x2B, 0xF5, 0x2A, 
         0xF5, 0x29, 0xC2, 0x03, 0xC2, 0x00, 0xC2, 0x02, 0xC2, 0x01, 
         0x12, 0x0C, 0x6C, 0x7E, 0x0A, 0x7F, 0x00, 0x8E, 0x0A, 0x8F, 
         0x0B, 0x75, 0x12, 0x0A, 0x75, 0x13, 0x12, 0x75, 0x08, 0x0A, 
         0x75, 0x09, 0x1C, 0x75, 0x10, 0x0A, 0x75, 0x11, 0x4A, 0x75, 
         0x14, 0x0A, 0x75, 0x15, 0x78, 0xEE, 0x54, 0xC0, 0x70, 0x03, 
         0x02, 0x07, 0x52, 0x75, 0x2D, 0x00, 0x75, 0x2E, 0x80, 0x8E, 
         0x2F, 0x8F, 0x30, 0xC3, 0x74, 0x9A, 0x9F, 0xFF, 0x74, 0x0A, 
         0x9E, 0xCF, 0x24, 0x02, 0xCF, 0x34, 0x00, 0xFE, 0xE4, 0x8F, 
         0x28, 0x8E, 0x27, 0xF5, 0x26, 0xF5, 0x25, 0xF5, 0x24, 0xF5, 
         0x23, 0xF5, 0x22, 0xF5, 0x21, 0xAF, 0x28, 0xAE, 0x27, 0xAD, 
         0x26, 0xAC, 0x25, 0xAB, 0x24, 0xAA, 0x23, 0xA9, 0x22, 0xA8, 
         0x21, 0xC3, 0x12, 0x0D, 0x03, 0x50, 0x37, 0xE5, 0x30, 0x25, 
         0x24, 0xF5, 0x82, 0xE5, 0x2F, 0x35, 0x23, 0xF5, 0x83, 0xE0, 
         0xFF, 0xE5, 0x2E, 0x25, 0x24, 0xF5, 0x82, 0xE5, 0x2D, 0x35, 
         0x23, 0xF5, 0x83, 0xEF, 0xF0, 0xE4, 0xFA, 0xF9, 0xF8, 0xE5, 
         0x24, 0x24, 0x01, 0xF5, 0x24, 0xEA, 0x35, 0x23, 0xF5, 0x23, 
         0xE9, 0x35, 0x22, 0xF5, 0x22, 0xE8, 0x35, 0x21, 0xF5, 0x21, 
         0x80, 0xB3, 0x85, 0x2D, 0x0A, 0x85, 0x2E, 0x0B, 0x74, 0x00, 
         0x24, 0x80, 0xFF, 0x74, 0x0A, 0x34, 0xFF, 0xFE, 0xC3, 0xE5, 
         0x13, 0x9F, 0xF5, 0x13, 0xE5, 0x12, 0x9E, 0xF5, 0x12, 0xC3, 
         0xE5, 0x0D, 0x9F, 0xF5, 0x0D, 0xE5, 0x0C, 0x9E, 0xF5, 0x0C, 
         0xC3, 0xE5, 0x0F, 0x9F, 0xF5, 0x0F, 0xE5, 0x0E, 0x9E, 0xF5, 
         0x0E, 0xC3, 0xE5, 0x09, 0x9F, 0xF5, 0x09, 0xE5, 0x08, 0x9E, 
         0xF5, 0x08, 0xC3, 0xE5, 0x11, 0x9F, 0xF5, 0x11, 0xE5, 0x10, 
         0x9E, 0xF5, 0x10, 0xC3, 0xE5, 0x15, 0x9F, 0xF5, 0x15, 0xE5, 
         0x14, 0x9E, 0xF5, 0x14, 0xD2, 0xE8, 0x43, 0xD8, 0x20, 0x90, 
         0xE6, 0x68, 0xE0, 0x44, 0x09, 0xF0, 0x90, 0xE6, 0x5C, 0xE0, 
         0x44, 0x3D, 0xF0, 0xD2, 0xAF, 0x90, 0xE6, 0x80, 0xE0, 0x54, 
         0xF7, 0xF0, 0x53, 0x8E, 0xF8, 0xC2, 0x03, 0x12, 0x07, 0xFF, 
         0x30, 0x01, 0x05, 0x12, 0x03, 0x9A, 0xC2, 0x01, 0x30, 0x03, 
         0xF2, 0x12, 0x0D, 0x64, 0x50, 0xED, 0xC2, 0x03, 0x12, 0x0C, 
         0x0D, 0x20, 0x00, 0x16, 0x90, 0xE6, 0x82, 0xE0, 0x30, 0xE7, 
         0x04, 0xE0, 0x20, 0xE1, 0xEF, 0x90, 0xE6, 0x82, 0xE0, 0x30, 
         0xE6, 0x04, 0xE0, 0x20, 0xE0, 0xE4, 0x12, 0x0B, 0xB6, 0x12, 
         0x0D, 0x66, 0x80, 0xC7, 0x22, 0x8E, 0x3A, 0x8F, 0x3B, 0x90, 
         0xE6, 0x00, 0xE0, 0x54, 0x18, 0x70, 0x12, 0xE5, 0x3B, 0x24, 
         0x01, 0xFF, 0xE4, 0x35, 0x3A, 0xC3, 0x13, 0xF5, 0x3A, 0xEF, 
         0x13, 0xF5, 0x3B, 0x80, 0x15, 0x90, 0xE6, 0x00, 0xE0, 0x54, 
         0x18, 0xFF, 0xBF, 0x10, 0x0B, 0xE5, 0x3B, 0x25, 0xE0, 0xF5, 
         0x3B, 0xE5, 0x3A, 0x33, 0xF5, 0x3A, 0xE5, 0x3B, 0x15, 0x3B, 
         0xAE, 0x3A, 0x70, 0x02, 0x15, 0x3A, 0x4E, 0x60, 0x05, 0x12, 
         0x0C, 0x21, 0x80, 0xEE, 0x22, 0x78, 0x7F, 0xE4, 0xF6, 0xD8, 
         0xFD, 0x75, 0x81, 0x41, 0x02, 0x06, 0x4D, 0x22, 0x02, 0x0C, 
         0x32, 0x00, 0x02, 0x0C, 0xB3, 0x00, 0x02, 0x0C, 0x9D, 0x00, 
         0x02, 0x0C, 0x85, 0x00, 0x02, 0x0B, 0x19, 0x00, 0x02, 0x0B, 
         0x50, 0x00, 0x02, 0x09, 0xFF, 0x00, 0x02, 0x0D, 0x70, 0x00, 
         0x02, 0x0D, 0x71, 0x00, 0x02, 0x0D, 0x72, 0x00, 0x02, 0x0D, 
         0x73, 0x00, 0x02, 0x0D, 0x74, 0x00, 0x02, 0x0D, 0x75, 0x00, 
         0x02, 0x0D, 0x76, 0x00, 0x02, 0x0D, 0x77, 0x00, 0x02, 0x0D, 
         0x78, 0x00, 0x02, 0x0D, 0x79, 0x00, 0x02, 0x0D, 0x70, 0x00, 
         0x02, 0x0D, 0x7A, 0x00, 0x02, 0x0D, 0x7B, 0x00, 0x02, 0x0D, 
         0x7C, 0x00, 0x02, 0x0D, 0x7D, 0x00, 0x02, 0x0D, 0x7E, 0x00, 
         0x02, 0x0D, 0x7F, 0x00, 0x02, 0x0D, 0x80, 0x00, 0x02, 0x0D, 
         0x70, 0x00, 0x02, 0x0D, 0x70, 0x00, 0x02, 0x0D, 0x70, 0x00, 
         0x02, 0x0D, 0x81, 0x00, 0x02, 0x0D, 0x82, 0x00, 0x02, 0x0D, 
         0x83, 0x00, 0x02, 0x0D, 0x84, 0x00, 0x02, 0x0D, 0x85, 0x00, 
         0x02, 0x0D, 0x86, 0x00, 0x02, 0x0D, 0x87, 0x00, 0x02, 0x0D, 
         0x88, 0x00, 0x02, 0x0D, 0x89, 0x00, 0x02, 0x0D, 0x8A, 0x00, 
         0x02, 0x0D, 0x8B, 0x00, 0x02, 0x0D, 0x8C, 0x00, 0x02, 0x0D, 
         0x8D, 0x00, 0x02, 0x0D, 0x8E, 0x00, 0x02, 0x0D, 0x8F, 0x00, 
         0x02, 0x0D, 0x90, 0x00, 0x02, 0x0D, 0x91, 0x00, 0x02, 0x0D, 
         0x92, 0x00, 0x8E, 0x3C, 0x8F, 0x3D, 0x8D, 0x3E, 0x8A, 0x3F, 
         0x8B, 0x40, 0x12, 0x0D, 0x58, 0x12, 0x0D, 0x24, 0x12, 0x0C, 
         0xC9, 0x50, 0x01, 0x22, 0xE5, 0x19, 0x60, 0x0C, 0xE5, 0x3C, 
         0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0C, 0xC9, 0x50, 0x01, 0x22, 
         0xE5, 0x3D, 0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0C, 0xC9, 0x50, 
         0x01, 0x22, 0x90, 0xE6, 0x78, 0x74, 0x80, 0xF0, 0xE5, 0x17, 
         0x25, 0xE0, 0x44, 0x01, 0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0D, 
         0x14, 0x50, 0x01, 0x22, 0x90, 0xE6, 0x79, 0xE0, 0xF5, 0x41, 
         0x12, 0x0D, 0x14, 0x50, 0x01, 0x22, 0xE4, 0xF5, 0x41, 0xE5, 
         0x3E, 0x14, 0xFF, 0xE5, 0x41, 0xC3, 0x9F, 0x50, 0x1C, 0x90, 
         0xE6, 0x79, 0xE0, 0xFF, 0xE5, 0x40, 0x25, 0x41, 0xF5, 0x82, 
         0xE4, 0x35, 0x3F, 0xF5, 0x83, 0xEF, 0xF0, 0x12, 0x0D, 0x14, 
         0x50, 0x01, 0x22, 0x05, 0x41, 0x80, 0xDA, 0x90, 0xE6, 0x78, 
         0x74, 0x20, 0xF0, 0x12, 0x0D, 0x14, 0x50, 0x01, 0x22, 0x90, 
         0xE6, 0x79, 0xE0, 0xFF, 0xE5, 0x40, 0x25, 0x41, 0xF5, 0x82, 
         0xE4, 0x35, 0x3F, 0xF5, 0x83, 0xEF, 0xF0, 0x12, 0x0D, 0x14, 
         0x50, 0x01, 0x22, 0x90, 0xE6, 0x78, 0x74, 0x40, 0xF0, 0x90, 
         0xE6, 0x79, 0xE0, 0xF5, 0x41, 0xC3, 0x22, 0xE5, 0x19, 0x70, 
         0x03, 0x7F, 0x01, 0x22, 0x7A, 0x10, 0x7B, 0x40, 0x7D, 0x40, 
         0xE4, 0xFF, 0xFE, 0x12, 0x08, 0xB8, 0xE4, 0xF5, 0x3A, 0x74, 
         0x00, 0x25, 0x3A, 0xF5, 0x82, 0xE4, 0x34, 0x10, 0xF5, 0x83, 
         0xE5, 0x3A, 0xF0, 0x05, 0x3A, 0xE5, 0x3A, 0xB4, 0x40, 0xEB, 
         0x7C, 0x10, 0x7D, 0x00, 0x7B, 0x40, 0xE4, 0xFF, 0xFE, 0x12, 
         0x0A, 0x9C, 0xE4, 0xF5, 0x3A, 0xE5, 0x3A, 0xF4, 0xFF, 0x74, 
         0x00, 0x25, 0x3A, 0xF5, 0x82, 0xE4, 0x34, 0x10, 0xF5, 0x83, 
         0xEF, 0xF0, 0x05, 0x3A, 0xE5, 0x3A, 0xB4, 0x40, 0xE8, 0x7A, 
         0x10, 0x7B, 0x00, 0x7D, 0x40, 0xE4, 0xFF, 0xFE, 0x12, 0x08, 
         0xB8, 0x90, 0x10, 0x00, 0xE0, 0xF5, 0x3A, 0xE5, 0x3A, 0x30, 
         0xE0, 0x05, 0x75, 0x3B, 0x01, 0x80, 0x08, 0x63, 0x3A, 0x3F, 
         0x05, 0x3A, 0x85, 0x3A, 0x3B, 0xE4, 0xF5, 0x3A, 0xE5, 0x3A, 
         0xC3, 0x94, 0x40, 0x50, 0x15, 0xAF, 0x3A, 0x7E, 0x00, 0x7C, 
         0x10, 0x7D, 0x40, 0xAB, 0x3B, 0x12, 0x0A, 0x9C, 0xE5, 0x3B, 
         0x25, 0x3A, 0xF5, 0x3A, 0x80, 0xE4, 0xAF, 0x3B, 0x22, 0x32, 
         0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xB4, 0x04, 
         0x04, 0x10, 0x00, 0x00, 0x01, 0x02, 0x00, 0x01, 0x0A, 0x06, 
         0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x09, 0x02, 
         0x2E, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 
         0x00, 0x04, 0xFF, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 
         0x00, 0x02, 0x00, 0x07, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, 
         0x07, 0x05, 0x86, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x88, 
         0x02, 0x00, 0x02, 0x00, 0x09, 0x02, 0x2E, 0x00, 0x01, 0x01, 
         0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 0x00, 0x04, 0xFF, 0x00, 
         0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 
         0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x86, 0x02, 
         0x40, 0x00, 0x00, 0x07, 0x05, 0x88, 0x02, 0x40, 0x00, 0x00, 
         0x04, 0x03, 0x09, 0x04, 0x10, 0x03, 0x43, 0x00, 0x79, 0x00, 
         0x70, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 
         0x0E, 0x03, 0x45, 0x00, 0x5A, 0x00, 0x2D, 0x00, 0x55, 0x00, 
         0x53, 0x00, 0x42, 0x00, 0x00, 0x00, 0x8E, 0x3C, 0x8F, 0x3D, 
         0x8C, 0x3E, 0x8D, 0x3F, 0x8B, 0x40, 0xC2, 0x87, 0x43, 0xB2, 
         0x80, 0x12, 0x0D, 0x58, 0x12, 0x0D, 0x24, 0x12, 0x0C, 0xC9, 
         0x50, 0x04, 0xD2, 0x04, 0x80, 0x59, 0xE5, 0x19, 0x60, 0x0F, 
         0xE5, 0x3C, 0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0C, 0xC9, 0x50, 
         0x04, 0xD2, 0x04, 0x80, 0x46, 0xE5, 0x3D, 0x90, 0xE6, 0x79, 
         0xF0, 0x12, 0x0C, 0xC9, 0x50, 0x04, 0xD2, 0x04, 0x80, 0x37, 
         0xE4, 0xF5, 0x41, 0xE5, 0x41, 0xC3, 0x95, 0x40, 0x50, 0x21, 
         0x05, 0x3F, 0xE5, 0x3F, 0xAE, 0x3E, 0x70, 0x02, 0x05, 0x3E, 
         0x14, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x90, 0xE6, 0x79, 0xF0, 
         0x12, 0x0D, 0x14, 0x50, 0x04, 0xD2, 0x04, 0x80, 0x10, 0x05, 
         0x41, 0x80, 0xD8, 0x90, 0xE6, 0x78, 0xE0, 0x44, 0x40, 0xF0, 
         0x12, 0x0C, 0x51, 0xC2, 0x04, 0x53, 0xB2, 0x7F, 0xA2, 0x04, 
         0x22, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x90, 0xE6, 0x80, 
         0xE0, 0x30, 0xE7, 0x0E, 0x85, 0x08, 0x0C, 0x85, 0x09, 0x0D, 
         0x85, 0x10, 0x0E, 0x85, 0x11, 0x0F, 0x80, 0x0C, 0x85, 0x10, 
         0x0C, 0x85, 0x11, 0x0D, 0x85, 0x08, 0x0E, 0x85, 0x09, 0x0F, 
         0x53, 0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 0x10, 0xF0, 0xD0, 
         0x82, 0xD0, 0x83, 0xD0, 0xE0, 0x32, 0xC0, 0xE0, 0xC0, 0x83, 
         0xC0, 0x82, 0x90, 0xE6, 0x80, 0xE0, 0x30, 0xE7, 0x0E, 0x85, 
         0x08, 0x0C, 0x85, 0x09, 0x0D, 0x85, 0x10, 0x0E, 0x85, 0x11, 
         0x0F, 0x80, 0x0C, 0x85, 0x10, 0x0C, 0x85, 0x11, 0x0D, 0x85, 
         0x08, 0x0E, 0x85, 0x09, 0x0F, 0x53, 0x91, 0xEF, 0x90, 0xE6, 
         0x5D, 0x74, 0x20, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 
         0x32, 0x30, 0x04, 0x09, 0x90, 0xE6, 0x80, 0xE0, 0x44, 0x0A, 
         0xF0, 0x80, 0x07, 0x90, 0xE6, 0x80, 0xE0, 0x44, 0x08, 0xF0, 
         0x7F, 0xDC, 0x7E, 0x05, 0x12, 0x07, 0xAD, 0x90, 0xE6, 0x5D, 
         0x74, 0xFF, 0xF0, 0x90, 0xE6, 0x5F, 0xF0, 0x53, 0x91, 0xEF, 
         0x90, 0xE6, 0x80, 0xE0, 0x54, 0xF7, 0xF0, 0x22, 0x90, 0xE6, 
         0x82, 0xE0, 0x30, 0xE0, 0x04, 0xE0, 0x20, 0xE6, 0x0B, 0x90, 
         0xE6, 0x82, 0xE0, 0x30, 0xE1, 0x19, 0xE0, 0x30, 0xE7, 0x15, 
         0x90, 0xE6, 0x80, 0xE0, 0x44, 0x01, 0xF0, 0x7F, 0x14, 0x7E, 
         0x00, 0x12, 0x07, 0xAD, 0x90, 0xE6, 0x80, 0xE0, 0x54, 0xFE, 
         0xF0, 0x22, 0xA9, 0x07, 0xAE, 0x14, 0xAF, 0x15, 0x8F, 0x82, 
         0x8E, 0x83, 0xA3, 0xE0, 0x64, 0x03, 0x70, 0x17, 0xAD, 0x01, 
         0x19, 0xED, 0x70, 0x01, 0x22, 0x8F, 0x82, 0x8E, 0x83, 0xE0, 
         0x7C, 0x00, 0x2F, 0xFD, 0xEC, 0x3E, 0xFE, 0xAF, 0x05, 0x80, 
         0xDF, 0xE4, 0xFE, 0xFF, 0x22, 0x90, 0xE6, 0x82, 0xE0, 0x44, 
         0xC0, 0xF0, 0x90, 0xE6, 0x81, 0xF0, 0x43, 0x87, 0x01, 0x00, 
         0x00, 0x00, 0x00, 0x00, 0x22, 0x74, 0x00, 0xF5, 0x86, 0x90, 
         0xFD, 0xA5, 0x7C, 0x05, 0xA3, 0xE5, 0x82, 0x45, 0x83, 0x70, 
         0xF9, 0x22, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x90, 0xE6, 
         0xB5, 0xE0, 0x44, 0x01, 0xF0, 0xD2, 0x01, 0x53, 0x91, 0xEF, 
         0x90, 0xE6, 0x5D, 0x74, 0x01, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 
         0xD0, 0xE0, 0x32, 0x12, 0x0D, 0x58, 0x12, 0x0D, 0x24, 0x12, 
         0x0D, 0x14, 0x90, 0xE6, 0x78, 0xE0, 0x44, 0x40, 0xF0, 0x12, 
         0x0D, 0x58, 0x90, 0xE6, 0x78, 0xE0, 0x30, 0xE1, 0xE9, 0x22, 
         0xD2, 0x00, 0xE4, 0xF5, 0x1A, 0x90, 0xE6, 0x78, 0xE0, 0x54, 
         0x10, 0xFF, 0xC4, 0x54, 0x0F, 0x44, 0x50, 0xF5, 0x17, 0x13, 
         0xE4, 0x33, 0xF5, 0x19, 0x22, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 
         0x82, 0xD2, 0x03, 0x53, 0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 
         0x08, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 0x32, 0xC0, 
         0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x53, 0x91, 0xEF, 0x90, 0xE6, 
         0x5D, 0x74, 0x04, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 
         0x32, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x53, 0x91, 0xEF, 
         0x90, 0xE6, 0x5D, 0x74, 0x02, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 
         0xD0, 0xE0, 0x32, 0x90, 0xE6, 0x78, 0xE0, 0xFF, 0x30, 0xE0, 
         0xF8, 0xEF, 0x30, 0xE2, 0x02, 0xD3, 0x22, 0xEF, 0x20, 0xE1, 
         0x02, 0xD3, 0x22, 0xC3, 0x22, 0x90, 0xE7, 0x40, 0xE5, 0x18, 
         0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 
         0xF0, 0xD3, 0x22, 0x90, 0xE7, 0x40, 0xE5, 0x16, 0xF0, 0xE4, 
         0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 0xD3, 
         0x22, 0xEB, 0x9F, 0xF5, 0xF0, 0xEA, 0x9E, 0x42, 0xF0, 0xE9, 
         0x9D, 0x42, 0xF0, 0xE8, 0x9C, 0x45, 0xF0, 0x22, 0x90, 0xE6, 
         0x78, 0xE0, 0xFF, 0x30, 0xE0, 0xF8, 0xEF, 0x30, 0xE2, 0x02, 
         0xD3, 0x22, 0xC3, 0x22, 0x90, 0xE6, 0x78, 0x74, 0x80, 0xF0, 
         0xE5, 0x17, 0x25, 0xE0, 0x90, 0xE6, 0x79, 0xF0, 0x22, 0x90, 
         0xE5, 0x0D, 0xE0, 0x30, 0xE4, 0x02, 0xC3, 0x22, 0xD3, 0x22, 
         0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 
         0x90, 0xE6, 0xBA, 0xE0, 0xF5, 0x18, 0xD3, 0x22, 0x90, 0xE6, 
         0xBA, 0xE0, 0xF5, 0x16, 0xD3, 0x22, 0x90, 0xE6, 0x78, 0xE0, 
         0x20, 0xE6, 0xF9, 0x22, 0x53, 0xD8, 0xEF, 0x32, 0xD3, 0x22, 
         0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0xAA, 
         #endregion 
      };
      
      #endregion

      #region DLL APIs

      // CreateFile - Used to get access to a USB device
      [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
      public static extern Microsoft.Win32.SafeHandles.SafeFileHandle CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr SecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes,
            IntPtr hTemplateFile
            );

      // public const uint FILE_ATTRIBUTE_NORMAL = 0x80;
      // public const uint FILE_INVALID_HANDLE_VALUE = -1;
      // Taken from WinNt.h. These could be enum-ized for type-safety.
      public const uint FILE_GENERIC_READ  = 0x80000000;
      public const uint FILE_GENERIC_WRITE = 0x40000000;
      public const uint FILE_SHARE_WRITE   = 0x00000002;
      public const uint FILE_CREATE_NEW    = 1;
      public const uint FILE_CREATE_ALWAYS = 2;
      public const uint FILE_OPEN_EXISTING = 3;

      #region multiple DeviceIoControl definitions

      // DeviceIoControl. outbuf as IntPtr
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.VENDOR_REQUEST_IN lpInBuffer,
         [In] int nInBufferSize,
         IntPtr lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.VENDOR_REQUEST_IN lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.ANCHOR_DOWNLOAD_CONTROL lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. intbuf and outbuf as Usb_Device_Descriptor
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.Usb_Device_Descriptor lpInBuffer,
         [In] int nInBufferSize,
         ref EzUsbSys.Usb_Device_Descriptor lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         byte[] lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      #endregion

      /*
         // since I'm using SafeFileHandle, don't call CloseHandle(hOut);
         // CloseHandle
         [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
         [return: MarshalAs(UnmanagedType.Bool)]
         public static extern bool CloseHandle(Microsoft.Win32.SafeHandles.SafeFileHandle hObject);
      */

      #endregion

      #region Other Interop defines

      // Taken from EzUsbSys.h
      public class EzUsbSys
      {
         // These values were taken from EzUsbSys.h which were defined using the CTL_CODE macro defined in WinIoCtl.h
         // lic static uint IOCTL_Ezusb_GET_PIPE_INFO           = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  0, Method.BUFFERED,  FileAccess.ANY );
         public static uint IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR   = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  1, Method.BUFFERED,  FileAccess.ANY );
         public static uint IOCTL_Ezusb_VENDOR_REQUEST          = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  5, Method.BUFFERED,  FileAccess.ANY );
         // lic static uint IOCTL_Ezusb_ANCHOR_DOWNLOAD         = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  7, Method.BUFFERED,  FileAccess.ANY );
         public static uint IOCTL_EZUSB_ANCHOR_DOWNLOAD         = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX + 27, Method.IN_DIRECT, FileAccess.ANY );
         public static uint IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX + 22, Method.IN_DIRECT, FileAccess.ANY );

         enum FileDevice : uint
         {
            UNKNOWN = 0x00000022, // taken from FILE_DEVICE_UNKNOWN in WinIoCtl.h
         };

         enum Method : uint
         {
            BUFFERED = 0, // METHOD_BUFFERED in WinIoCtl.h 
            IN_DIRECT = 1,
            OUT_DIRECT = 2,
            NEITHER = 3,
         };

         enum FileAccess : uint
         {
            ANY = 0, // FILE_ANY_ACCESS in WinIoCtl.h 
         };

         // CTL_CODE macro defined in WinIoCtl.h
         // c# does not allow macros with parameters therefore this function was created.
         // For improved type-safety, the parameters are defined as enums based on uint.
         private static uint CTL_CODE(FileDevice deviceType, uint function, Method method, FileAccess access)
         {
            return ((uint)deviceType << 16) | ((uint)access << 14) | ((uint)function << 2) | (uint)method;
         }

         private const uint Ezusb_IOCTL_INDEX = 0x0800; // taken from Ezusb_IOCTL_INDEX in EzUsbSys.h.

         private static bool testOk = TestOk(); // Run test at startup.

         static bool TestOk()
         {
            // Make sure that this implementation results in the same values seen in EzUsb.
            Debug.Assert(
               IOCTL_Ezusb_VENDOR_REQUEST == 0x00222014 &&
               IOCTL_EZUSB_ANCHOR_DOWNLOAD == 0x0022206D &&
               IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST == 0x00222059
            );
            return true;
         }

         public enum VendAxCmd : byte
         {
            ANCHOR_LOAD_INTERNAL = 0xA0, // ANCHOR_LOAD_INTERNAL in EzUsbSys.h. R+W internal memory. Executed by USB core rather than firmware.
            RwEepromSmall        = 0xA2, // Couldn't find A2 in EzUsbSys.h. It R&W small EEPROM.
            ANCHOR_LOAD_EXTERNAL = 0xA3, // ANCHOR_LOAD_EXTERNAL
            GetEepromSize        = 0xA5, // 
            RwEepromBig          = 0xA9, // R&W a 'large' EEPROM.
         };

         public enum RequestType : byte
         {
            Class = 1,
            Vendor = 2
         };

         public enum Recipient : byte
         {
            Device = 0,
            Interface = 1,
            Endpoint = 2,
            Other = 3
         };

         public enum Direction : byte
         {
            HostToDevice = 0,
            DeviceToHost = 1
         }


         public struct VENDOR_REQUEST_IN // from EzUsbSys.h
         {
            public byte   bRequest;
            public UInt16 wValue;
            public UInt16 wIndex;
            public UInt16 wLength;
            public byte   direction;
            public byte   bData;

            public VENDOR_REQUEST_IN(EzUsbSys.VendAxCmd bRequest, int offset, UInt16 wIndex, int wLength, Direction direction, byte bData)
            {
               this.bRequest = (byte)bRequest;
               this.wValue = (UInt16)offset;
               this.wIndex = wIndex;
               this.wLength = (UInt16)wLength;
               this.direction = (byte)direction;
               this.bData = bData;
            }

         };

         // Structure used with IOCTL_EZUSB_ANCHOR_DOWNLOAD (but not IOCTL_Ezusb_ANCHOR_DOWNLOAD).
         public struct ANCHOR_DOWNLOAD_CONTROL // From EzUsbSys.h
         {
            UInt16 offset;

            public ANCHOR_DOWNLOAD_CONTROL(UInt16 offset)
            {
               this.offset = offset;
            }
         };


         public struct VENDOR_OR_CLASS_REQUEST_CONTROL // From EzUsbSys.h
         {
            public byte direction; // transfer direction (0=host to device, 1=device to host)
            public byte requestType; // request type (1=class, 2=vendor)
            public byte recepient; // recipient (0=device,1=interface,2=endpoint,3=other)
            public byte requestTypeReservedBits;
            public byte request;
            public UInt16 value;
            public UInt16 index;

            public VENDOR_OR_CLASS_REQUEST_CONTROL(
               Direction direction,
               RequestType requestType,
               Recipient recepient,
               EzUsbSys.VendAxCmd request,
               int value,
               UInt16 index)
            {
               Debug.Assert(value < 0x100000);
               this.direction = (byte)direction;
               this.requestType = (byte)requestType;
               this.recepient = (byte)recepient;
               this.request = (byte)request;
               this.value = (UInt16)value;
               this.index = index;
               this.requestTypeReservedBits = 0;
            }
         };

         public struct Usb_Device_Descriptor // Taken from usb100.h
         {
            public byte   bLength;
            public byte   bDescriptorType;
            public ushort bcdUSB;
            public byte   bDeviceClass;
            public byte   bDeviceSubClass;
            public byte   bDeviceProtocol;
            public byte   bMaxPacketSize0;
            public ushort idVendor;
            public ushort idProduct;
            public ushort bcdDevice;
            public byte   iManufacturer;
            public byte   iProduct;
            public byte   iSerialNumber;
            public byte   bNumConfigurations;
         };

      } // EzUsbSys


      #endregion

      public const int EepromSizeBytes  = 0x8000; // The size of a 32 kB EEPROM.
      public const int UsbMaxPacketSize = 0x1000;

      static Microsoft.Win32.SafeHandles.SafeFileHandle hDevice;
      string iicFilename;
      EzUsbSys.Usb_Device_Descriptor deviceDescriptor = new EzUsbSys.Usb_Device_Descriptor();
      bool deviceOnline = false;
      bool vendAxLoaded = false;

      public MainForm()
      {
         InitializeComponent();
      }

      private void timer1_Tick(object sender, EventArgs e)
      {
         try
         {
            timer1.Stop();

            // This should be modififed to dynamically update a list of devices.
            if (txtDeviceName.Text.Length==0)
            {
               string[] list = GetUnopenedDevices();

               cmboDeviceList.Items.Clear();
               cmboDeviceList.Items.AddRange(list);

               txtQtyDevices.Text = string.Format("{0} device{1} available", list.Length, list.Length != 1 ? "s" : "");

               if (list.Length == 1)
               {
                  cmboDeviceList.SelectedIndex = 0;
               }
            }
            ping();
         }
         finally
         {
            timer1.Start();
         }
      }

      private void ping()
      {
         bool deviceOnlineNow = false;
         byte [] eeFirst8Bytes = null;
         try
         {
            Open();
            GetDeviceDescriptorDevIoCtl(ref deviceDescriptor);
            deviceOnlineNow = true;

            if (vendAxLoaded)
            {
               eeFirst8Bytes = EepromRead(8);
            }

            hDevice.Close();

            if (!vendAxLoaded)
            {
               downloadVendAx(); //  FirmwareDownloadDevIoCtl(VendAxCode);
            }

         }
         catch 
         {
            deviceOnlineNow = false;
         }

         // change in status.
         if (deviceOnline != deviceOnlineNow)
         {
            deviceOnline = deviceOnlineNow;

            txtIdVendor.Text = !deviceOnline ? "" :
               deviceDescriptor.idVendor.ToString("X04") + ( deviceDescriptor.idVendor==0x04B4 ?
               " (Cypress default)" : deviceDescriptor.idVendor==0x08b1 ? " (DCT)" : "" ) 
               ;

            txtDeviceName.Text = deviceOnline ? cmboDeviceList.Text : "";
            txtProductId.Text = deviceOnline ? deviceDescriptor.idProduct.ToString("X04") : "";
            txtDeviceId.Text = deviceOnline ? deviceDescriptor.bcdDevice.ToString("X04") : "";

            ProgressDone(deviceOnline ? "Connected" : "Disconnected");

         }

         if (!deviceOnline)
         {
            vendAxLoaded = false;
         }

         txtVendAxLoaded.Text = vendAxLoaded ? "Yes" : "No";

         if (deviceOnline && vendAxLoaded && eeFirst8Bytes != null)
         {
            txtEeFirst8Bytes.Text = BitConverter.ToString(eeFirst8Bytes).Replace("-", " "); ;
         }
         else
         {
            txtEeFirst8Bytes.Text = "";
         }

         btnDeviceToIicFile.Enabled = deviceOnline;
         btnEraseEeAfter8.Enabled = deviceOnline;
         IicDownload.Enabled = deviceOnline;
         btnVerifyIicFile.Enabled = deviceOnline;
         btnEraseEeprom.Enabled = deviceOnline;
         cmboDeviceToIicFileSize.Enabled = deviceOnline;

         cmboDeviceList.Visible = cmboDeviceList.Items.Count > 1;

      }


      void GetDeviceDescriptorDevIoCtl(ref EzUsbSys.Usb_Device_Descriptor arg)
      {

         Debug.Assert(hDevice != null);

         int pBytesReturned = 0;
         bool bOk;

         bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR,
            ref arg,
            Marshal.SizeOf(arg),
            ref arg,
            Marshal.SizeOf(arg),
            ref pBytesReturned,
            IntPtr.Zero);

         if (!bOk || pBytesReturned != Marshal.SizeOf(arg)) { throw new Exception(); }

      }
      
      
      // taken from CEzMrView::Ezusb_DownloadIntelHex in EzMrView
      void downloadVendAx()
      {
         try
         {

            ProgressInit(3, "Downloading FW");
            Open();
            SendOpReset();
            hDevice.Close();
            ProgressUpdate(1);
            Thread.Sleep(400);
            Debug.Assert(VendAxCode.Length == 3476);
            ProgressUpdate(2);

            Open();
            vendAxLoaded = VendAxCode.SequenceEqual(IntRamRead(0, VendAxCode.Length));

            if (!vendAxLoaded)
            {
               FirmwareDownloadDevIoCtl(VendAxCode);
               vendAxLoaded = VendAxCode.SequenceEqual(IntRamRead(0, VendAxCode.Length));
               if (!vendAxLoaded) { throw new Exception("VendAx Verify Failed"); }
            }
            Thread.Sleep(400);
            SendOpRun();
            hDevice.Close();
            ProgressUpdate(3);
            Thread.Sleep(400);
            ProgressDone( "FW downloaded and verified" );
         }
         catch ( Exception ex ) 
         {
            ProgressDone( "FW downloaded Failed" );
         }
      }

      // Open a handle for the Cypress device.
      // The result is stored in this->hDevice.
      void Open()
      {
         hDevice = CreateFile(
            cmboDeviceList.Text,
            FILE_GENERIC_WRITE,
            FILE_SHARE_WRITE,
            IntPtr.Zero,
            FILE_OPEN_EXISTING,
            0,
            IntPtr.Zero);

         if (hDevice.IsInvalid ) throw( new Exception( "Open failed") );
      }

      byte[] EepromRead( int qty)
      {
         Debug.Assert(qty <= EepromSizeBytes);

         if (qty <= UsbMaxPacketSize)
         {
            return EepromReadDevIoCtl(0, qty);
         }

         byte[] buffer = new byte[qty];

         ProgressInit(buffer.Length, "Reading EEPROM");

         for (int remaining = qty, offset=0; remaining>0; )
         {
            int len = Math.Min(remaining, UsbMaxPacketSize);

            // Append smaller buffer onto larger buffer.
            Array.Copy(EepromReadDevIoCtl(offset, len), 0, buffer, offset, len);

            ProgressUpdate(offset);

            offset += len;
            remaining -= len;
         } // for

         ProgressDone("Done reading");
         
         return buffer;

      } // EepromRead

      byte[] EepromReadDevIoCtl(int offset, int qty)
      {
         Debug.Assert(qty <= UsbMaxPacketSize);
         Debug.Assert(offset <= EepromSizeBytes);
         
         byte[] buffer = new byte[qty];

         EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL myRequest = new EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL(
            EzUsbSys.Direction.DeviceToHost,
            EzUsbSys.RequestType.Vendor,
            EzUsbSys.Recipient.Device,
            EzUsbSys.VendAxCmd.RwEepromBig,
            offset, 
            0 );

         Debug.Assert(hDevice != null);

         int pBytesReturned = 0;

         bool bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST,
            ref myRequest,
            Marshal.SizeOf(myRequest),
            buffer,
            buffer.Length,
            ref pBytesReturned,
            IntPtr.Zero);

         if (!bOk) { throw new Exception("DeviceIoControl failed"); }
         if (!(pBytesReturned == qty)) { throw new Exception("DeviceIoControl failed"); }

         return buffer;

      }

      void EepromWrite( byte[] buffer)
      {
         EepromWriteDevIoCtl(0, buffer);
      }

      void EepromWriteDevIoCtl(int offset, byte[] buffer )
      {

         Debug.Assert(offset <= EepromSizeBytes );
         Debug.Assert(buffer.Length <= UsbMaxPacketSize);

         EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL myRequest = new EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL(
            EzUsbSys.Direction.HostToDevice,
            EzUsbSys.RequestType.Vendor,
            EzUsbSys.Recipient.Device,
            EzUsbSys.VendAxCmd.RwEepromBig,
            offset,
            0);

         Debug.Assert(hDevice != null);

         int pBytesReturned = 0;

         bool bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST,
            ref myRequest,
            Marshal.SizeOf(myRequest),
            buffer,
            buffer.Length,
            ref pBytesReturned,
            IntPtr.Zero);

         if (!bOk) { throw new Exception("DeviceIoControl failed"); }
         if (!(pBytesReturned == buffer.Length)) { throw new Exception("DeviceIoControl failed"); }
         if (!buffer.SequenceEqual(EepromReadDevIoCtl(offset, buffer.Length))) { throw new Exception("Verify failed"); }

      }


      // Write a single byte to ram location specified.
      // To download firmware, see FirmwareDownloadDevIoCtl 
      // Typical usage:
      //    IntRamWrite(0xE600, 1); // write a 1 to address 0xE600 to enter reset.
      //    IntRamWrite(0xE600, 0); // write a 1 to address 0xE600 to enter reset.
      void IntRamWriteByteDevIoCtl(UInt16 offset, byte data)
      {

         EzUsbSys.VENDOR_REQUEST_IN myRequest = new EzUsbSys.VENDOR_REQUEST_IN(
            EzUsbSys.VendAxCmd.ANCHOR_LOAD_INTERNAL,
            offset, 
            0x00,
            0x01, // length of data.
            EzUsbSys.Direction.HostToDevice,
            data); 

         Debug.Assert(hDevice != null);

         int pBytesReturned = 0;

         bool bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_Ezusb_VENDOR_REQUEST,
            ref myRequest,
            Marshal.SizeOf(myRequest),
            IntPtr.Zero,
            0,
            ref pBytesReturned,
            IntPtr.Zero);

         if (!bOk) { throw new Exception("DeviceIoControl failed"); }
         if (!(pBytesReturned == 0)) { throw new Exception("DeviceIoControl failed"); }

      }

      
      // Read internal memory. Used to determine if Vend_Ax is downloaded.
      byte[] IntRamRead(int offset, int qty)
      {
         byte data=0;

         EzUsbSys.VENDOR_REQUEST_IN myRequest = new EzUsbSys.VENDOR_REQUEST_IN(
            EzUsbSys.VendAxCmd.ANCHOR_LOAD_INTERNAL,
            offset, 
            0x00,
            qty, // length of data.
            EzUsbSys.Direction.DeviceToHost,
            data); 

         Debug.Assert(hDevice != null);

         byte[] buffer = new byte[qty];

         int pBytesReturned = 0;

         bool bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_Ezusb_VENDOR_REQUEST,
            ref myRequest,
            Marshal.SizeOf(myRequest),
            buffer,
            buffer.Length,
            ref pBytesReturned,
            IntPtr.Zero);

         if (!bOk) { throw new Exception("DeviceIoControl failed"); }
         Debug.Assert(pBytesReturned == qty);

         return buffer;

      }

      // Hold CPU in reset.
      void SendOpReset()
      {
         IntRamWriteByteDevIoCtl(0xE600, 1); // write a 1 to address 0xE600 to enter reset.
         return;
      }

      // Let CPU run.
      void SendOpRun()
      {
         IntRamWriteByteDevIoCtl(0xE600, 0); // write a 1 to address 0xE600 to enter reset.
         return;
      }

      // Download firmware.
      // See downloadVendAx for usage.
      // Typical usage:
      //    SendOpReset();
      //    FirmwareDownload(VendAxCode);
      //    SendOpRun();
      void FirmwareDownloadDevIoCtl( byte [] buffer )
      {
         Debug.Assert(buffer.Length < 7 * 1024); // The driver spec says the size must be less than 7 kB.

         EzUsbSys.ANCHOR_DOWNLOAD_CONTROL myRequest = new EzUsbSys.ANCHOR_DOWNLOAD_CONTROL(0);
         Debug.Assert(hDevice != null);

         int pBytesReturned = 0;
         bool bOk;

         bOk = DeviceIoControl(
            hDevice,
            (uint)EzUsbSys.IOCTL_EZUSB_ANCHOR_DOWNLOAD,
            ref myRequest,
            Marshal.SizeOf(myRequest),
            buffer,
            buffer.Length,
            ref pBytesReturned,
            IntPtr.Zero);
      
         if (!bOk) { throw new Exception("DeviceIoControl failed"); }
         Debug.Assert(pBytesReturned == 0);

      }
      

      // Find all un-opened devices.
      // Check the ezusb driver, and our driver, for a list of available devices.
      // Typically, there would be 0 or 1. Rarely, there would be more.
      // It's assumed that there would be few devices.
      static string[] GetUnopenedDevices()
      {
         string [] driverList = new string[]{ "Tsusb2", "ezusb" };
         List<string> deviceList = new List<string>();

         foreach (string driverName in driverList)
         {
            // I didn't test this fully with the ezusb driver.
            // The Tsusb driver used 'funny' characters and didn't seem to work with character '\'.
            // I might be able to use characters > '\' but didn't think this would be very common.
            for (char c = '0'; c < '\\'; c++)
            {
               string deviceName = @"\\.\" + driverName + "-" + c;

               Microsoft.Win32.SafeHandles.SafeFileHandle hOut = CreateFile(
                  deviceName,
                  FILE_GENERIC_READ | FILE_GENERIC_WRITE,
                  0,
                  IntPtr.Zero,
                  FILE_OPEN_EXISTING,
                  0,
                  IntPtr.Zero);

               if (hOut.IsInvalid)
               {
                  hOut.Close();
                  continue;
               }
               else
               {
                  deviceList.Add(deviceName);
                  hOut.Close();
                  // if using SafeFileHandle, don't call CloseHandle(hOut);
                  // Why? hOut was getting closed 'safely' yet again which resulted in odd behavior.
               }
            } // for each device letter
         } // for each device driver


         return deviceList.ToArray();

      }

      // Download a .IIC file.
      // Prompt for the file to download.
      private void IicDownload_Click(object sender, EventArgs e)
      {
         try
         {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.FileName = iicFilename;
            dlg.Title = "Select .IIC file to load into EEPROM";
            dlg.CheckFileExists = true;
            dlg.Filter = "IIC files (*.iic)|*.iic|All files (*.*)|*.*";
            DialogResult result = dlg.ShowDialog();

            if (result != DialogResult.OK)
            {
               return;
            }

            iicFilename = dlg.FileName;

            byte [] buffer = System.IO.File.ReadAllBytes(iicFilename);

            const int packetSize = 0x100;

            ProgressInit( buffer.Length, "Writing EEPROM");

            Open();

            for ( int offset=0, remaining=buffer.Length; remaining>0; )
            {
               int length = Math.Min( packetSize, remaining );

               byte [] x = new byte[length];

               ProgressUpdate(buffer.Length - remaining);

               // extract smaller buffer from large buffer
               Array.Copy( buffer, offset, x, 0, length );

               EepromWriteDevIoCtl( offset, x );

               remaining -= length;
               offset += length;


            }

            Debug.Assert(buffer.SequenceEqual(EepromRead( buffer.Length)));

            hDevice.Close();

            ProgressDone( string.Format( "{0} bytes downloaded and verified", buffer.Length ));
         }
         catch (Exception ex)
         {
            ProgressDone( string.Format( "Download Error" ));
         }
      }

      private void btnEraseEeprom_Click(object sender, EventArgs e)
      {
         EraseEe( false );
      }

      private void btnDeviceToIicFile_Click(object sender, EventArgs e)
      {
         int size = 0;

         try
         {
            string s = cmboDeviceToIicFileSize.Text;
            s = s.Split(' ')[0];

            size = ( s.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) ? 
               Int32.Parse(s.Substring(2), System.Globalization.NumberStyles.HexNumber):
               Int32.Parse(s);

            size = Math.Min(size, EepromSizeBytes);
         }
         catch
         {
            MessageBox.Show("Invalid file size");
            return; // TODO:
         }

         SaveFileDialog dlg = new SaveFileDialog();
         dlg.Title = "Select .IIC file to write from EEPROM";
         dlg.RestoreDirectory = true;
         dlg.FileName = iicFilename;
         dlg.Filter = "IIC files (*.iic)|*.iic|All files (*.*)|*.*";
         DialogResult result = dlg.ShowDialog();

         if (result != DialogResult.OK)
         {
            return;
         }

         iicFilename = dlg.FileName;

         byte [] buffer = new byte[size];

         Open();

         ProgressInit(size, "Reading EEPROM");

         for ( int offset = 0; offset < size; offset += Math.Min( size, UsbMaxPacketSize))
         {
            ProgressUpdate(offset);

            byte[] x = EepromReadDevIoCtl(offset, Math.Min(size, UsbMaxPacketSize));

            x.CopyTo(buffer, offset);
         }
         
         hDevice.Close();

         ProgressDone( string.Format( "{0} bytes saved", size ) );

         System.IO.File.WriteAllBytes(iicFilename, buffer);

      }



      private void EraseEe( bool keepFirst8Bytes )
      {
         try
         {
            const int eraseSize = 0x100;
            const int eraseSizeTotal = EepromSizeBytes;

            byte[] buffer = new byte[eraseSize];
            for (int i = 0; i < buffer.Length; i++)
            {
               buffer[i] = 0xFF;
            }

            Open();

            ProgressInit(eraseSizeTotal, "Erasing EEPROM");

            for (int offset = 0; offset < eraseSizeTotal; offset += eraseSize)
            {
               ProgressUpdate(offset);
               EepromWriteDevIoCtl(offset == 0 && keepFirst8Bytes ? 8 : offset, buffer);
            }

            hDevice.Close();

            ProgressDone("EEPROM erased");
         }
         catch (Exception ex)
         {
            ProgressDone("EEPROM erase failed");
         }
      }

      private void btnEraseEeAfter8_Click(object sender, EventArgs e)
      {
         EraseEe( true );
      }



      private void ProgressInit(int maxArg, string txtArg)
      {
         toolStripStatusLabel1.Text = txtArg;
         toolStripStatusLabel1.Visible = true;
         toolStripProgressBar1.Maximum = maxArg; //
         toolStripProgressBar1.Visible = true;
      }

      private void ProgressUpdate(int offsetArg )
      {
         toolStripProgressBar1.Value = offsetArg;
         statusStrip1.Update();
      }

      private void ProgressDone( string txt )
      {
         toolStripProgressBar1.Visible = false;
         toolStripStatusLabel1.Text = txt;
      }
      
      private void cmboDeviceList_SelectedIndexChanged(object sender, EventArgs e)
      {
         deviceOnline = false;
      }

      private void btnVerifyIicFile_Click(object sender, EventArgs e)
      {
         OpenFileDialog dlg = new OpenFileDialog();
         dlg.FileName = iicFilename;
         dlg.Title = "Select .IIC file to compare with EEPROM";
         dlg.CheckFileExists = true;
         dlg.Filter = "IIC files (*.iic)|*.iic|All files (*.*)|*.*";
         DialogResult result = dlg.ShowDialog();

         if (result != DialogResult.OK)
         {
            return;
         }

         iicFilename = dlg.FileName;

         byte[] buffer = System.IO.File.ReadAllBytes(iicFilename);

         try
         {
            Open();
            if (!buffer.SequenceEqual(EepromRead(buffer.Length)))
            {
               throw new Exception();
            }
            hDevice.Close();
            ProgressDone("Verify OK");
         }
         catch
         {
            ProgressDone("Verify failed");
         }
      }


      private void MainForm_Load(object sender, EventArgs e)
      {
         //testIntelHexToByteArray();
         timer1.Start();
         cmboDeviceToIicFileSize.SelectedIndex = 0;
      } // btnVerifyIicFile_Click

      void testIntelHexToByteArray()
      {
         // See http://en.wikipedia.org/wiki/.hex for .HEX record structure.
         // I'm assuming that the .hex file is simple, loads internal memory only.

         string[] hex = System.IO.File.ReadAllLines("vend_ax.hex");

         int maxAddress=0;

         // find max memory used.
         foreach (string record in hex )
         {
            Debug.Assert(record[0] == ':');

            byte recordType = byte.Parse(record.Substring(7, 2), System.Globalization.NumberStyles.HexNumber);
            if (recordType == 1)
            {
               break;
            }

            UInt16 recByteCount = UInt16.Parse(record.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
            UInt16 recAddress = UInt16.Parse(record.Substring(3, 4), System.Globalization.NumberStyles.HexNumber);

            Debug.Assert(recAddress < 0x2000); // If this fails, re-visit assumptions.

            byte checkSum = byte.Parse(record.Substring(9 + recByteCount * 2, 2), System.Globalization.NumberStyles.HexNumber);

            Debug.Assert(record.Length == 11 + recByteCount * 2);

            maxAddress = Math.Max( maxAddress, recAddress+recByteCount );

         }

         byte[] bin = new byte[maxAddress+1]; // allocate buffer to reconstitute .hex file into. +1 should result in an extra AA at the end.
         for ( int i=0; i<bin.Length; i++ ) { bin[i]=0xAA; } // Initialize buffer with 0xAA, just because the original Vend_Ax array did this.

         // For each record read from the .hex file, 
         foreach (string record in hex)
         {
            Debug.Assert(record[0] == ':');

            byte recordType = byte.Parse(record.Substring(7, 2), System.Globalization.NumberStyles.HexNumber);
            if (recordType == 1)
            {
               break;
            }

            UInt16 recByteCount = UInt16.Parse(record.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
            UInt16 recAddress = UInt16.Parse(record.Substring(3, 4), System.Globalization.NumberStyles.HexNumber);

            byte checkSum = byte.Parse(record.Substring(9 + recByteCount * 2, 2), System.Globalization.NumberStyles.HexNumber);
            // TODO: validate checksum.
            // In my tests, the firmware ran.

            Debug.Assert(record.Length == 11 + recByteCount * 2); // make sure the length is ok.

            // For each byte, represented as a 2-character hex number, store the byte in the binary buffer.
            for (int i = 0; i < recByteCount; i++)
            {
               byte b = byte.Parse(record.Substring(9 + i * 2, 2), System.Globalization.NumberStyles.HexNumber);
               bin[recAddress + i] = b;
            }
         } // foreach record in hex.

         // write to file
         // Create records of the form: 0x02, 0x07, 0xF3, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 

         // This resulting text will be used to initialize an array.
         System.IO.StreamWriter file = new System.IO.StreamWriter("vend_ax.txt");

         for (int i = 0; i < bin.Length; i++)
         {
            string s = string.Format( "0x{0:X02}, {1}", bin[i], i%10==9 ? "
" : "" );
            file.Write(s);
         }

         file.Close();

         return;
      }

      private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
      {
         System.Diagnostics.Process.Start("devmgmt.msc"); // Start the Device Manager in the Control Panel.
      }

      private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
      {
         System.Diagnostics.Process.Start(System.IO.Directory.GetCurrentDirectory()); // Open the current working directoy.
      }

   }

}
// End of file

Revision: 20873
at November 28, 2009 23:37 by jimfred


Initial Code
// File MainForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices; // for DllImport
using System.Diagnostics;
using System.Threading; // for Debug.Assert


namespace CypressEepromUtility
{
   public partial class MainForm : Form
   {
      #region Vend_AX firmware array.
      // This array was generated from C:\Cypress\USB\Examples\FX2LP\Vend_ax\Vend_Ax.hex.
      // The .hex was was reconstituted into a binary buffer and then written to a text file and its contents included here.
      // The code used to create the text file is testIntelHexToByteArray().
      // The AA bytes are gaps. 
      public static byte[] VendAxCode = new byte[]
      {
         #region fwCode
         0x02, 0x07, 0xF3, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0x02, 0x0D, 0x60, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x02, 0x08, 0x00, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0x02, 0x08, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x90, 0xE6, 
         0xB9, 0xE0, 0x24, 0x5E, 0xB4, 0x0B, 0x00, 0x40, 0x03, 0x02, 
         0x03, 0x98, 0x90, 0x00, 0x9C, 0x75, 0xF0, 0x03, 0xA4, 0xC5, 
         0x83, 0x25, 0xF0, 0xC5, 0x83, 0x73, 0x02, 0x01, 0x92, 0x02, 
         0x01, 0x92, 0x02, 0x01, 0x0D, 0x02, 0x00, 0xBD, 0x02, 0x00, 
         0xD7, 0x02, 0x00, 0xF3, 0x02, 0x01, 0x3C, 0x02, 0x01, 0x8C, 
         0x02, 0x01, 0x16, 0x02, 0x01, 0x29, 0x02, 0x01, 0x62, 0x90, 
         0xE7, 0x40, 0xE5, 0x19, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 
         0x90, 0xE6, 0x8B, 0x04, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 
         0x80, 0xF0, 0x02, 0x03, 0x98, 0x90, 0xE6, 0x0A, 0xE0, 0x90, 
         0xE7, 0x40, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 
         0x8B, 0x04, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 
         0x02, 0x03, 0x98, 0x90, 0xE7, 0x40, 0x74, 0x0F, 0xF0, 0xE4, 
         0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 0x90, 
         0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 0x02, 0x03, 0x98, 0x90, 
         0xE6, 0xBA, 0xE0, 0xF5, 0x17, 0x02, 0x03, 0x98, 0x90, 0xE6, 
         0x7A, 0xE0, 0x54, 0xFE, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 
         0x90, 0xE6, 0x8B, 0xF0, 0x02, 0x03, 0x98, 0x90, 0xE6, 0x7A, 
         0xE0, 0x44, 0x01, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 
         0xE6, 0x8B, 0xF0, 0x02, 0x03, 0x98, 0x90, 0xE7, 0x40, 0x74, 
         0x07, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 
         0x04, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 0x7F, 
         0xE8, 0x7E, 0x03, 0x12, 0x07, 0xAD, 0xD2, 0x04, 0x12, 0x0B, 
         0x87, 0x02, 0x03, 0x98, 0x90, 0xE6, 0xB5, 0xE0, 0x54, 0xFE, 
         0xF0, 0x90, 0xE6, 0xBF, 0xE0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 
         0xE6, 0xBE, 0xE0, 0x90, 0xE6, 0x8B, 0xF0, 0x90, 0xE6, 0xBB, 
         0xE0, 0x90, 0xE6, 0xB3, 0xF0, 0x90, 0xE6, 0xBA, 0xE0, 0x90, 
         0xE6, 0xB4, 0xF0, 0x02, 0x03, 0x98, 0x75, 0x19, 0x01, 0x43, 
         0x17, 0x01, 0x90, 0xE6, 0xBA, 0xE0, 0x75, 0x31, 0x00, 0xF5, 
         0x32, 0xA3, 0xE0, 0xFE, 0xE4, 0xEE, 0x42, 0x31, 0x90, 0xE6, 
         0xBE, 0xE0, 0x75, 0x33, 0x00, 0xF5, 0x34, 0xA3, 0xE0, 0xFE, 
         0xE4, 0xEE, 0x42, 0x33, 0x90, 0xE6, 0xB8, 0xE0, 0x64, 0xC0, 
         0x60, 0x03, 0x02, 0x02, 0x82, 0xE5, 0x34, 0x45, 0x33, 0x70, 
         0x03, 0x02, 0x03, 0x98, 0x90, 0xE6, 0xA0, 0xE0, 0x20, 0xE1, 
         0xF9, 0xC3, 0xE5, 0x34, 0x94, 0x40, 0xE5, 0x33, 0x94, 0x00, 
         0x50, 0x08, 0x85, 0x33, 0x35, 0x85, 0x34, 0x36, 0x80, 0x06, 
         0x75, 0x35, 0x00, 0x75, 0x36, 0x40, 0x90, 0xE6, 0xB9, 0xE0, 
         0xB4, 0xA3, 0x35, 0xE4, 0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 
         0x38, 0x95, 0x36, 0xE5, 0x37, 0x95, 0x35, 0x50, 0x60, 0xE5, 
         0x32, 0x25, 0x38, 0xF5, 0x82, 0xE5, 0x31, 0x35, 0x37, 0xF5, 
         0x83, 0xE0, 0xFF, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 
         0x34, 0xE7, 0xF5, 0x83, 0xEF, 0xF0, 0x05, 0x38, 0xE5, 0x38, 
         0x70, 0x02, 0x05, 0x37, 0x80, 0xD0, 0xE4, 0xF5, 0x37, 0xF5, 
         0x38, 0xC3, 0xE5, 0x38, 0x95, 0x36, 0xE5, 0x37, 0x95, 0x35, 
         0x50, 0x18, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34, 
         0xE7, 0xF5, 0x83, 0x74, 0xCD, 0xF0, 0x05, 0x38, 0xE5, 0x38, 
         0x70, 0x02, 0x05, 0x37, 0x80, 0xDD, 0xAD, 0x36, 0x7A, 0xE7, 
         0x79, 0x40, 0x7E, 0xE7, 0x7F, 0x40, 0xAB, 0x07, 0xAF, 0x32, 
         0xAE, 0x31, 0x12, 0x08, 0xB8, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 
         0x90, 0xE6, 0x8B, 0xE5, 0x36, 0xF0, 0x25, 0x32, 0xF5, 0x32, 
         0xE5, 0x35, 0x35, 0x31, 0xF5, 0x31, 0xC3, 0xE5, 0x34, 0x95, 
         0x36, 0xF5, 0x34, 0xE5, 0x33, 0x95, 0x35, 0xF5, 0x33, 0x02, 
         0x01, 0xBD, 0x90, 0xE6, 0xB8, 0xE0, 0x64, 0x40, 0x60, 0x03, 
         0x02, 0x03, 0x98, 0xE5, 0x1A, 0x70, 0x05, 0x12, 0x09, 0x67, 
         0x8F, 0x1A, 0xE5, 0x34, 0x45, 0x33, 0x70, 0x03, 0x02, 0x03, 
         0x98, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0xF0, 
         0x90, 0xE6, 0xA0, 0xE0, 0x20, 0xE1, 0xF9, 0x90, 0xE6, 0x8B, 
         0xE0, 0x75, 0x35, 0x00, 0xF5, 0x36, 0x90, 0xE6, 0xB9, 0xE0, 
         0xB4, 0xA3, 0x38, 0xE4, 0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 
         0x38, 0x95, 0x36, 0xE5, 0x37, 0x95, 0x35, 0x40, 0x03, 0x02, 
         0x03, 0x7C, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34, 
         0xE7, 0xF5, 0x83, 0xE0, 0xFF, 0xE5, 0x32, 0x25, 0x38, 0xF5, 
         0x82, 0xE5, 0x31, 0x35, 0x37, 0xF5, 0x83, 0xEF, 0xF0, 0x05, 
         0x38, 0xE5, 0x38, 0x70, 0x02, 0x05, 0x37, 0x80, 0xCD, 0xE4, 
         0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 0x38, 0x95, 0x36, 0xE5, 
         0x37, 0x95, 0x35, 0x50, 0x75, 0x85, 0x1A, 0x39, 0xE5, 0x1A, 
         0x64, 0x01, 0x60, 0x44, 0xE5, 0x32, 0x25, 0x38, 0xFF, 0xE5, 
         0x31, 0x35, 0x37, 0xFE, 0xE5, 0x1A, 0x24, 0xFF, 0xFD, 0xE4, 
         0x34, 0xFF, 0x5E, 0xFE, 0xEF, 0x5D, 0x4E, 0x60, 0x10, 0xE5, 
         0x32, 0x25, 0x38, 0xFF, 0xE5, 0x1A, 0x14, 0x5F, 0xFF, 0xC3, 
         0xE5, 0x1A, 0x9F, 0xF5, 0x39, 0xC3, 0xE5, 0x36, 0x95, 0x38, 
         0xFF, 0xE5, 0x35, 0x95, 0x37, 0xFE, 0xC3, 0xEF, 0x95, 0x39, 
         0xEE, 0x94, 0x00, 0x50, 0x07, 0xC3, 0xE5, 0x36, 0x95, 0x38, 
         0xF5, 0x39, 0xE5, 0x32, 0x25, 0x38, 0xFF, 0xE5, 0x31, 0x35, 
         0x37, 0xFE, 0x74, 0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34, 
         0xE7, 0xAD, 0x82, 0xFC, 0xAB, 0x39, 0x12, 0x0A, 0x9C, 0xE5, 
         0x39, 0x25, 0x38, 0xF5, 0x38, 0xE4, 0x35, 0x37, 0xF5, 0x37, 
         0x80, 0x80, 0xE5, 0x36, 0x25, 0x32, 0xF5, 0x32, 0xE5, 0x35, 
         0x35, 0x31, 0xF5, 0x31, 0xC3, 0xE5, 0x34, 0x95, 0x36, 0xF5, 
         0x34, 0xE5, 0x33, 0x95, 0x35, 0xF5, 0x33, 0x02, 0x02, 0x96, 
         0xC3, 0x22, 0x90, 0xE6, 0xB9, 0xE0, 0x70, 0x03, 0x02, 0x04, 
         0x85, 0x14, 0x70, 0x03, 0x02, 0x05, 0x2E, 0x24, 0xFE, 0x70, 
         0x03, 0x02, 0x05, 0xC4, 0x24, 0xFB, 0x70, 0x03, 0x02, 0x04, 
         0x7F, 0x14, 0x70, 0x03, 0x02, 0x04, 0x79, 0x14, 0x70, 0x03, 
         0x02, 0x04, 0x6D, 0x14, 0x70, 0x03, 0x02, 0x04, 0x73, 0x24, 
         0x05, 0x60, 0x03, 0x02, 0x06, 0x39, 0x12, 0x0D, 0x68, 0x40, 
         0x03, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xBB, 0xE0, 0x24, 0xFE, 
         0x60, 0x3B, 0x14, 0x60, 0x56, 0x24, 0xFD, 0x60, 0x16, 0x14, 
         0x60, 0x40, 0x24, 0x06, 0x70, 0x75, 0xE5, 0x0A, 0x90, 0xE6, 
         0xB3, 0xF0, 0xE5, 0x0B, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x06, 
         0x45, 0x12, 0x0D, 0x33, 0x50, 0x0F, 0xE5, 0x12, 0x90, 0xE6, 
         0xB3, 0xF0, 0xE5, 0x13, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x02, 0x06, 
         0x45, 0xE5, 0x0C, 0x90, 0xE6, 0xB3, 0xF0, 0xE5, 0x0D, 0x90, 
         0xE6, 0xB4, 0xF0, 0x02, 0x06, 0x45, 0xE5, 0x0E, 0x90, 0xE6, 
         0xB3, 0xF0, 0xE5, 0x0F, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xBA, 0xE0, 0xFF, 0x12, 0x0B, 0xE2, 0xAA, 
         0x06, 0xA9, 0x07, 0x7B, 0x01, 0xEA, 0x49, 0x4B, 0x60, 0x0D, 
         0xEE, 0x90, 0xE6, 0xB3, 0xF0, 0xEF, 0x90, 0xE6, 0xB4, 0xF0, 
         0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 
         0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 
         0x02, 0x06, 0x45, 0x12, 0x0C, 0xF1, 0x02, 0x06, 0x45, 0x12, 
         0x0D, 0x50, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x48, 0x02, 0x06, 
         0x45, 0x12, 0x0C, 0xDF, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x6A, 
         0x40, 0x03, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xB8, 0xE0, 0x24, 
         0x7F, 0x60, 0x2B, 0x14, 0x60, 0x3C, 0x24, 0x02, 0x60, 0x03, 
         0x02, 0x05, 0x24, 0xA2, 0x00, 0xE4, 0x33, 0xFF, 0x25, 0xE0, 
         0xFF, 0xA2, 0x02, 0xE4, 0x33, 0x4F, 0x90, 0xE7, 0x40, 0xF0, 
         0xE4, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 
         0x74, 0x02, 0xF0, 0x02, 0x06, 0x45, 0xE4, 0x90, 0xE7, 0x40, 
         0xF0, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 
         0x74, 0x02, 0xF0, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xBC, 0xE0, 
         0x54, 0x7E, 0xFF, 0x7E, 0x00, 0xE0, 0xD3, 0x94, 0x80, 0x40, 
         0x06, 0x7C, 0x00, 0x7D, 0x01, 0x80, 0x04, 0x7C, 0x00, 0x7D, 
         0x00, 0xEC, 0x4E, 0xFE, 0xED, 0x4F, 0x24, 0x3E, 0xF5, 0x82, 
         0x74, 0x0D, 0x3E, 0xF5, 0x83, 0xE4, 0x93, 0xFF, 0x33, 0x95, 
         0xE0, 0xFE, 0xEF, 0x24, 0xA1, 0xFF, 0xEE, 0x34, 0xE6, 0x8F, 
         0x82, 0xF5, 0x83, 0xE0, 0x54, 0x01, 0x90, 0xE7, 0x40, 0xF0, 
         0xE4, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 
         0x74, 0x02, 0xF0, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 
         0x44, 0x01, 0xF0, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x6C, 0x40, 
         0x03, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xB8, 0xE0, 0x24, 0xFE, 
         0x60, 0x1D, 0x24, 0x02, 0x60, 0x03, 0x02, 0x06, 0x45, 0x90, 
         0xE6, 0xBA, 0xE0, 0xB4, 0x01, 0x05, 0xC2, 0x00, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x02, 0x06, 
         0x45, 0x90, 0xE6, 0xBA, 0xE0, 0x70, 0x59, 0x90, 0xE6, 0xBC, 
         0xE0, 0x54, 0x7E, 0xFF, 0x7E, 0x00, 0xE0, 0xD3, 0x94, 0x80, 
         0x40, 0x06, 0x7C, 0x00, 0x7D, 0x01, 0x80, 0x04, 0x7C, 0x00, 
         0x7D, 0x00, 0xEC, 0x4E, 0xFE, 0xED, 0x4F, 0x24, 0x3E, 0xF5, 
         0x82, 0x74, 0x0D, 0x3E, 0xF5, 0x83, 0xE4, 0x93, 0xFF, 0x33, 
         0x95, 0xE0, 0xFE, 0xEF, 0x24, 0xA1, 0xFF, 0xEE, 0x34, 0xE6, 
         0x8F, 0x82, 0xF5, 0x83, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0xE6, 
         0xBC, 0xE0, 0x54, 0x80, 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 
         0xFF, 0xE0, 0x54, 0x0F, 0x2F, 0x90, 0xE6, 0x83, 0xF0, 0xE0, 
         0x44, 0x20, 0xF0, 0x02, 0x06, 0x45, 0x90, 0xE6, 0xA0, 0xE0, 
         0x44, 0x01, 0xF0, 0x02, 0x06, 0x45, 0x12, 0x0D, 0x6E, 0x50, 
         0x7C, 0x90, 0xE6, 0xB8, 0xE0, 0x24, 0xFE, 0x60, 0x20, 0x24, 
         0x02, 0x70, 0x5B, 0x90, 0xE6, 0xBA, 0xE0, 0xB4, 0x01, 0x04, 
         0xD2, 0x00, 0x80, 0x65, 0x90, 0xE6, 0xBA, 0xE0, 0x64, 0x02, 
         0x60, 0x5D, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x80, 
         0x54, 0x90, 0xE6, 0xBC, 0xE0, 0x54, 0x7E, 0xFF, 0x7E, 0x00, 
         0xE0, 0xD3, 0x94, 0x80, 0x40, 0x06, 0x7C, 0x00, 0x7D, 0x01, 
         0x80, 0x04, 0x7C, 0x00, 0x7D, 0x00, 0xEC, 0x4E, 0xFE, 0xED, 
         0x4F, 0x24, 0x3E, 0xF5, 0x82, 0x74, 0x0D, 0x3E, 0xF5, 0x83, 
         0xE4, 0x93, 0xFF, 0x33, 0x95, 0xE0, 0xFE, 0xEF, 0x24, 0xA1, 
         0xFF, 0xEE, 0x34, 0xE6, 0x8F, 0x82, 0xF5, 0x83, 0xE0, 0x44, 
         0x01, 0xF0, 0x80, 0x15, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 
         0xF0, 0x80, 0x0C, 0x12, 0x00, 0x80, 0x50, 0x07, 0x90, 0xE6, 
         0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 
         0x80, 0xF0, 0x22, 0xE4, 0xF5, 0x2C, 0xF5, 0x2B, 0xF5, 0x2A, 
         0xF5, 0x29, 0xC2, 0x03, 0xC2, 0x00, 0xC2, 0x02, 0xC2, 0x01, 
         0x12, 0x0C, 0x6C, 0x7E, 0x0A, 0x7F, 0x00, 0x8E, 0x0A, 0x8F, 
         0x0B, 0x75, 0x12, 0x0A, 0x75, 0x13, 0x12, 0x75, 0x08, 0x0A, 
         0x75, 0x09, 0x1C, 0x75, 0x10, 0x0A, 0x75, 0x11, 0x4A, 0x75, 
         0x14, 0x0A, 0x75, 0x15, 0x78, 0xEE, 0x54, 0xC0, 0x70, 0x03, 
         0x02, 0x07, 0x52, 0x75, 0x2D, 0x00, 0x75, 0x2E, 0x80, 0x8E, 
         0x2F, 0x8F, 0x30, 0xC3, 0x74, 0x9A, 0x9F, 0xFF, 0x74, 0x0A, 
         0x9E, 0xCF, 0x24, 0x02, 0xCF, 0x34, 0x00, 0xFE, 0xE4, 0x8F, 
         0x28, 0x8E, 0x27, 0xF5, 0x26, 0xF5, 0x25, 0xF5, 0x24, 0xF5, 
         0x23, 0xF5, 0x22, 0xF5, 0x21, 0xAF, 0x28, 0xAE, 0x27, 0xAD, 
         0x26, 0xAC, 0x25, 0xAB, 0x24, 0xAA, 0x23, 0xA9, 0x22, 0xA8, 
         0x21, 0xC3, 0x12, 0x0D, 0x03, 0x50, 0x37, 0xE5, 0x30, 0x25, 
         0x24, 0xF5, 0x82, 0xE5, 0x2F, 0x35, 0x23, 0xF5, 0x83, 0xE0, 
         0xFF, 0xE5, 0x2E, 0x25, 0x24, 0xF5, 0x82, 0xE5, 0x2D, 0x35, 
         0x23, 0xF5, 0x83, 0xEF, 0xF0, 0xE4, 0xFA, 0xF9, 0xF8, 0xE5, 
         0x24, 0x24, 0x01, 0xF5, 0x24, 0xEA, 0x35, 0x23, 0xF5, 0x23, 
         0xE9, 0x35, 0x22, 0xF5, 0x22, 0xE8, 0x35, 0x21, 0xF5, 0x21, 
         0x80, 0xB3, 0x85, 0x2D, 0x0A, 0x85, 0x2E, 0x0B, 0x74, 0x00, 
         0x24, 0x80, 0xFF, 0x74, 0x0A, 0x34, 0xFF, 0xFE, 0xC3, 0xE5, 
         0x13, 0x9F, 0xF5, 0x13, 0xE5, 0x12, 0x9E, 0xF5, 0x12, 0xC3, 
         0xE5, 0x0D, 0x9F, 0xF5, 0x0D, 0xE5, 0x0C, 0x9E, 0xF5, 0x0C, 
         0xC3, 0xE5, 0x0F, 0x9F, 0xF5, 0x0F, 0xE5, 0x0E, 0x9E, 0xF5, 
         0x0E, 0xC3, 0xE5, 0x09, 0x9F, 0xF5, 0x09, 0xE5, 0x08, 0x9E, 
         0xF5, 0x08, 0xC3, 0xE5, 0x11, 0x9F, 0xF5, 0x11, 0xE5, 0x10, 
         0x9E, 0xF5, 0x10, 0xC3, 0xE5, 0x15, 0x9F, 0xF5, 0x15, 0xE5, 
         0x14, 0x9E, 0xF5, 0x14, 0xD2, 0xE8, 0x43, 0xD8, 0x20, 0x90, 
         0xE6, 0x68, 0xE0, 0x44, 0x09, 0xF0, 0x90, 0xE6, 0x5C, 0xE0, 
         0x44, 0x3D, 0xF0, 0xD2, 0xAF, 0x90, 0xE6, 0x80, 0xE0, 0x54, 
         0xF7, 0xF0, 0x53, 0x8E, 0xF8, 0xC2, 0x03, 0x12, 0x07, 0xFF, 
         0x30, 0x01, 0x05, 0x12, 0x03, 0x9A, 0xC2, 0x01, 0x30, 0x03, 
         0xF2, 0x12, 0x0D, 0x64, 0x50, 0xED, 0xC2, 0x03, 0x12, 0x0C, 
         0x0D, 0x20, 0x00, 0x16, 0x90, 0xE6, 0x82, 0xE0, 0x30, 0xE7, 
         0x04, 0xE0, 0x20, 0xE1, 0xEF, 0x90, 0xE6, 0x82, 0xE0, 0x30, 
         0xE6, 0x04, 0xE0, 0x20, 0xE0, 0xE4, 0x12, 0x0B, 0xB6, 0x12, 
         0x0D, 0x66, 0x80, 0xC7, 0x22, 0x8E, 0x3A, 0x8F, 0x3B, 0x90, 
         0xE6, 0x00, 0xE0, 0x54, 0x18, 0x70, 0x12, 0xE5, 0x3B, 0x24, 
         0x01, 0xFF, 0xE4, 0x35, 0x3A, 0xC3, 0x13, 0xF5, 0x3A, 0xEF, 
         0x13, 0xF5, 0x3B, 0x80, 0x15, 0x90, 0xE6, 0x00, 0xE0, 0x54, 
         0x18, 0xFF, 0xBF, 0x10, 0x0B, 0xE5, 0x3B, 0x25, 0xE0, 0xF5, 
         0x3B, 0xE5, 0x3A, 0x33, 0xF5, 0x3A, 0xE5, 0x3B, 0x15, 0x3B, 
         0xAE, 0x3A, 0x70, 0x02, 0x15, 0x3A, 0x4E, 0x60, 0x05, 0x12, 
         0x0C, 0x21, 0x80, 0xEE, 0x22, 0x78, 0x7F, 0xE4, 0xF6, 0xD8, 
         0xFD, 0x75, 0x81, 0x41, 0x02, 0x06, 0x4D, 0x22, 0x02, 0x0C, 
         0x32, 0x00, 0x02, 0x0C, 0xB3, 0x00, 0x02, 0x0C, 0x9D, 0x00, 
         0x02, 0x0C, 0x85, 0x00, 0x02, 0x0B, 0x19, 0x00, 0x02, 0x0B, 
         0x50, 0x00, 0x02, 0x09, 0xFF, 0x00, 0x02, 0x0D, 0x70, 0x00, 
         0x02, 0x0D, 0x71, 0x00, 0x02, 0x0D, 0x72, 0x00, 0x02, 0x0D, 
         0x73, 0x00, 0x02, 0x0D, 0x74, 0x00, 0x02, 0x0D, 0x75, 0x00, 
         0x02, 0x0D, 0x76, 0x00, 0x02, 0x0D, 0x77, 0x00, 0x02, 0x0D, 
         0x78, 0x00, 0x02, 0x0D, 0x79, 0x00, 0x02, 0x0D, 0x70, 0x00, 
         0x02, 0x0D, 0x7A, 0x00, 0x02, 0x0D, 0x7B, 0x00, 0x02, 0x0D, 
         0x7C, 0x00, 0x02, 0x0D, 0x7D, 0x00, 0x02, 0x0D, 0x7E, 0x00, 
         0x02, 0x0D, 0x7F, 0x00, 0x02, 0x0D, 0x80, 0x00, 0x02, 0x0D, 
         0x70, 0x00, 0x02, 0x0D, 0x70, 0x00, 0x02, 0x0D, 0x70, 0x00, 
         0x02, 0x0D, 0x81, 0x00, 0x02, 0x0D, 0x82, 0x00, 0x02, 0x0D, 
         0x83, 0x00, 0x02, 0x0D, 0x84, 0x00, 0x02, 0x0D, 0x85, 0x00, 
         0x02, 0x0D, 0x86, 0x00, 0x02, 0x0D, 0x87, 0x00, 0x02, 0x0D, 
         0x88, 0x00, 0x02, 0x0D, 0x89, 0x00, 0x02, 0x0D, 0x8A, 0x00, 
         0x02, 0x0D, 0x8B, 0x00, 0x02, 0x0D, 0x8C, 0x00, 0x02, 0x0D, 
         0x8D, 0x00, 0x02, 0x0D, 0x8E, 0x00, 0x02, 0x0D, 0x8F, 0x00, 
         0x02, 0x0D, 0x90, 0x00, 0x02, 0x0D, 0x91, 0x00, 0x02, 0x0D, 
         0x92, 0x00, 0x8E, 0x3C, 0x8F, 0x3D, 0x8D, 0x3E, 0x8A, 0x3F, 
         0x8B, 0x40, 0x12, 0x0D, 0x58, 0x12, 0x0D, 0x24, 0x12, 0x0C, 
         0xC9, 0x50, 0x01, 0x22, 0xE5, 0x19, 0x60, 0x0C, 0xE5, 0x3C, 
         0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0C, 0xC9, 0x50, 0x01, 0x22, 
         0xE5, 0x3D, 0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0C, 0xC9, 0x50, 
         0x01, 0x22, 0x90, 0xE6, 0x78, 0x74, 0x80, 0xF0, 0xE5, 0x17, 
         0x25, 0xE0, 0x44, 0x01, 0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0D, 
         0x14, 0x50, 0x01, 0x22, 0x90, 0xE6, 0x79, 0xE0, 0xF5, 0x41, 
         0x12, 0x0D, 0x14, 0x50, 0x01, 0x22, 0xE4, 0xF5, 0x41, 0xE5, 
         0x3E, 0x14, 0xFF, 0xE5, 0x41, 0xC3, 0x9F, 0x50, 0x1C, 0x90, 
         0xE6, 0x79, 0xE0, 0xFF, 0xE5, 0x40, 0x25, 0x41, 0xF5, 0x82, 
         0xE4, 0x35, 0x3F, 0xF5, 0x83, 0xEF, 0xF0, 0x12, 0x0D, 0x14, 
         0x50, 0x01, 0x22, 0x05, 0x41, 0x80, 0xDA, 0x90, 0xE6, 0x78, 
         0x74, 0x20, 0xF0, 0x12, 0x0D, 0x14, 0x50, 0x01, 0x22, 0x90, 
         0xE6, 0x79, 0xE0, 0xFF, 0xE5, 0x40, 0x25, 0x41, 0xF5, 0x82, 
         0xE4, 0x35, 0x3F, 0xF5, 0x83, 0xEF, 0xF0, 0x12, 0x0D, 0x14, 
         0x50, 0x01, 0x22, 0x90, 0xE6, 0x78, 0x74, 0x40, 0xF0, 0x90, 
         0xE6, 0x79, 0xE0, 0xF5, 0x41, 0xC3, 0x22, 0xE5, 0x19, 0x70, 
         0x03, 0x7F, 0x01, 0x22, 0x7A, 0x10, 0x7B, 0x40, 0x7D, 0x40, 
         0xE4, 0xFF, 0xFE, 0x12, 0x08, 0xB8, 0xE4, 0xF5, 0x3A, 0x74, 
         0x00, 0x25, 0x3A, 0xF5, 0x82, 0xE4, 0x34, 0x10, 0xF5, 0x83, 
         0xE5, 0x3A, 0xF0, 0x05, 0x3A, 0xE5, 0x3A, 0xB4, 0x40, 0xEB, 
         0x7C, 0x10, 0x7D, 0x00, 0x7B, 0x40, 0xE4, 0xFF, 0xFE, 0x12, 
         0x0A, 0x9C, 0xE4, 0xF5, 0x3A, 0xE5, 0x3A, 0xF4, 0xFF, 0x74, 
         0x00, 0x25, 0x3A, 0xF5, 0x82, 0xE4, 0x34, 0x10, 0xF5, 0x83, 
         0xEF, 0xF0, 0x05, 0x3A, 0xE5, 0x3A, 0xB4, 0x40, 0xE8, 0x7A, 
         0x10, 0x7B, 0x00, 0x7D, 0x40, 0xE4, 0xFF, 0xFE, 0x12, 0x08, 
         0xB8, 0x90, 0x10, 0x00, 0xE0, 0xF5, 0x3A, 0xE5, 0x3A, 0x30, 
         0xE0, 0x05, 0x75, 0x3B, 0x01, 0x80, 0x08, 0x63, 0x3A, 0x3F, 
         0x05, 0x3A, 0x85, 0x3A, 0x3B, 0xE4, 0xF5, 0x3A, 0xE5, 0x3A, 
         0xC3, 0x94, 0x40, 0x50, 0x15, 0xAF, 0x3A, 0x7E, 0x00, 0x7C, 
         0x10, 0x7D, 0x40, 0xAB, 0x3B, 0x12, 0x0A, 0x9C, 0xE5, 0x3B, 
         0x25, 0x3A, 0xF5, 0x3A, 0x80, 0xE4, 0xAF, 0x3B, 0x22, 0x32, 
         0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xB4, 0x04, 
         0x04, 0x10, 0x00, 0x00, 0x01, 0x02, 0x00, 0x01, 0x0A, 0x06, 
         0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x09, 0x02, 
         0x2E, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 
         0x00, 0x04, 0xFF, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 
         0x00, 0x02, 0x00, 0x07, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, 
         0x07, 0x05, 0x86, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x88, 
         0x02, 0x00, 0x02, 0x00, 0x09, 0x02, 0x2E, 0x00, 0x01, 0x01, 
         0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 0x00, 0x04, 0xFF, 0x00, 
         0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 
         0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x86, 0x02, 
         0x40, 0x00, 0x00, 0x07, 0x05, 0x88, 0x02, 0x40, 0x00, 0x00, 
         0x04, 0x03, 0x09, 0x04, 0x10, 0x03, 0x43, 0x00, 0x79, 0x00, 
         0x70, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 
         0x0E, 0x03, 0x45, 0x00, 0x5A, 0x00, 0x2D, 0x00, 0x55, 0x00, 
         0x53, 0x00, 0x42, 0x00, 0x00, 0x00, 0x8E, 0x3C, 0x8F, 0x3D, 
         0x8C, 0x3E, 0x8D, 0x3F, 0x8B, 0x40, 0xC2, 0x87, 0x43, 0xB2, 
         0x80, 0x12, 0x0D, 0x58, 0x12, 0x0D, 0x24, 0x12, 0x0C, 0xC9, 
         0x50, 0x04, 0xD2, 0x04, 0x80, 0x59, 0xE5, 0x19, 0x60, 0x0F, 
         0xE5, 0x3C, 0x90, 0xE6, 0x79, 0xF0, 0x12, 0x0C, 0xC9, 0x50, 
         0x04, 0xD2, 0x04, 0x80, 0x46, 0xE5, 0x3D, 0x90, 0xE6, 0x79, 
         0xF0, 0x12, 0x0C, 0xC9, 0x50, 0x04, 0xD2, 0x04, 0x80, 0x37, 
         0xE4, 0xF5, 0x41, 0xE5, 0x41, 0xC3, 0x95, 0x40, 0x50, 0x21, 
         0x05, 0x3F, 0xE5, 0x3F, 0xAE, 0x3E, 0x70, 0x02, 0x05, 0x3E, 
         0x14, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x90, 0xE6, 0x79, 0xF0, 
         0x12, 0x0D, 0x14, 0x50, 0x04, 0xD2, 0x04, 0x80, 0x10, 0x05, 
         0x41, 0x80, 0xD8, 0x90, 0xE6, 0x78, 0xE0, 0x44, 0x40, 0xF0, 
         0x12, 0x0C, 0x51, 0xC2, 0x04, 0x53, 0xB2, 0x7F, 0xA2, 0x04, 
         0x22, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x90, 0xE6, 0x80, 
         0xE0, 0x30, 0xE7, 0x0E, 0x85, 0x08, 0x0C, 0x85, 0x09, 0x0D, 
         0x85, 0x10, 0x0E, 0x85, 0x11, 0x0F, 0x80, 0x0C, 0x85, 0x10, 
         0x0C, 0x85, 0x11, 0x0D, 0x85, 0x08, 0x0E, 0x85, 0x09, 0x0F, 
         0x53, 0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 0x10, 0xF0, 0xD0, 
         0x82, 0xD0, 0x83, 0xD0, 0xE0, 0x32, 0xC0, 0xE0, 0xC0, 0x83, 
         0xC0, 0x82, 0x90, 0xE6, 0x80, 0xE0, 0x30, 0xE7, 0x0E, 0x85, 
         0x08, 0x0C, 0x85, 0x09, 0x0D, 0x85, 0x10, 0x0E, 0x85, 0x11, 
         0x0F, 0x80, 0x0C, 0x85, 0x10, 0x0C, 0x85, 0x11, 0x0D, 0x85, 
         0x08, 0x0E, 0x85, 0x09, 0x0F, 0x53, 0x91, 0xEF, 0x90, 0xE6, 
         0x5D, 0x74, 0x20, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 
         0x32, 0x30, 0x04, 0x09, 0x90, 0xE6, 0x80, 0xE0, 0x44, 0x0A, 
         0xF0, 0x80, 0x07, 0x90, 0xE6, 0x80, 0xE0, 0x44, 0x08, 0xF0, 
         0x7F, 0xDC, 0x7E, 0x05, 0x12, 0x07, 0xAD, 0x90, 0xE6, 0x5D, 
         0x74, 0xFF, 0xF0, 0x90, 0xE6, 0x5F, 0xF0, 0x53, 0x91, 0xEF, 
         0x90, 0xE6, 0x80, 0xE0, 0x54, 0xF7, 0xF0, 0x22, 0x90, 0xE6, 
         0x82, 0xE0, 0x30, 0xE0, 0x04, 0xE0, 0x20, 0xE6, 0x0B, 0x90, 
         0xE6, 0x82, 0xE0, 0x30, 0xE1, 0x19, 0xE0, 0x30, 0xE7, 0x15, 
         0x90, 0xE6, 0x80, 0xE0, 0x44, 0x01, 0xF0, 0x7F, 0x14, 0x7E, 
         0x00, 0x12, 0x07, 0xAD, 0x90, 0xE6, 0x80, 0xE0, 0x54, 0xFE, 
         0xF0, 0x22, 0xA9, 0x07, 0xAE, 0x14, 0xAF, 0x15, 0x8F, 0x82, 
         0x8E, 0x83, 0xA3, 0xE0, 0x64, 0x03, 0x70, 0x17, 0xAD, 0x01, 
         0x19, 0xED, 0x70, 0x01, 0x22, 0x8F, 0x82, 0x8E, 0x83, 0xE0, 
         0x7C, 0x00, 0x2F, 0xFD, 0xEC, 0x3E, 0xFE, 0xAF, 0x05, 0x80, 
         0xDF, 0xE4, 0xFE, 0xFF, 0x22, 0x90, 0xE6, 0x82, 0xE0, 0x44, 
         0xC0, 0xF0, 0x90, 0xE6, 0x81, 0xF0, 0x43, 0x87, 0x01, 0x00, 
         0x00, 0x00, 0x00, 0x00, 0x22, 0x74, 0x00, 0xF5, 0x86, 0x90, 
         0xFD, 0xA5, 0x7C, 0x05, 0xA3, 0xE5, 0x82, 0x45, 0x83, 0x70, 
         0xF9, 0x22, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x90, 0xE6, 
         0xB5, 0xE0, 0x44, 0x01, 0xF0, 0xD2, 0x01, 0x53, 0x91, 0xEF, 
         0x90, 0xE6, 0x5D, 0x74, 0x01, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 
         0xD0, 0xE0, 0x32, 0x12, 0x0D, 0x58, 0x12, 0x0D, 0x24, 0x12, 
         0x0D, 0x14, 0x90, 0xE6, 0x78, 0xE0, 0x44, 0x40, 0xF0, 0x12, 
         0x0D, 0x58, 0x90, 0xE6, 0x78, 0xE0, 0x30, 0xE1, 0xE9, 0x22, 
         0xD2, 0x00, 0xE4, 0xF5, 0x1A, 0x90, 0xE6, 0x78, 0xE0, 0x54, 
         0x10, 0xFF, 0xC4, 0x54, 0x0F, 0x44, 0x50, 0xF5, 0x17, 0x13, 
         0xE4, 0x33, 0xF5, 0x19, 0x22, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 
         0x82, 0xD2, 0x03, 0x53, 0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 
         0x08, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 0x32, 0xC0, 
         0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x53, 0x91, 0xEF, 0x90, 0xE6, 
         0x5D, 0x74, 0x04, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 
         0x32, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 0x53, 0x91, 0xEF, 
         0x90, 0xE6, 0x5D, 0x74, 0x02, 0xF0, 0xD0, 0x82, 0xD0, 0x83, 
         0xD0, 0xE0, 0x32, 0x90, 0xE6, 0x78, 0xE0, 0xFF, 0x30, 0xE0, 
         0xF8, 0xEF, 0x30, 0xE2, 0x02, 0xD3, 0x22, 0xEF, 0x20, 0xE1, 
         0x02, 0xD3, 0x22, 0xC3, 0x22, 0x90, 0xE7, 0x40, 0xE5, 0x18, 
         0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 
         0xF0, 0xD3, 0x22, 0x90, 0xE7, 0x40, 0xE5, 0x16, 0xF0, 0xE4, 
         0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 0xD3, 
         0x22, 0xEB, 0x9F, 0xF5, 0xF0, 0xEA, 0x9E, 0x42, 0xF0, 0xE9, 
         0x9D, 0x42, 0xF0, 0xE8, 0x9C, 0x45, 0xF0, 0x22, 0x90, 0xE6, 
         0x78, 0xE0, 0xFF, 0x30, 0xE0, 0xF8, 0xEF, 0x30, 0xE2, 0x02, 
         0xD3, 0x22, 0xC3, 0x22, 0x90, 0xE6, 0x78, 0x74, 0x80, 0xF0, 
         0xE5, 0x17, 0x25, 0xE0, 0x90, 0xE6, 0x79, 0xF0, 0x22, 0x90, 
         0xE5, 0x0D, 0xE0, 0x30, 0xE4, 0x02, 0xC3, 0x22, 0xD3, 0x22, 
         0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 
         0x90, 0xE6, 0xBA, 0xE0, 0xF5, 0x18, 0xD3, 0x22, 0x90, 0xE6, 
         0xBA, 0xE0, 0xF5, 0x16, 0xD3, 0x22, 0x90, 0xE6, 0x78, 0xE0, 
         0x20, 0xE6, 0xF9, 0x22, 0x53, 0xD8, 0xEF, 0x32, 0xD3, 0x22, 
         0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0xAA, 
         #endregion 
      };
      
      /*
      // VendAx code taken from Vend_Ax.h in the EzMr project.
      // It caused random Windows driver errors and PC lock-ups.
      // The Vend_Ax.hex file worked OK so I re-generated this array, above.
      public static byte[] VendAxCode_Crash = new byte[]
      {
         #region fwCode
         0x02, 0x0D, 0x16, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0x02, 0x07, 0xFC, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x02, 0x08, 0x00, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x02, 0x06, 0x94, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0x02, 0x08, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x90, 0xE6, 
         0x78, 0xE0, 0x54, 0x10, 0xFF, 0xC4, 0x54, 0x0F, 0x44, 0x50, 
         0xF5, 0x1D, 0x13, 0xE4, 0x33, 0xF5, 0x1F, 0x90, 0xE6, 0xB9, 
         0xE0, 0x24, 0x5E, 0xB4, 0x0B, 0x00, 0x40, 0x03, 0x02, 0x03, 
         0x2A, 0x90, 0x00, 0xA8, 0xF8, 0x28, 0x28, 0x73, 0x02, 0x01, 
         0xA2, 0x02, 0x01, 0xA2, 0x02, 0x01, 0x1D, 0x02, 0x00, 0xC9, 
         0x02, 0x00, 0xE3, 0x02, 0x01, 0x03, 0x02, 0x01, 0x4C, 0x02, 
         0x01, 0x9C, 0x02, 0x01, 0x26, 0x02, 0x01, 0x39, 0x02, 0x01, 
         0x72, 0x90, 0xE7, 0x40, 0xE5, 0x1F, 0xF0, 0xE4, 0x90, 0xE6, 
         0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 0x90, 0xE6, 0xA0, 
         0xE0, 0x44, 0x80, 0xF0, 0x02, 0x03, 0x2A, 0x90, 0xE6, 0x00, 
         0xE0, 0xFF, 0xC4, 0x54, 0x0F, 0x90, 0xE7, 0x40, 0xF0, 0xE4, 
         0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 0x90, 
         0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 0x02, 0x03, 0x2A, 0x90, 
         0xE7, 0x40, 0x74, 0x0F, 0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 
         0x90, 0xE6, 0x8B, 0x04, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 
         0x80, 0xF0, 0x02, 0x03, 0x2A, 0x90, 0xE6, 0xBA, 0xE0, 0xF5, 
         0x1D, 0x02, 0x03, 0x2A, 0x90, 0xE6, 0x7A, 0xE0, 0x54, 0xFE, 
         0xF0, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0xF0, 
         0x02, 0x03, 0x2A, 0x90, 0xE6, 0x7A, 0xE0, 0x44, 0x01, 0xF0, 
         0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0xF0, 0x02, 
         0x03, 0x2A, 0x90, 0xE7, 0x40, 0x74, 0x07, 0xF0, 0xE4, 0x90, 
         0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 0x90, 0xE6, 
         0xA0, 0xE0, 0x44, 0x80, 0xF0, 0x7F, 0xE8, 0x7E, 0x03, 0x12, 
         0x0A, 0x5F, 0xD2, 0x04, 0x12, 0x0B, 0x9F, 0x02, 0x03, 0x2A, 
         0x90, 0xE6, 0xB5, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0xE6, 0xBF, 
         0xE0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0xBE, 0xE0, 0x90, 
         0xE6, 0x8B, 0xF0, 0x90, 0xE6, 0xBB, 0xE0, 0x90, 0xE6, 0xB3, 
         0xF0, 0x90, 0xE6, 0xBA, 0xE0, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 
         0x03, 0x2A, 0x75, 0x1F, 0x01, 0x43, 0x1D, 0x01, 0x90, 0xE6, 
         0xBA, 0xE0, 0x75, 0x31, 0x00, 0xF5, 0x32, 0xA3, 0xE0, 0xFE, 
         0xE4, 0xEE, 0x42, 0x31, 0x90, 0xE6, 0xBE, 0xE0, 0x75, 0x33, 
         0x00, 0xF5, 0x34, 0xA3, 0xE0, 0xFE, 0xE4, 0xEE, 0x42, 0x33, 
         0x90, 0xE6, 0xB8, 0xE0, 0x64, 0xC0, 0x60, 0x03, 0x02, 0x02, 
         0x92, 0xE5, 0x34, 0x45, 0x33, 0x70, 0x03, 0x02, 0x03, 0x2A, 
         0x90, 0xE6, 0xA0, 0xE0, 0x20, 0xE1, 0xF9, 0xC3, 0xE5, 0x34, 
         0x94, 0x40, 0xE5, 0x33, 0x94, 0x00, 0x50, 0x08, 0x85, 0x33, 
         0x35, 0x85, 0x34, 0x36, 0x80, 0x06, 0x75, 0x35, 0x00, 0x75, 
         0x36, 0x40, 0x90, 0xE6, 0xB9, 0xE0, 0xB4, 0xA3, 0x35, 0xE4, 
         0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 0x38, 0x95, 0x36, 0xE5, 
         0x37, 0x95, 0x35, 0x50, 0x60, 0xE5, 0x32, 0x25, 0x38, 0xF5, 
         0x82, 0xE5, 0x31, 0x35, 0x37, 0xF5, 0x83, 0xE0, 0xFF, 0x74, 
         0x40, 0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34, 0xE7, 0xF5, 0x83, 
         0xEF, 0xF0, 0x05, 0x38, 0xE5, 0x38, 0x70, 0xD4, 0x05, 0x37, 
         0x80, 0xD0, 0xE4, 0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 0x38, 
         0x95, 0x36, 0xE5, 0x37, 0x95, 0x35, 0x50, 0x18, 0x74, 0x40, 
         0x25, 0x38, 0xF5, 0x82, 0xE4, 0x34, 0xE7, 0xF5, 0x83, 0x74, 
         0xCD, 0xF0, 0x05, 0x38, 0xE5, 0x38, 0x70, 0xE1, 0x05, 0x37, 
         0x80, 0xDD, 0xAD, 0x36, 0x7A, 0xE7, 0x79, 0x40, 0x7E, 0xE7, 
         0x7F, 0x40, 0xAB, 0x07, 0xAF, 0x32, 0xAE, 0x31, 0x12, 0x09, 
         0x40, 0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0xE5, 
         0x36, 0xF0, 0x25, 0x32, 0xF5, 0x32, 0xE5, 0x35, 0x35, 0x31, 
         0xF5, 0x31, 0xC3, 0xE5, 0x34, 0x95, 0x36, 0xF5, 0x34, 0xE5, 
         0x33, 0x95, 0x35, 0xF5, 0x33, 0x02, 0x01, 0xCD, 0x90, 0xE6, 
         0xB8, 0xE0, 0x64, 0x40, 0x60, 0x03, 0x02, 0x03, 0x2A, 0xE5, 
         0x34, 0x45, 0x33, 0x70, 0x03, 0x02, 0x03, 0x2A, 0xE4, 0x90, 
         0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0xF0, 0x90, 0xE6, 0xA0, 
         0xE0, 0x20, 0xE1, 0xF9, 0x90, 0xE6, 0x8B, 0xE0, 0x75, 0x35, 
         0x00, 0xF5, 0x36, 0x90, 0xE6, 0xB9, 0xE0, 0xB4, 0xA3, 0x35, 
         0xE4, 0xF5, 0x37, 0xF5, 0x38, 0xC3, 0xE5, 0x38, 0x95, 0x36, 
         0xE5, 0x37, 0x95, 0x35, 0x50, 0x38, 0x74, 0x40, 0x25, 0x38, 
         0xF5, 0x82, 0xE4, 0x34, 0xE7, 0xF5, 0x83, 0xE0, 0xFF, 0xE5, 
         0x32, 0x25, 0x38, 0xF5, 0x82, 0xE5, 0x31, 0x35, 0x37, 0xF5, 
         0x83, 0xEF, 0xF0, 0x05, 0x38, 0xE5, 0x38, 0x70, 0xD4, 0x05, 
         0x37, 0x80, 0xD0, 0xAD, 0x36, 0x7A, 0xE7, 0x79, 0x40, 0x7E, 
         0xE7, 0x7F, 0x40, 0xAB, 0x07, 0xAF, 0x32, 0xAE, 0x31, 0x12, 
         0x0A, 0xD6, 0xE5, 0x36, 0x25, 0x32, 0xF5, 0x32, 0xE5, 0x35, 
         0x35, 0x31, 0xF5, 0x31, 0xC3, 0xE5, 0x34, 0x95, 0x36, 0xF5, 
         0x34, 0xE5, 0x33, 0x95, 0x35, 0xF5, 0x33, 0x02, 0x02, 0x9D, 
         0xC3, 0x22, 0x90, 0xE6, 0xB9, 0xE0, 0x70, 0x03, 0x02, 0x04, 
         0x07, 0x14, 0x70, 0x03, 0x02, 0x04, 0x6D, 0x24, 0xFE, 0x70, 
         0x03, 0x02, 0x04, 0xA1, 0x24, 0xFB, 0x70, 0x03, 0x02, 0x04, 
         0x01, 0x14, 0x70, 0x03, 0x02, 0x03, 0xFB, 0x14, 0x70, 0x03, 
         0x02, 0x03, 0xEF, 0x14, 0x70, 0x03, 0x02, 0x03, 0xF5, 0x24, 
         0x05, 0x60, 0x03, 0x02, 0x04, 0xCF, 0x12, 0x0D, 0x43, 0x40, 
         0x03, 0x02, 0x04, 0xDB, 0x90, 0xE6, 0xBB, 0xE0, 0x24, 0xFE, 
         0x60, 0x2C, 0x14, 0x60, 0x47, 0x24, 0xFD, 0x60, 0x16, 0x14, 
         0x60, 0x31, 0x24, 0x06, 0x70, 0x65, 0xE5, 0x0A, 0x90, 0xE6, 
         0xB3, 0xF0, 0xE5, 0x0B, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x04, 
         0xDB, 0xE5, 0x12, 0x90, 0xE6, 0xB3, 0xF0, 0xE5, 0x13, 0x90, 
         0xE6, 0xB4, 0xF0, 0x02, 0x04, 0xDB, 0xE5, 0x0C, 0x90, 0xE6, 
         0xB3, 0xF0, 0xE5, 0x0D, 0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x04, 
         0xDB, 0xE5, 0x0E, 0x90, 0xE6, 0xB3, 0xF0, 0xE5, 0x0F, 0x90, 
         0xE6, 0xB4, 0xF0, 0x02, 0x04, 0xDB, 0x90, 0xE6, 0xBA, 0xE0, 
         0xFF, 0x12, 0x0B, 0xF8, 0xAA, 0x06, 0xA9, 0x07, 0x7B, 0x01, 
         0xEA, 0x49, 0x60, 0x0D, 0xEE, 0x90, 0xE6, 0xB3, 0xF0, 0xEF, 
         0x90, 0xE6, 0xB4, 0xF0, 0x02, 0x04, 0xDB, 0x90, 0xE6, 0xA0, 
         0xE0, 0x44, 0x01, 0xF0, 0x02, 0x04, 0xDB, 0x90, 0xE6, 0xA0, 
         0xE0, 0x44, 0x01, 0xF0, 0x02, 0x04, 0xDB, 0x12, 0x0D, 0x04, 
         0x02, 0x04, 0xDB, 0x12, 0x0D, 0x2A, 0x02, 0x04, 0xDB, 0x12, 
         0x0D, 0x22, 0x02, 0x04, 0xDB, 0x12, 0x0C, 0xF2, 0x02, 0x04, 
         0xDB, 0x12, 0x0D, 0x45, 0x40, 0x03, 0x02, 0x04, 0xDB, 0x90, 
         0xE6, 0xB8, 0xE0, 0x24, 0x7F, 0x60, 0x28, 0x14, 0x60, 0x39, 
         0x24, 0x02, 0x70, 0x46, 0xA2, 0x00, 0xE4, 0x33, 0xFF, 0x25, 
         0xE0, 0xFF, 0xA2, 0x02, 0xE4, 0x33, 0x4F, 0x90, 0xE7, 0x40, 
         0xF0, 0xE4, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 
         0x8B, 0x74, 0x02, 0xF0, 0x02, 0x04, 0xDB, 0xE4, 0x90, 0xE7, 
         0x40, 0xF0, 0xA3, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 
         0x8B, 0x74, 0x02, 0xF0, 0x02, 0x04, 0xDB, 0xE4, 0x90, 0xE7, 
         0x41, 0xF0, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x74, 
         0x02, 0xF0, 0x80, 0x77, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 
         0xF0, 0x80, 0x6E, 0x12, 0x0D, 0x47, 0x50, 0x69, 0x90, 0xE6, 
         0xB8, 0xE0, 0x24, 0xFE, 0x60, 0x18, 0x24, 0x02, 0x70, 0x5D, 
         0x90, 0xE6, 0xBA, 0xE0, 0xB4, 0x01, 0x04, 0xC2, 0x00, 0x80, 
         0x52, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x49, 
         0x90, 0xE6, 0xBA, 0xE0, 0x60, 0x43, 0x90, 0xE6, 0xA0, 0xE0, 
         0x44, 0x01, 0xF0, 0x80, 0x3A, 0x12, 0x0D, 0x49, 0x50, 0x35, 
         0x90, 0xE6, 0xB8, 0xE0, 0x24, 0xFE, 0x60, 0x18, 0x24, 0x02, 
         0x70, 0x29, 0x90, 0xE6, 0xBA, 0xE0, 0xB4, 0x01, 0x04, 0xD2, 
         0x00, 0x80, 0x1E, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 
         0x80, 0x15, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x01, 0xF0, 0x80, 
         0x0C, 0x12, 0x00, 0x80, 0x50, 0x07, 0x90, 0xE6, 0xA0, 0xE0, 
         0x44, 0x01, 0xF0, 0x90, 0xE6, 0xA0, 0xE0, 0x44, 0x80, 0xF0, 
         0x22, 0xE4, 0xF5, 0x2C, 0xF5, 0x2B, 0xF5, 0x2A, 0xF5, 0x29, 
         0xC2, 0x03, 0xC2, 0x00, 0xC2, 0x02, 0xC2, 0x01, 0x12, 0x0D, 
         0x3A, 0x7E, 0x08, 0x7F, 0xB8, 0x8E, 0x0A, 0x8F, 0x0B, 0x75, 
         0x12, 0x08, 0x75, 0x13, 0xCA, 0x75, 0x08, 0x08, 0x75, 0x09, 
         0xD4, 0x75, 0x10, 0x08, 0x75, 0x11, 0xF4, 0x75, 0x14, 0x09, 
         0x75, 0x15, 0x14, 0x90, 0xE6, 0x80, 0xE0, 0x30, 0xE7, 0x0E, 
         0x85, 0x08, 0x0C, 0x85, 0x09, 0x0D, 0x85, 0x10, 0x0E, 0x85, 
         0x11, 0x0F, 0x80, 0x0C, 0x85, 0x10, 0x0C, 0x85, 0x11, 0x0D, 
         0x85, 0x08, 0x0E, 0x85, 0x09, 0x0F, 0xEE, 0x54, 0xE0, 0x70, 
         0x03, 0x02, 0x06, 0x4C, 0x75, 0x2D, 0x00, 0x75, 0x2E, 0x80, 
         0x7E, 0x08, 0x7F, 0xB8, 0x8E, 0x2F, 0x8F, 0x30, 0xC3, 0x74, 
         0x3E, 0x9F, 0xFF, 0x74, 0x09, 0x9E, 0xCF, 0x24, 0x02, 0xCF, 
         0x34, 0x00, 0xFE, 0xE4, 0x8F, 0x28, 0x8E, 0x27, 0xF5, 0x26, 
         0xF5, 0x25, 0xF5, 0x24, 0xF5, 0x23, 0xF5, 0x22, 0xF5, 0x21, 
         0xAF, 0x28, 0xAE, 0x27, 0xAD, 0x26, 0xAC, 0x25, 0xAB, 0x24, 
         0xAA, 0x23, 0xA9, 0x22, 0xA8, 0x21, 0xC3, 0x12, 0x07, 0xEB, 
         0x50, 0x26, 0xE5, 0x2E, 0x25, 0x24, 0xF5, 0x82, 0xE5, 0x2D, 
         0x35, 0x23, 0xF5, 0x83, 0x74, 0xCD, 0xF0, 0xE5, 0x24, 0x24, 
         0x01, 0xF5, 0x24, 0xE4, 0x35, 0x23, 0xF5, 0x23, 0xE4, 0x35, 
         0x22, 0xF5, 0x22, 0xE4, 0x35, 0x21, 0xF5, 0x21, 0x80, 0xC4, 
         0xE4, 0xF5, 0x24, 0xF5, 0x23, 0xF5, 0x22, 0xF5, 0x21, 0xAF, 
         0x28, 0xAE, 0x27, 0xAD, 0x26, 0xAC, 0x25, 0xAB, 0x24, 0xAA, 
         0x23, 0xA9, 0x22, 0xA8, 0x21, 0xC3, 0x12, 0x07, 0xEB, 0x50, 
         0x31, 0xAE, 0x23, 0xAF, 0x24, 0xE5, 0x30, 0x2F, 0xF5, 0x82, 
         0xE5, 0x2F, 0x3E, 0xF5, 0x83, 0xE0, 0xFD, 0xE5, 0x2E, 0x2F, 
         0xF5, 0x82, 0xE5, 0x2D, 0x3E, 0xF5, 0x83, 0xED, 0xF0, 0xEF, 
         0x24, 0x01, 0xF5, 0x24, 0xE4, 0x3E, 0xF5, 0x23, 0xE4, 0x35, 
         0x22, 0xF5, 0x22, 0xE4, 0x35, 0x21, 0xF5, 0x21, 0x80, 0xB9, 
         0x85, 0x2D, 0x0A, 0x85, 0x2E, 0x0B, 0x74, 0xB8, 0x24, 0x80, 
         0xFF, 0x74, 0x08, 0x34, 0xFF, 0xFE, 0xC3, 0xE5, 0x13, 0x9F, 
         0xF5, 0x13, 0xE5, 0x12, 0x9E, 0xF5, 0x12, 0xC3, 0xE5, 0x0D, 
         0x9F, 0xF5, 0x0D, 0xE5, 0x0C, 0x9E, 0xF5, 0x0C, 0xC3, 0xE5, 
         0x0F, 0x9F, 0xF5, 0x0F, 0xE5, 0x0E, 0x9E, 0xF5, 0x0E, 0xC3, 
         0xE5, 0x09, 0x9F, 0xF5, 0x09, 0xE5, 0x08, 0x9E, 0xF5, 0x08, 
         0xC3, 0xE5, 0x11, 0x9F, 0xF5, 0x11, 0xE5, 0x10, 0x9E, 0xF5, 
         0x10, 0xC3, 0xE5, 0x15, 0x9F, 0xF5, 0x15, 0xE5, 0x14, 0x9E, 
         0xF5, 0x14, 0xD2, 0xE8, 0x43, 0xD8, 0x20, 0x90, 0xE6, 0x68, 
         0xE0, 0x44, 0x09, 0xF0, 0x90, 0xE6, 0x5C, 0xE0, 0x44, 0x3D, 
         0xF0, 0xD2, 0xAF, 0x53, 0x8E, 0xF8, 0xC2, 0x03, 0x30, 0x01, 
         0x05, 0x12, 0x03, 0x2C, 0xC2, 0x01, 0x30, 0x03, 0x1E, 0x12, 
         0x0D, 0x3F, 0x50, 0x19, 0xC2, 0x03, 0x12, 0x0C, 0x95, 0x20, 
         0x00, 0x0B, 0x90, 0xE6, 0x82, 0xE0, 0x20, 0xE7, 0xF3, 0xE0, 
         0x20, 0xE6, 0xEF, 0x12, 0x0B, 0xCC, 0x12, 0x0D, 0x41, 0x12, 
         0x0D, 0x4B, 0x80, 0xD2, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 
         0xC0, 0x85, 0xC0, 0x84, 0xC0, 0x86, 0x75, 0x86, 0x00, 0xC0, 
         0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 
         0xC0, 0x03, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0xE6, 0x78, 0xE0, 
         0x30, 0xE2, 0x06, 0x75, 0x1B, 0x06, 0x02, 0x07, 0x7E, 0x90, 
         0xE6, 0x78, 0xE0, 0x20, 0xE1, 0x0C, 0xE5, 0x1B, 0x64, 0x02, 
         0x60, 0x06, 0x75, 0x1B, 0x07, 0x02, 0x07, 0x7E, 0xE5, 0x1B, 
         0x24, 0xFE, 0x60, 0x5F, 0x14, 0x60, 0x36, 0x24, 0xFE, 0x70, 
         0x03, 0x02, 0x07, 0x6F, 0x24, 0xFC, 0x70, 0x03, 0x02, 0x07, 
         0x7B, 0x24, 0x08, 0x60, 0x03, 0x02, 0x07, 0x7E, 0xAB, 0x17, 
         0xAA, 0x18, 0xA9, 0x19, 0xAF, 0x1A, 0x05, 0x1A, 0x8F, 0x82, 
         0x75, 0x83, 0x00, 0x12, 0x07, 0x9C, 0x90, 0xE6, 0x79, 0xF0, 
         0xE5, 0x1A, 0x65, 0x16, 0x70, 0x70, 0x75, 0x1B, 0x05, 0x80, 
         0x6B, 0x90, 0xE6, 0x79, 0xE0, 0xAB, 0x17, 0xAA, 0x18, 0xA9, 
         0x19, 0xAE, 0x1A, 0x8E, 0x82, 0x75, 0x83, 0x00, 0x12, 0x07, 
         0xC9, 0x75, 0x1B, 0x02, 0xE5, 0x16, 0x64, 0x01, 0x70, 0x4E, 
         0x90, 0xE6, 0x78, 0xE0, 0x44, 0x20, 0xF0, 0x80, 0x45, 0xE5, 
         0x16, 0x24, 0xFE, 0xB5, 0x1A, 0x07, 0x90, 0xE6, 0x78, 0xE0, 
         0x44, 0x20, 0xF0, 0xE5, 0x16, 0x14, 0xB5, 0x1A, 0x0A, 0x90, 
         0xE6, 0x78, 0xE0, 0x44, 0x40, 0xF0, 0x75, 0x1B, 0x00, 0x90, 
         0xE6, 0x79, 0xE0, 0xAB, 0x17, 0xAA, 0x18, 0xA9, 0x19, 0xAE, 
         0x1A, 0x8E, 0x82, 0x75, 0x83, 0x00, 0x12, 0x07, 0xC9, 0x05, 
         0x1A, 0x80, 0x0F, 0x90, 0xE6, 0x78, 0xE0, 0x44, 0x40, 0xF0, 
         0x75, 0x1B, 0x00, 0x80, 0x03, 0x75, 0x1B, 0x00, 0x53, 0x91, 
         0xDF, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 
         0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x86, 0xD0, 0x84, 0xD0, 
         0x85, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 0x32, 0xBB, 0x01, 
         0x0C, 0xE5, 0x82, 0x29, 0xF5, 0x82, 0xE5, 0x83, 0x3A, 0xF5, 
         0x83, 0xE0, 0x22, 0x50, 0x06, 0xE9, 0x25, 0x82, 0xF8, 0xE6, 
         0x22, 0xBB, 0xFE, 0x06, 0xE9, 0x25, 0x82, 0xF8, 0xE2, 0x22, 
         0xE5, 0x82, 0x29, 0xF5, 0x82, 0xE5, 0x83, 0x3A, 0xF5, 0x83, 
         0xE4, 0x93, 0x22, 0xF8, 0xBB, 0x01, 0x0D, 0xE5, 0x82, 0x29, 
         0xF5, 0x82, 0xE5, 0x83, 0x3A, 0xF5, 0x83, 0xE8, 0xF0, 0x22, 
         0x50, 0x06, 0xE9, 0x25, 0x82, 0xC8, 0xF6, 0x22, 0xBB, 0xFE, 
         0x05, 0xE9, 0x25, 0x82, 0xC8, 0xF2, 0x22, 0xEB, 0x9F, 0xF5, 
         0xF0, 0xEA, 0x9E, 0x42, 0xF0, 0xE9, 0x9D, 0x42, 0xF0, 0xE8, 
         0x9C, 0x45, 0xF0, 0x22, 0x53, 0xD8, 0xEF, 0x32, 0x02, 0x0B, 
         0x71, 0x00, 0x02, 0x0C, 0x70, 0x00, 0x02, 0x0C, 0x4B, 0x00, 
         0x02, 0x0C, 0x24, 0x00, 0x02, 0x09, 0xD3, 0x00, 0x02, 0x0A, 
         0x19, 0x00, 0x02, 0x0D, 0x4C, 0x00, 0x02, 0x0D, 0x4D, 0x00, 
         0x02, 0x0D, 0x4E, 0x00, 0x02, 0x0D, 0x4F, 0x00, 0x02, 0x0D, 
         0x50, 0x00, 0x02, 0x0D, 0x51, 0x00, 0x02, 0x0D, 0x52, 0x00, 
         0x02, 0x0D, 0x53, 0x00, 0x02, 0x0D, 0x54, 0x00, 0x02, 0x0D, 
         0x55, 0x00, 0x02, 0x0D, 0x56, 0x00, 0x02, 0x0D, 0x4D, 0x00, 
         0x02, 0x0D, 0x57, 0x00, 0x02, 0x0D, 0x58, 0x00, 0x02, 0x0D, 
         0x59, 0x00, 0x02, 0x0D, 0x5A, 0x00, 0x02, 0x0D, 0x5B, 0x00, 
         0x02, 0x0D, 0x5C, 0x00, 0x02, 0x0D, 0x5D, 0x00, 0x02, 0x0D, 
         0x4D, 0x00, 0x02, 0x0D, 0x4D, 0x00, 0x02, 0x0D, 0x4D, 0x00, 
         0x02, 0x0D, 0x5E, 0x00, 0x02, 0x0D, 0x5F, 0x00, 0x02, 0x0D, 
         0x60, 0x00, 0x02, 0x0D, 0x61, 0x00, 0x02, 0x0D, 0x62, 0x00, 
         0x02, 0x0D, 0x63, 0x00, 0x02, 0x0D, 0x64, 0x00, 0x02, 0x0D, 
         0x65, 0x00, 0x02, 0x0D, 0x66, 0x00, 0x02, 0x0D, 0x67, 0x00, 
         0x02, 0x0D, 0x68, 0x00, 0x02, 0x0D, 0x69, 0x00, 0x02, 0x0D, 
         0x6A, 0x00, 0x02, 0x0D, 0x6B, 0x00, 0x02, 0x0D, 0x6C, 0x00, 
         0x02, 0x0D, 0x6D, 0x00, 0x02, 0x0D, 0x6E, 0x00, 0x02, 0x0D, 
         0x6F, 0x00, 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 
         0x47, 0x05, 0x02, 0x10, 0x00, 0x00, 0x01, 0x02, 0x00, 0x01, 
         0x0A, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 
         0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xA0, 0x32, 0x09, 
         0x04, 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x07, 0x05, 
         0x02, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x86, 0x02, 0x00, 
         0x02, 0x00, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0xA0, 
         0x32, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x00, 
         0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 
         0x02, 0x40, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x10, 0x03, 
         0x43, 0x00, 0x79, 0x00, 0x70, 0x00, 0x72, 0x00, 0x65, 0x00, 
         0x73, 0x00, 0x73, 0x00, 0x16, 0x03, 0x45, 0x00, 0x5A, 0x00, 
         0x2D, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 
         0x46, 0x00, 0x58, 0x00, 0x32, 0x00, 0x00, 0x00, 0x8E, 0x39, 
         0x8F, 0x3A, 0x8D, 0x3B, 0x8A, 0x3C, 0x8B, 0x3D, 0xE4, 0xFD, 
         0xF5, 0x3E, 0xE5, 0x1F, 0x60, 0x12, 0xE5, 0x39, 0xFF, 0x7E, 
         0x00, 0x0D, 0xEE, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0x0E, 
         0xF5, 0x83, 0xEF, 0xF0, 0xE5, 0x3A, 0xAE, 0x05, 0x0D, 0x74, 
         0x00, 0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x0E, 0xF5, 0x83, 0xE5, 
         0x3A, 0xF0, 0x7A, 0x0E, 0x7B, 0x00, 0xAF, 0x1D, 0x12, 0x0C, 
         0xD6, 0xAB, 0x3D, 0xAA, 0x3C, 0xAD, 0x3B, 0xAF, 0x1D, 0x02, 
         0x0C, 0xBA, 0xAB, 0x07, 0xAA, 0x06, 0xAC, 0x05, 0xE4, 0xFD, 
         0xE5, 0x1F, 0x60, 0x10, 0xEA, 0x7E, 0x00, 0x0D, 0xEE, 0x24, 
         0x00, 0xF5, 0x82, 0xE4, 0x34, 0x0E, 0xF5, 0x83, 0xEA, 0xF0, 
         0xEB, 0xAE, 0x05, 0x0D, 0x74, 0x00, 0x2E, 0xF5, 0x82, 0xE4, 
         0x34, 0x0E, 0xF5, 0x83, 0xEB, 0xF0, 0xAF, 0x05, 0x0D, 0x74, 
         0x00, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x0E, 0xF5, 0x83, 0xEC, 
         0xF0, 0x7A, 0x0E, 0x7B, 0x00, 0xAF, 0x1D, 0x12, 0x0C, 0xD6, 
         0xAF, 0x1D, 0x02, 0x0A, 0xA0, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 
         0x82, 0xC0, 0x85, 0xC0, 0x84, 0xC0, 0x86, 0x75, 0x86, 0x00, 
         0x90, 0xE6, 0x80, 0xE0, 0x30, 0xE7, 0x0E, 0x85, 0x08, 0x0C, 
         0x85, 0x09, 0x0D, 0x85, 0x10, 0x0E, 0x85, 0x11, 0x0F, 0x80, 
         0x0C, 0x85, 0x10, 0x0C, 0x85, 0x11, 0x0D, 0x85, 0x08, 0x0E, 
         0x85, 0x09, 0x0F, 0x53, 0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 
         0x10, 0xF0, 0xD0, 0x86, 0xD0, 0x84, 0xD0, 0x85, 0xD0, 0x82, 
         0xD0, 0x83, 0xD0, 0xE0, 0x32, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 
         0x82, 0xC0, 0x85, 0xC0, 0x84, 0xC0, 0x86, 0x75, 0x86, 0x00, 
         0x90, 0xE6, 0x80, 0xE0, 0x30, 0xE7, 0x0E, 0x85, 0x08, 0x0C, 
         0x85, 0x09, 0x0D, 0x85, 0x10, 0x0E, 0x85, 0x11, 0x0F, 0x80, 
         0x0C, 0x85, 0x10, 0x0C, 0x85, 0x11, 0x0D, 0x85, 0x08, 0x0E, 
         0x85, 0x09, 0x0F, 0x53, 0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 
         0x20, 0xF0, 0xD0, 0x86, 0xD0, 0x84, 0xD0, 0x85, 0xD0, 0x82, 
         0xD0, 0x83, 0xD0, 0xE0, 0x32, 0x8E, 0x3A, 0x8F, 0x3B, 0x90, 
         0xE6, 0x00, 0xE0, 0x54, 0x18, 0x70, 0x0D, 0xE5, 0x3A, 0xC3, 
         0x13, 0xF5, 0x3A, 0xE5, 0x3B, 0x13, 0xF5, 0x3B, 0x80, 0x15, 
         0x90, 0xE6, 0x00, 0xE0, 0x54, 0x18, 0xFF, 0xBF, 0x10, 0x0B, 
         0xE5, 0x3B, 0x25, 0xE0, 0xF5, 0x3B, 0xE5, 0x3A, 0x33, 0xF5, 
         0x3A, 0xE5, 0x3B, 0x15, 0x3B, 0xAE, 0x3A, 0x70, 0x02, 0x15, 
         0x3A, 0x4E, 0x60, 0x05, 0x12, 0x0C, 0xA9, 0x80, 0xEE, 0x22, 
         0x90, 0xE6, 0x78, 0xE0, 0x20, 0xE6, 0xF9, 0xC2, 0xE9, 0x90, 
         0xE6, 0x78, 0xE0, 0x44, 0x80, 0xF0, 0xEF, 0x25, 0xE0, 0x90, 
         0xE6, 0x79, 0xF0, 0x90, 0xE6, 0x78, 0xE0, 0x30, 0xE0, 0xF9, 
         0x90, 0xE6, 0x78, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0xE6, 0x78, 
         0xE0, 0x20, 0xE6, 0xF9, 0x90, 0xE6, 0x78, 0xE0, 0x30, 0xE1, 
         0xD6, 0xD2, 0xE9, 0x22, 0x8E, 0x39, 0x8F, 0x3A, 0x8D, 0x3B, 
         0x8A, 0x3C, 0x8B, 0x3D, 0xE4, 0xF5, 0x3E, 0xE5, 0x3E, 0xC3, 
         0x95, 0x3B, 0x50, 0x20, 0x05, 0x3A, 0xE5, 0x3A, 0xAE, 0x39, 
         0x70, 0x02, 0x05, 0x39, 0x14, 0xFF, 0xE5, 0x3D, 0x25, 0x3E, 
         0xF5, 0x82, 0xE4, 0x35, 0x3C, 0xF5, 0x83, 0xE0, 0xFD, 0x12, 
         0x09, 0x8A, 0x05, 0x3E, 0x80, 0xD9, 0x22, 0xA9, 0x07, 0x90, 
         0xE6, 0x78, 0xE0, 0x20, 0xE6, 0xF9, 0xE5, 0x1B, 0x70, 0x25, 
         0x90, 0xE6, 0x78, 0xE0, 0x44, 0x80, 0xF0, 0xE9, 0x25, 0xE0, 
         0x44, 0x01, 0x90, 0xE6, 0x79, 0xF0, 0x8D, 0x16, 0xAF, 0x03, 
         0xA9, 0x07, 0x75, 0x17, 0x01, 0x8A, 0x18, 0x89, 0x19, 0xE4, 
         0xF5, 0x1A, 0x75, 0x1B, 0x03, 0xD3, 0x22, 0xC3, 0x22, 0xA9, 
         0x07, 0x90, 0xE6, 0x78, 0xE0, 0x20, 0xE6, 0xF9, 0xE5, 0x1B, 
         0x70, 0x23, 0x90, 0xE6, 0x78, 0xE0, 0x44, 0x80, 0xF0, 0xE9, 
         0x25, 0xE0, 0x90, 0xE6, 0x79, 0xF0, 0x8D, 0x16, 0xAF, 0x03, 
         0xA9, 0x07, 0x75, 0x17, 0x01, 0x8A, 0x18, 0x89, 0x19, 0xE4, 
         0xF5, 0x1A, 0x75, 0x1B, 0x01, 0xD3, 0x22, 0xC3, 0x22, 0xC0, 
         0xE0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0x85, 0xC0, 0x84, 0xC0, 
         0x86, 0x75, 0x86, 0x00, 0x90, 0xE6, 0xB5, 0xE0, 0x44, 0x01, 
         0xF0, 0xD2, 0x01, 0x53, 0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 
         0x01, 0xF0, 0xD0, 0x86, 0xD0, 0x84, 0xD0, 0x85, 0xD0, 0x82, 
         0xD0, 0x83, 0xD0, 0xE0, 0x32, 0x90, 0xE6, 0x80, 0xE0, 0x44, 
         0x08, 0xF0, 0xE4, 0xF5, 0x39, 0x30, 0x04, 0x04, 0xE0, 0x44, 
         0x02, 0xF0, 0x7F, 0xDC, 0x7E, 0x05, 0x12, 0x0A, 0x5F, 0x90, 
         0xE6, 0x5D, 0x74, 0xFF, 0xF0, 0x90, 0xE6, 0x5F, 0xF0, 0x53, 
         0x91, 0xEF, 0x90, 0xE6, 0x80, 0xE0, 0x54, 0xF7, 0xF0, 0x22, 
         0x90, 0xE6, 0x82, 0xE0, 0x30, 0xE0, 0x04, 0xE0, 0x20, 0xE6, 
         0x0B, 0x90, 0xE6, 0x82, 0xE0, 0x30, 0xE1, 0x19, 0xE0, 0x30, 
         0xE7, 0x15, 0x90, 0xE6, 0x80, 0xE0, 0x44, 0x01, 0xF0, 0x7F, 
         0x14, 0x7E, 0x00, 0x12, 0x0A, 0x5F, 0x90, 0xE6, 0x80, 0xE0, 
         0x54, 0xFE, 0xF0, 0x22, 0xA9, 0x07, 0xAE, 0x14, 0xAF, 0x15, 
         0x8F, 0x82, 0x8E, 0x83, 0xA3, 0xE0, 0x64, 0x03, 0x70, 0x17, 
         0xAD, 0x01, 0x19, 0xED, 0x70, 0x01, 0x22, 0x8F, 0x82, 0x8E, 
         0x83, 0xE0, 0x7C, 0x00, 0x2F, 0xFD, 0xEC, 0x3E, 0xFE, 0xAF, 
         0x05, 0x80, 0xDF, 0x7E, 0x00, 0x7F, 0x00, 0x22, 0xC0, 0xE0, 
         0xC0, 0x83, 0xC0, 0x82, 0xC0, 0x85, 0xC0, 0x84, 0xC0, 0x86, 
         0x75, 0x86, 0x00, 0xD2, 0x03, 0x53, 0x91, 0xEF, 0x90, 0xE6, 
         0x5D, 0x74, 0x08, 0xF0, 0xD0, 0x86, 0xD0, 0x84, 0xD0, 0x85, 
         0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 0x32, 0xC0, 0xE0, 0xC0, 
         0x83, 0xC0, 0x82, 0xC0, 0x85, 0xC0, 0x84, 0xC0, 0x86, 0x75, 
         0x86, 0x00, 0x53, 0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 0x04, 
         0xF0, 0xD0, 0x86, 0xD0, 0x84, 0xD0, 0x85, 0xD0, 0x82, 0xD0, 
         0x83, 0xD0, 0xE0, 0x32, 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, 
         0xC0, 0x85, 0xC0, 0x84, 0xC0, 0x86, 0x75, 0x86, 0x00, 0x53, 
         0x91, 0xEF, 0x90, 0xE6, 0x5D, 0x74, 0x02, 0xF0, 0xD0, 0x86, 
         0xD0, 0x84, 0xD0, 0x85, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 
         0x32, 0x90, 0xE6, 0x82, 0xE0, 0x44, 0xC0, 0xF0, 0x90, 0xE6, 
         0x81, 0xF0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
         0x22, 0x74, 0x00, 0xF5, 0x86, 0x90, 0xFD, 0xA5, 0x7C, 0x05, 
         0xA3, 0xE5, 0x82, 0x45, 0x83, 0x70, 0xF9, 0x22, 0x12, 0x0B, 
         0x0B, 0xE5, 0x1B, 0x24, 0xFA, 0x60, 0x0E, 0x14, 0x60, 0x06, 
         0x24, 0x07, 0x70, 0xF3, 0xD3, 0x22, 0xE4, 0xF5, 0x1B, 0xD3, 
         0x22, 0xE4, 0xF5, 0x1B, 0xD3, 0x22, 0x12, 0x0B, 0x3F, 0xE5, 
         0x1B, 0x24, 0xFA, 0x60, 0x0E, 0x14, 0x60, 0x06, 0x24, 0x07, 
         0x70, 0xF3, 0xD3, 0x22, 0xE4, 0xF5, 0x1B, 0xD3, 0x22, 0xE4, 
         0xF5, 0x1B, 0xD3, 0x22, 0x90, 0xE7, 0x40, 0xE5, 0x1E, 0xF0, 
         0xE4, 0x90, 0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 
         0xD3, 0x22, 0x90, 0xE7, 0x40, 0xE5, 0x1C, 0xF0, 0xE4, 0x90, 
         0xE6, 0x8A, 0xF0, 0x90, 0xE6, 0x8B, 0x04, 0xF0, 0xD3, 0x22, 
         0x78, 0x7F, 0xE4, 0xF6, 0xD8, 0xFD, 0x75, 0x81, 0x3E, 0x02, 
         0x04, 0xE3, 0x90, 0xE6, 0xBA, 0xE0, 0xF5, 0x1E, 0xD3, 0x22, 
         0x90, 0xE6, 0xBA, 0xE0, 0xF5, 0x1C, 0xD3, 0x22, 0xE4, 0xF5, 
         0x1B, 0xD2, 0xE9, 0xD2, 0xAF, 0x22, 0xD2, 0x00, 0x02, 0x0D, 
         0x32, 0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 0xD3, 0x22, 0xD3, 
         0x22, 0xD3, 0x22, 0x22, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 
         0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
         0,0,0,0,0,0 // EzMr sends 6 extra null bytes for some reason.
         #endregion
      };
      */
      #endregion

      #region DLL APIs

      // CreateFile - Used to get access to a USB device
      [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
      public static extern Microsoft.Win32.SafeHandles.SafeFileHandle CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr SecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes,
            IntPtr hTemplateFile
            );

      // public const uint FILE_ATTRIBUTE_NORMAL = 0x80;
      // public const uint FILE_INVALID_HANDLE_VALUE = -1;
      // Taken from WinNt.h. These could be enum-ized for type-safety.
      public const uint FILE_GENERIC_READ  = 0x80000000;
      public const uint FILE_GENERIC_WRITE = 0x40000000;
      public const uint FILE_SHARE_WRITE   = 0x00000002;
      public const uint FILE_CREATE_NEW    = 1;
      public const uint FILE_CREATE_ALWAYS = 2;
      public const uint FILE_OPEN_EXISTING = 3;

      #region multiple DeviceIoControl definitions

      // DeviceIoControl. outbuf as IntPtr
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.VENDOR_REQUEST_IN lpInBuffer,
         [In] int nInBufferSize,
         IntPtr lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.VENDOR_REQUEST_IN lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.ANCHOR_DOWNLOAD_CONTROL lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.VENDOR_OR_CLASS_REQUEST_CONTROL lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. intbuf and outbuf as Usb_Device_Descriptor
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         ref EzUsbSys.Usb_Device_Descriptor lpInBuffer,
         [In] int nInBufferSize,
         ref EzUsbSys.Usb_Device_Descriptor lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      // DeviceIoControl. outbuf as byte []
      [return: MarshalAs(UnmanagedType.Bool)]
      [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
      public static extern bool DeviceIoControl(
         [In] Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
         [In] uint dwIoControlCode, // EIOControlCode
         byte[] lpInBuffer,
         [In] int nInBufferSize,
         byte[] lpOutBuffer,
         int nOutBufferSize,
         ref int pBytesReturned,
         IntPtr Overlapped
      );

      #endregion

      /*
         // since I'm using SafeFileHandle, don't call CloseHandle(hOut);
         // CloseHandle
         [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
         [return: MarshalAs(UnmanagedType.Bool)]
         public static extern bool CloseHandle(Microsoft.Win32.SafeHandles.SafeFileHandle hObject);
      */

      #endregion

      #region Other Interop defines

      // Taken from EzUsbSys.h
      public class EzUsbSys
      {
         // These values were taken from EzUsbSys.h which were defined using the CTL_CODE macro defined in WinIoCtl.h
         // lic static uint IOCTL_Ezusb_GET_PIPE_INFO           = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  0, Method.BUFFERED,  FileAccess.ANY );
         public static uint IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR   = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  1, Method.BUFFERED,  FileAccess.ANY );
         public static uint IOCTL_Ezusb_VENDOR_REQUEST          = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  5, Method.BUFFERED,  FileAccess.ANY );
         // lic static uint IOCTL_Ezusb_ANCHOR_DOWNLOAD         = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX +  7, Method.BUFFERED,  FileAccess.ANY );
         public static uint IOCTL_EZUSB_ANCHOR_DOWNLOAD         = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX + 27, Method.IN_DIRECT, FileAccess.ANY );
         public static uint IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST = CTL_CODE(FileDevice.UNKNOWN, Ezusb_IOCTL_INDEX + 22, Method.IN_DIRECT, FileAccess.ANY );

         enum FileDevice : uint
         {
            UNKNOWN = 0x00000022, // taken from FILE_DEVICE_UNKNOWN in WinIoCtl.h
         };

         enum Method : uint
         {
            BUFFERED = 0, // METHOD_BUFFERED in WinIoCtl.h 
            IN_DIRECT = 1,
            OUT_DIRECT = 2,
            NEITHER = 3,
         };

         enum FileAccess : uint
         {
            ANY = 0, // FILE_ANY_ACCESS in WinIoCtl.h 
         };

         // CTL_CODE macro defined in WinIoCtl.h
         // c# does not allow macros with parameters therefore this function was created.
         // For improved type-safety, the parameters are defined as enums based on uint.
         private static uint CTL_CODE(FileDevice deviceType, uint function, Method method, FileAccess access)
         {
            return ((uint)deviceType << 16) | ((uint)access << 14) | ((uint)function << 2) | (uint)method;
         }

         private const uint Ezusb_IOCTL_INDEX = 0x0800; // taken from Ezusb_IOCTL_INDEX in EzUsbSys.h.

         private static bool testOk = TestOk(); // Run test at startup.

         static bool TestOk()
         {
            // Make sure that this implementation results in the same values seen in EzUsb.
            Debug.Assert(
               IOCTL_Ezusb_VENDOR_REQUEST == 0x00222014 &&
               IOCTL_EZUSB_ANCHOR_DOWNLOAD == 0x0022206D &&
               IOCTL_EZUSB_VENDOR_OR_CLASS_REQUEST == 0x00222059
            );
            return true;
         }

         public enum VendAxCmd : byte
         {
            ANCHOR_LOAD_INTERNAL = 0xA0, // ANCHOR_LOAD_INTERNAL in EzUsbSys.h. R+W internal memory. Executed by USB core rather than firmware.
            RwEepromSmall        = 0xA2, // Couldn't find A2 in EzUsbSys.h. It R&W small EEPROM.
            ANCHOR_LOAD_EXTERNAL = 0xA3, // ANCHOR_LOAD_EXTERNAL
            GetEepromSize        = 0xA5, // 
            RwEepromBig          = 0xA9, // R&W a 'large' EEPROM.
         };

         public enum RequestType : byte
         {
            Class = 1,
            Vendor = 2
         };

         public enum Recipient : byte
         {
            Device = 0,
            Interface = 1,
            Endpoint = 2,
            Other = 3
         };

         public enum Direction : byte
         {
            HostToDevice = 0,
            DeviceToHost = 1
         }


         public struct VENDOR_REQUEST_IN // from EzUsbSys.h
         {
            public byte   bRequest;
            public UInt16 wValue;
            public UInt16 wIndex;
            public UInt16 wLength;
            public byte   direction;
            public byte   bData;

            public VENDOR_REQUEST_IN(EzUsbSys.VendAxCmd bRequest, int offset, UInt16 wIndex, int wLength, Direction direction, byte bData)
            {
               this.bRequest = (byte)bRequest;
               this.wValue = (UInt16)offset;
               this.wIndex = wIndex;
               this.wLength = (UInt16)wLength;
               this.direction = (byte)direction;
               this.bData = bData;
            }

         };

         // Structure used with IOCTL_EZUSB_ANCHOR_DOWNLOAD (but not IOCTL_Ezusb_ANCHOR_DOWNLOAD).
         public struct ANCHOR_DOWNLOAD_CONTROL // From EzUsbSys.h
         {
            UInt16 offset;

            public ANCHOR_DOWNLOAD_CONTROL(UInt16 offset)
            {
               this.offset = offset;
            }
         };


         public struct VENDOR_OR_CLASS_REQUEST_CONTROL // From EzUsbSys.h
         {
            public byte direction; // transfer direction (0=host to device, 1=device to host)
            public byte requestType; // request type (1=class, 2=vendor)
            public byte recepient; // recipient (0=device,1=interface,2=endpoint,3=other)
            public byte requestTypeReservedBits;
            public byte request;
            public UInt16 value;
            public UInt16 index;

            public VENDOR_OR_CLASS_REQUEST_CONTROL(
               Direction direction,
               RequestType requestType,
               Recipient recepient,
               EzUsbSys.VendAxCmd request,
               int value,
               UInt16 index)
            {
               Debug.Assert(value < 0x100000);
               this.direction = (byte)direction;
               this.requestType = (byte)requestType;
               this.recepient = (byte)recepient;
               this.request = (byte)request;
               this.value = (UInt16)value;
               this.index = index;
               this.requestTypeReservedBits = 0;
            }
         };

         public struct Usb_Device_Descriptor // Taken from usb100.h
         {
            public byte   bLength;
            public byte   bDescriptorType;
            public ushort bcdUSB;
            public byte   bDeviceClass;
            public byte   bDeviceSubClass;
            public byte   bDeviceProtocol;
            public byte   bMaxPacketSize0;
            public ushort idVendor;
            public ushort idProduct;
            public ushort bcdDevice;
            public byte   iManufacturer;
            public byte   iProduct;
            public byte   iSerialNumber;
            public byte   bNumConfigurations;
         };

      } // EzUsbSys


      #endregion

      public const int EepromSizeBytes  = 0x8000; // The size of a 32 kB EEPROM.
      public const int UsbMaxPacketSize = 0x1000;

      static Microsoft.Win32.SafeHandles.SafeFileHandle hDevice;
      string iicFilename;
      EzUsbSys.Usb_Device_Descriptor deviceDescriptor = new EzUsbSys.Usb_Device_Descriptor();
      bool deviceOnline = false;
      bool vendAxLoaded = false;

      public MainForm()
      {
         InitializeComponent();
      }

      private void timer1_Tick(object sender, EventArgs e)
      {
         try
         {
            timer1.Stop();

            // This should be modififed to dynamically update a list of devices.
            if (txtDeviceName.Text.Length==0)
            {
               string[] list = GetUnopenedDevices();

               cmboDeviceList.Items.Clear();
               cmboDeviceList.Items.AddRange(list);

               txtQtyDevices.Text = string.Format("{0} device{1} available", list.Length, list.Length != 1 ? "s" : "");

               if (list.Length == 1)
               {
                  cmboDeviceList.SelectedIndex = 0;
               }
            }
            ping();
         }
         finally
         {
            timer1.Start();
         }
      }

      private void ping()
      {
         bool deviceOnlineNow = false;
         byte [] eeFirst8Bytes = null;
         try
         {
            Open();
            GetDeviceDescriptorDevIoCtl(ref deviceDescriptor);
            deviceOnlineNow = true;

            if (vendAxLoaded)
            {
               eeFirst8Bytes = EepromRead(8);
            }

            hDevice.Close();

            if (!vendAxLoaded)
            {
               downloadVendAx(); //  FirmwareDownloadDevIoCtl(VendAxCode);
            }

         }
         catch 
         {
            deviceOnlineNow = false;
         }

         // change in status.
         if (deviceOnline != deviceOnlineNow)
         {
            deviceOnline = deviceOnlineNow;

            txtIdVendor.Text = !deviceOnline ? "" :
               deviceDescriptor.idVendor.ToString("X04") + ( deviceDescriptor.idVendor==0x04B4 ?
               " (Cypress default)" : deviceDescriptor.idVendor==0x08b1 ? " (DCT)" : "" ) 
               ;

            txtDeviceName.Text = deviceOnline ? cmboDeviceList.Text : "";
            txtProductId.Text = deviceOnline ? deviceDescriptor.idProduct.ToString("X04") : "";
            txtDeviceId.Text = deviceOnline ? deviceDescriptor.bcdDevice.ToString("X04") : "";

            ProgressDone(deviceOnline ? "Connected" : "Disconnected");

         }

         if (!deviceOnline)
         {
            vendAxLoaded = false;
         }

         txtVendAxLoaded.Text = vendAxLoaded ? "Yes" : "No";

         if (deviceOnline && vendAxLoaded && eeFirst8Bytes != null)
         {
            txtEeFirst8Bytes.Text = BitConverter.ToString(eeFirst8Bytes).Replace("-", " "); ;
         }
         else
         {
            txtEeFirst8Bytes.Text = "";
         }

         btnDeviceToIicFile.Enabled = deviceOnline;
         btnEraseEeAfter8.Enabled = deviceOnline;
         IicDownload.Enabled = deviceOnline;
         btnVerifyIicFile.Enab

Initial URL


Initial Description
Cypress FX2 EEPROM utility implemented in C#.net with interop calls to deviceIoControl for access to the USB driver. This utility reads, writes, verifies and erases the EEPROM. It embeds the vend_ax.hex firmware in a byte array and automatically downloads the firmware if it isn't detected in internal RAM. Some of the code was borrowed from the EzUsb or CyConsole utility. Some code was taken from the EzUsbSys.h file and re-defined for use in c#.

Initial Title
C# Cypress EEPROM Utility with interop calls to deviceIoControl for access to USB driver.

Initial Tags


Initial Language
C#