﻿//MainBrain32MZ.cpp

#include "framework.h"
#include "resource.h"
#include "targetver.h"

#include <SetupAPI.h>
#include <winusb.h>
#include <initguid.h>
#include <Usbiodef.h>
#include <shlwapi.h>
#include <sstream>
#include <Dbt.h>
#include <strsafe.h>
#include <winnt.h>
#include <vector>
#include <array>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <string.h>
#include <bitset> 

#pragma comment (lib, "setupapi.lib") //Used for device management and monitoring (device enumeration, checking device status).
#pragma comment (lib, "winusb.lib") // Provides the interface for communicating with USB devices.
#pragma comment(lib, "Shlwapi.lib")

//using namespace std;

enum connectionStatus
{
    isConnected,
    notConnected
};

connectionStatus Connection;

#define MAX_LOADSTRING                  100
#define IDD_MAINBRAIN32USBTEST_DIALOG   102
#define IDS_APP_TITLE                   103
#define IDM_EXIT                        105
#define IDC_LISTBOX                     106
#define ProgramListTitleText            107
#define SendByteStatic                  108
#define SendByteEdit                    109
#define MainTimer                       110
#define DevCurText                      111
#define mAText                          112
#define DevVoltsText                    113
#define VText                           114
#define RunButton                       115
#define StopButton                      116
#define FreqEdit                        117
#define FreqStatic                      118
#define HzStatic                        119
#define groupBox                        120
#define groupBoxTitle                   121
#define QEIPositionTitle                122
#define QEIPosition                     123
#define DutyCycle                       124
#define DutyCycleText                   125
#define DutyCycleUnits                  126
#define QEIIndexTxt                     127
#define QEIIndex                        128
#define ResetButton                     129
#define SpeedEdit                       130
#define DirectionCheckBox               131
#define DirectionStatic                 132
#define SpeedStatic                     133
#define UpdateButton                    134
#define CurrentSpeedStatic              135
#define CurrentSpeedTxt                 136
#define ControlByteTxt                  137
#define StatusByteTxt                   138
#define ControlByte                     139
#define StatusByte                      140
#define updateGroupBox                  141
#define CurrentRPMTxt                   142
#define SpeedTimer                      143
#define RunSeqButton                    144
#define RunSeqStatic                    145
#define SeqNumEdit                      146
#define SeqDirEdit                      147
#define SeqAccEdit                      148
#define SeqSpdEdit                      149
#define SeqNumStatic                    150
#define SeqAccStatic                    151
#define SeqSpdStatic                    152
#define SeqDirStatic                    153
#define SeqDirCombo                     154
#define SeqDecStatic                    155
#define SeqDecEdit                      156
#define SeqDistStatic                   157
#define SeqDistEdit                     158
#define SeqLoopStatic                   159
#define SeqLoopCheckBox                 160
#define SeqSaveButton                   161
#define SeqStopEdit                     162
#define SeqStopStatic                   163
#define SeqDelayEdit                    164
#define SeqDelayStatic                  165
#define SeqTotalEdit                    166
#define SeqTotalStatic                  167
#define SplashStatic                    168
#define IDC_Peripherals_LISTBOX         169
#define BoardAddressStatic              170
#define BoardAddressEdit                171
#define BoardDataStatic                 172
#define BoardDataEdit                   173
#define BoardData2Static                174
#define BoardData2Edit                  175
#define SineWaveCheckBox                176
#define SineWaveStatic                  177
#define AudioWaveCheckBox               178
#define AudioWaveStatic                 179
#define TriangleWaveCheckBox            180
#define TriangleWaveStatic              181
#define CompositeVideoCheckBox          182
#define CompositeVideoStatic            183

//The Device Programs Listbox stuff
typedef struct _COMMANDS
{
    TCHAR progName[MAX_PATH];
} devicePrograms;

devicePrograms ProgramList[] =
{
    { TEXT("Test Connection to MainBrain") },
    { TEXT("Write to LED Port") },
    { TEXT("Reset Device") },
    { TEXT("Build Motion") },
    { TEXT("Board Comm Check") },
    { TEXT("Flash Utilities") },
    { TEXT("Write Byte to SRAM")},
    { TEXT("Peripheral Commands")},
    //{ TEXT("Set Time") },
    //{ TEXT("Get Device Info") },
    //{ TEXT("Read SRAM") },
    //{ TEXT("Dump SRAM to Display") },
    //{ TEXT("Write File to SRAM") },
    //{ TEXT("Read Flash") },
    //{ TEXT("Write Flash") },
    //{ TEXT("Set LEDs") },
    //{ TEXT("Update Firmware") },
    //{ TEXT("Home") },
    //{ TEXT("Motion Interface") },
    //{ TEXT("Build Motion Sequence") }
};

devicePrograms PeripheralCommandsList[] =
{
    { TEXT("Send Data Byte") },
    { TEXT("Build Board List") },
    { TEXT("DAC - Set Voltage") },
    { TEXT("PWM") },
    { TEXT("DAC - Generate Waveform") },
    { TEXT("ADC - Get Value") }
};

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
SYSTEMTIME localTime;
HDEVINFO DeviceInfoTable = INVALID_HANDLE_VALUE;
DWORD Error = NO_ERROR;
//USB#VID_1209&PID_0001#MainBrain_MZ#{2b8a8216-c82a-4a91-a8bc-a12129d2d70b}
GUID InterfaceClassGuid = { 0x2b8a8216, 0xc82a, 0x4a91, 0xa8, 0xbc, 0xa1, 0x21, 0x29, 0xd2, 0xd7, 0x0b };
PSP_DEVICE_INTERFACE_DATA InterfaceDataStructure = new SP_DEVICE_INTERFACE_DATA;
DWORD InterfaceIndex;
PSP_DEVICE_INTERFACE_DETAIL_DATA DetailedInterfaceDataStructure = new SP_DEVICE_INTERFACE_DETAIL_DATA;
HANDLE MyDeviceHandle = INVALID_HANDLE_VALUE;
WINUSB_INTERFACE_HANDLE MyWinUSBInterfaceHandle;
HDC dc;
LPCWSTR c;
WORD hpos = 10;
WORD vpos = 10;
RECT rect;
HBRUSH hBrush;
HFONT hFont;
HFONT BigFont;
PAINTSTRUCT ps;
BYTE keyInput = 0;
unsigned char outBuffer[64] = { 0 };
unsigned char inBuffer[64] = { 0 };
unsigned char DataOutBuffer[64] = { 0 };
wchar_t buf[4];
unsigned int fs;
wchar_t ErrorBuffer[10] = { '\0' };
wchar_t MyBuffer[30];
uint8_t lbIndex = 0;
BYTE DeviceIndex = -1;
HWND hEdit;
static HBRUSH hbrBkgnd;
bool isBusy = false;
uint8_t data_counter = 0;
int16_t data_array[10];
uint16_t PWM_Freq;
bool voltsTimeMet = false;
bool curTimeMet = false;
float avgCurData[11] = { 0 };
uint8_t cv = 0;
float avgVoltsData[11] = { 0 };
uint8_t vv = 0;
double TimerCount = 0;
double TimerTmpA = 0;
double TimerTmpB = 0;
bool myBool = false;
uint32_t pos;
uint8_t cntl;
bool SeqChecked = false;

union byte2dword
{
    uint8_t     mByte[4];
    uint32_t    mDword;  
};

void FindMainBrain(HWND hWnd);
void SelectDevice(HWND hWnd, BYTE DeviceIndex);
void SendCMD(HWND hWnd, uint8_t lbIndex);
void Debug_Function(DWORD Error);
void LED_Port(uint8_t led);
void getDevData(HWND hWnd);
void SendDisconnected(HWND hWnd);
void SetTime(HWND hWnd);
void MotorRun(HWND hWnd);
void MotorStop(HWND hWnd);
void ResetCounter(HWND hWnd);
void UpdateMotion(HWND hWnd);
std::string ToBinaryString(uint8_t value);
void CalculateRPM(HWND hWnd);
void RunSeq(HWND hWnd);
void SeqSave(HWND hWnd);
void USBbyteOut(void);
void File2Array(HWND hWnd);

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    SendByte(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_MAINBRAIN32USBTEST, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MAINBRAIN32USBTEST));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_MAINBRAIN32USBTEST);
    wcex.lpszClassName  = szWindowClass;
    //wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_ICON1));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX ^ WS_MINIMIZEBOX,
      250, 250, 620, 400, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

    //Register for device notification details
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;

    ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    NotificationFilter.dbcc_classguid = InterfaceClassGuid;

    RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);

    //Connect to MainBrain
    FindMainBrain(hWnd);

    return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
      case WM_DEVICECHANGE:
      {
          //PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
          switch (wParam)
          {
             case DBT_DEVNODES_CHANGED:
                 break;

             case DBT_DEVICEARRIVAL:
                 //Write to Window
                 InvalidateRect(hWnd, NULL, TRUE);
                 UpdateWindow(hWnd);
                 FindMainBrain(hWnd);
                 break;

             case DBT_DEVICEREMOVECOMPLETE:

                 InvalidateRect(hWnd, NULL, TRUE);
                 UpdateWindow(hWnd);

                 DestroyWindow(hWnd);
                break;

             default:
                 InvalidateRect(hWnd, NULL, TRUE);
                 UpdateWindow(hWnd);
          }
          break;
      }
      break;

      //This sets the background of the controls to white with black text
      //Gets rid of the default control shadows
      case WM_CTLCOLORSTATIC:
      {
          HDC hdcStatic = (HDC)wParam;
          SetTextColor(hdcStatic, RGB(0, 0, 0));
          SetBkColor(hdcStatic, RGB(255, 255, 255));

          if (hbrBkgnd == NULL)
          {
              hbrBkgnd = CreateSolidBrush(RGB(255, 255, 255));
          }
          return (INT_PTR)hbrBkgnd;
      }
      break;
      case WM_KEYDOWN:
      {
          if(Connection == notConnected)
          {
              if (wParam > 0x29 && wParam < 0x39)
              {
                  //MessageBoxW(NULL, L"Key Pressed!", L"MsgFromTextBox", MB_OK);
                  DeviceIndex = ((BYTE)wParam - 0x30);
                  //SelectedState = TRUE;
                  SelectDevice(hWnd, DeviceIndex);
              }
              else
              {
                  SelectDevice(hWnd, 0);
              }
          }
      }
      return DefWindowProc(hWnd, message, wParam, lParam);

     case WM_COMMAND:
     {
            int wmId = LOWORD(wParam);
            int wmEvent = HIWORD(wParam);

            // Parse the menu selections:
            switch (wmId)
            {
            case SpeedEdit:
                //to do
                break;
            case DirectionCheckBox:
                if (HIWORD(wParam) == BN_CLICKED)
                {
                    //TO DO
                }
                break;
            case RunSeqButton:
                RunSeq(hWnd);
                break;
            case SeqSaveButton:
                SeqSave(hWnd);
                break;
            case UpdateButton:
                UpdateMotion(hWnd);
                break;
            case RunButton:
                MotorRun(hWnd);
                break;
            case StopButton:
                MotorStop(hWnd);
                break;
            case ResetButton:
                ResetCounter(hWnd);
                break;
            case ID_PROGRAMS:
                ShowWindow(GetDlgItem(hWnd, SplashStatic), SW_HIDE);

                ShowWindow(GetDlgItem(hWnd, IDC_LISTBOX), SW_SHOW);
                ShowWindow(GetDlgItem(hWnd, ProgramListTitleText), SW_SHOW);
                ShowWindow(GetDlgItem(hWnd, RunButton), SW_HIDE);
                ShowWindow(GetDlgItem(hWnd, StopButton), SW_HIDE);
                ShowWindow(GetDlgItem(hWnd, FreqStatic), SW_HIDE);
                ShowWindow(GetDlgItem(hWnd, FreqEdit), SW_HIDE);
                ShowWindow(GetDlgItem(hWnd, HzStatic), SW_HIDE);

                EnableMenuItem(GetMenu(hWnd), ID_PROGRAMS, MF_BYCOMMAND | MF_GRAYED);

                InvalidateRect(hWnd, NULL, TRUE);
                UpdateWindow(hWnd);
                break;
            case IDC_LISTBOX:
                if (wmEvent == LBN_SELCHANGE)
                {
                    lbIndex = (BYTE)SendMessage(GetDlgItem(hWnd, IDC_LISTBOX), LB_GETCURSEL, NULL, NULL);
                }
                if (wmEvent == LBN_DBLCLK)
                {
                    SendCMD(hWnd, lbIndex);
                }

                InvalidateRect(hWnd, NULL, TRUE);
                UpdateWindow(hWnd);

                break;
            case IDC_Peripherals_LISTBOX:
                    if (wmEvent == LBN_SELCHANGE)
                    {
                        lbIndex = (BYTE)SendMessage(GetDlgItem(hWnd, IDC_Peripherals_LISTBOX), LB_GETCURSEL, NULL, NULL);
                        switch (lbIndex)
                        {
                            //Send Data Byte
                        case 0:
                            ShowWindow(GetDlgItem(hWnd, BoardAddressStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardAddressEdit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataEdit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Static), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Edit), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, SineWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, SineWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoCheckBox), SW_HIDE);

                            SetWindowTextW(GetDlgItem(hWnd, BoardDataStatic), L"Data Byte");

                            break;

                            //Build Board List
                        case 1:
                            ShowWindow(GetDlgItem(hWnd, BoardAddressStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardAddressEdit), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, BoardDataStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataEdit), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Static), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Edit), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, SineWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, SineWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoCheckBox), SW_HIDE);

                            SetWindowTextW(GetDlgItem(hWnd, BoardAddressStatic), L"Board List:");
                            SetWindowTextW(GetDlgItem(hWnd, BoardDataStatic), L"No boards found!");

                            break;

                            //Set DAC Level
                        case 2:
                            ShowWindow(GetDlgItem(hWnd, BoardAddressStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardAddressEdit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataEdit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Static), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Edit), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, SineWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, SineWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoCheckBox), SW_HIDE);

                            SetWindowTextW(GetDlgItem(hWnd, BoardDataStatic), L"DAC Level");

                            break;

                            //Set PWM
                        case 3:
                            ShowWindow(GetDlgItem(hWnd, BoardAddressStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardAddressEdit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataEdit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Static), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Edit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, SineWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, SineWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoCheckBox), SW_HIDE);

                            SetWindowTextW(GetDlgItem(hWnd, BoardDataStatic), L"Frequency");
                            SetWindowTextW(GetDlgItem(hWnd, BoardData2Static), L"Sample Rate");
                            SetWindowTextW(GetDlgItem(hWnd, BoardDataEdit), L"1000");
                            SetWindowTextW(GetDlgItem(hWnd, BoardData2Edit), L"44100");

                            break;

                            //DAC - Generate Waveform
                        case 4:
                            ShowWindow(GetDlgItem(hWnd, BoardAddressStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardAddressEdit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataEdit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Static), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Edit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, SineWaveStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, SineWaveCheckBox), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveCheckBox), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveCheckBox), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoCheckBox), SW_SHOW);

                            SetWindowTextW(GetDlgItem(hWnd, BoardDataStatic), L"Frequency");
                            SetWindowTextW(GetDlgItem(hWnd, BoardData2Static), L"Sample Rate");
                            SetWindowTextW(GetDlgItem(hWnd, BoardDataEdit), L"1000");
                            SetWindowTextW(GetDlgItem(hWnd, BoardData2Edit), L"44100");

                            break;

                        case 5:
                            ShowWindow(GetDlgItem(hWnd, BoardAddressStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardAddressEdit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataStatic), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardDataEdit), SW_SHOW);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Static), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, BoardData2Edit), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, SineWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, SineWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, AudioWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, TriangleWaveCheckBox), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoStatic), SW_HIDE);
                            ShowWindow(GetDlgItem(hWnd, CompositeVideoCheckBox), SW_HIDE);

                            SetWindowTextW(GetDlgItem(hWnd, BoardDataStatic), L"ADC start/stop");
                            SetWindowTextW(GetDlgItem(hWnd, BoardDataEdit), L"0");

                            break;
                        }

                        InvalidateRect(hWnd, NULL, TRUE);
                        UpdateWindow(hWnd);
                    }
                    if (wmEvent == LBN_DBLCLK)
                    {                       
                        SendCMD(hWnd, (lbIndex + 100));
                    }
                break;
            case CompositeVideoCheckBox:
                if (SendMessage(GetDlgItem(hWnd, CompositeVideoCheckBox), BM_GETCHECK, 0, 0) == BST_CHECKED)
                {
                    SetWindowTextW(GetDlgItem(hWnd, BoardDataStatic), L"Horizontal");
                    SetWindowTextW(GetDlgItem(hWnd, BoardData2Static), L"Vertical");
                    SetWindowTextW(GetDlgItem(hWnd, BoardDataEdit), L"180");
                    SetWindowTextW(GetDlgItem(hWnd, BoardData2Edit), L"100");
                }

                break;
            case IDM_ABOUT:
                 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_FILE2ARRAY:
                File2Array(hWnd);
                EnableMenuItem(GetMenu(hWnd), ID_PROGRAMS, MF_BYCOMMAND | MF_ENABLED);
                break;
            case IDM_EXIT:
                SendDisconnected(hWnd);
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
     case WM_TIMER:
     {
         switch (wParam)
         {
             case MainTimer:
                if (Connection == isConnected)
                { 
                    getDevData(hWnd);
                }
             case SpeedTimer:
                 if (Connection == isConnected)
                 {
                     CalculateRPM(hWnd);
                 }
                 return 0;
         }
     }
         break;
    case WM_CREATE:
    {
        //set connection to not connected
        Connection = notConnected;

        //Sets the font for the main window
        hFont = CreateFont(14, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
            CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Consolas"));

        BigFont = CreateFont(40, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
            CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Consolas"));

        //Create a timer to poll the Device for Data
        SetTimer(hWnd, MainTimer, 100, (TIMERPROC)NULL);

        //Create a timer 
        SetTimer(hWnd, SpeedTimer, 500, (TIMERPROC)NULL);

        //Splash message
        CreateWindow(L"STATIC", L"MainBrain is connected ...", SS_LEFT | WS_CHILD | SW_HIDE, 20, 20, 400, 15, hWnd, (HMENU)SplashStatic, NULL, NULL);

        //Listbox
        CreateWindow(L"LISTBOX", NULL, WS_CHILD | WS_BORDER | SW_HIDE | WS_VSCROLL | LBS_NOTIFY, 20, 50, 300, 255, hWnd, (HMENU)IDC_LISTBOX, NULL, NULL);
        CreateWindow(L"STATIC", L"Utilities", SS_CENTER | WS_CHILD | SW_HIDE, 100, 20, 100, 15, hWnd, (HMENU)ProgramListTitleText, NULL, NULL);

        //Current and Voltage Display
        CreateWindow(L"STATIC", L"Board Power", SS_LEFT | WS_CHILD | SW_HIDE, 400, 5, 170, 100, hWnd, (HMENU)groupBoxTitle, NULL, NULL);
        CreateWindow(L"STATIC", NULL, SS_BLACKFRAME | WS_CHILD | SW_HIDE, 400, 20, 170, 100, hWnd, (HMENU)groupBox, NULL, NULL);
        CreateWindow(L"STATIC", L"---", SS_RIGHT | WS_CHILD | SW_HIDE, 420, 70, 80, 40, hWnd, (HMENU)DevCurText, NULL, NULL);
        CreateWindow(L"STATIC", L"mA", SS_LEFT | WS_CHILD | SW_HIDE, 510, 70, 50, 40, hWnd, (HMENU)mAText, NULL, NULL);
        CreateWindow(L"STATIC", L"--.--", SS_RIGHT | WS_CHILD | SW_HIDE, 420, 30, 100, 40, hWnd, (HMENU)DevVoltsText, NULL, NULL);
        CreateWindow(L"STATIC", L"V", SS_LEFT | WS_CHILD | SW_HIDE, 530, 30, 60, 50, hWnd, (HMENU)VText, NULL, NULL);

        //Motion stuff
        CreateWindowW(L"BUTTON", L"Run", WS_CHILD | SW_HIDE | BS_PUSHLIKE, 20, 280, 100, 30, hWnd, (HMENU)RunButton, NULL, NULL);
        CreateWindowW(L"BUTTON", L"Stop", WS_CHILD | SW_HIDE | BS_PUSHLIKE, 130, 280, 100, 30, hWnd, (HMENU)StopButton, NULL, NULL);
        CreateWindowW(L"BUTTON", L"Reset", WS_CHILD | SW_HIDE | BS_PUSHLIKE, 240, 280, 100, 30, hWnd, (HMENU)ResetButton, NULL, NULL);
        CreateWindowW(L"STATIC", L"PWM Freq:", WS_CHILD | SW_HIDE, 20, 30, 80, 20, hWnd, (HMENU)FreqStatic, NULL, NULL);
        CreateWindowW(L"STATIC", NULL, WS_CHILD | SW_HIDE, 90, 30, 40, 20, hWnd, (HMENU)FreqEdit, NULL, NULL);
        CreateWindowW(L"STATIC", L"Hz", WS_CHILD | SW_HIDE, 135, 30, 20, 20, hWnd, (HMENU)HzStatic, NULL, NULL);

        CreateWindow(L"STATIC", L"Position:", SS_LEFT | WS_CHILD | SW_HIDE, 200, 30, 60, 30, hWnd, (HMENU)QEIPositionTitle, NULL, NULL);
        CreateWindow(L"STATIC", NULL, SS_LEFT | WS_CHILD | SW_HIDE, 265, 30, 100, 30, hWnd, (HMENU)QEIPosition, NULL, NULL);

        CreateWindow(L"STATIC", L"Duty Cycle:", SS_LEFT | WS_CHILD | SW_HIDE, 20, 60, 100, 30, hWnd, (HMENU)DutyCycleText, NULL, NULL);
        CreateWindow(L"STATIC", L"---", SS_RIGHT | WS_CHILD | SW_HIDE, 95, 60, 20, 20, hWnd, (HMENU)DutyCycle, NULL, NULL);
        CreateWindow(L"STATIC", L"%", SS_LEFT | WS_CHILD | SW_HIDE, 120, 60, 20, 30, hWnd, (HMENU)DutyCycleUnits, NULL, NULL);

        CreateWindow(L"STATIC", L"Index:", SS_LEFT | WS_CHILD | SW_HIDE, 170, 60, 60, 30, hWnd, (HMENU)QEIIndexTxt, NULL, NULL);
        CreateWindow(L"STATIC", NULL, SS_LEFT | WS_CHILD | SW_HIDE, 215, 60, 50, 30, hWnd, (HMENU)QEIIndex, NULL, NULL);

        CreateWindow(L"STATIC", NULL, SS_BLACKFRAME | WS_CHILD | SW_HIDE, 20, 90, 230, 100, hWnd, (HMENU)updateGroupBox, NULL, NULL);

        CreateWindowW(L"EDIT", L"100", WS_CHILD | WS_BORDER | SW_HIDE, 90, 108, 50, 20, hWnd, (HMENU)SpeedEdit, NULL, NULL);
        CreateWindowW(L"STATIC", L"Speed:", WS_CHILD | SS_LEFT | SW_HIDE, 40, 110, 50, 20, hWnd, (HMENU)SpeedStatic, NULL, NULL);
        CreateWindowW(L"STATIC", L"Speed:", WS_CHILD | SS_LEFT | SW_HIDE, 275, 60, 50, 30, hWnd, (HMENU)CurrentSpeedStatic, NULL, NULL);
        CreateWindowW(L"STATIC", NULL, WS_CHILD | SS_LEFT | SW_HIDE, 320, 60, 30, 30, hWnd, (HMENU)CurrentSpeedTxt, NULL, NULL);
        CreateWindowW(L"STATIC", L"RPM", WS_CHILD | SS_LEFT | SW_HIDE, 355, 60, 30, 30, hWnd, (HMENU)CurrentRPMTxt, NULL, NULL);


        CreateWindowW(L"BUTTON", NULL, WS_CHILD | SW_HIDE | BS_AUTOCHECKBOX, 210, 108, 20, 20, hWnd, (HMENU)DirectionCheckBox, NULL, NULL);
        CreateWindowW(L"STATIC", L"Rev", WS_CHILD | SW_HIDE, 180, 110, 20, 20, hWnd, (HMENU)DirectionStatic, NULL, NULL);

        CreateWindowW(L"BUTTON", L"Update", WS_CHILD | SW_HIDE | BS_PUSHLIKE, 90, 150, 100, 30, hWnd, (HMENU)UpdateButton, NULL, NULL);

        CreateWindowW(L"STATIC", L"Control:", WS_CHILD | SW_HIDE, 20, 5, 60, 20, hWnd, (HMENU)ControlByteTxt, NULL, NULL);
        CreateWindowW(L"STATIC", L"Status:", WS_CHILD | SW_HIDE, 200, 5, 60, 20, hWnd, (HMENU)StatusByteTxt, NULL, NULL);
        CreateWindowW(L"STATIC", L"00000000", WS_CHILD | SW_HIDE, 80, 5, 60, 20, hWnd, (HMENU)ControlByte, NULL, NULL);
        CreateWindowW(L"STATIC", L"00000000", WS_CHILD | SW_HIDE, 255, 5, 60, 20, hWnd, (HMENU)StatusByte, NULL, NULL);

        //CreateWindowW(L"STATIC", L"Run Seq", WS_CHILD | SW_HIDE, 280, 110, 50, 20, hWnd, (HMENU)RunSeqStatic, NULL, NULL);
        CreateWindowW(L"BUTTON", L"Run SEQ", WS_CHILD | SW_HIDE | BS_PUSHLIKE, 350, 280, 100, 30, hWnd, (HMENU)RunSeqButton, NULL, NULL);

        //Sequence buttons
        CreateWindowW(L"STATIC", L"Seq #", WS_CHILD | SW_HIDE, 25, 210, 40, 20, hWnd, (HMENU)SeqNumStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"1", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 20, 230, 50, 20, hWnd, (HMENU)SeqNumEdit, NULL, NULL);

        CreateWindowW(L"STATIC", L"Dir", WS_CHILD | SW_HIDE, 95, 210, 30, 20, hWnd, (HMENU)SeqDirStatic, NULL, NULL);
        CreateWindowW(WC_COMBOBOX, TEXT("REV"), CBS_DROPDOWN | CBS_HASSTRINGS | WS_CHILD | SW_HIDE | SS_CENTER,
            80, 230, 50, 120, hWnd, (HMENU)SeqDirCombo, NULL, NULL);

        const TCHAR* str;
        str = TEXT("FOR");
        SendMessage(GetDlgItem(hWnd, SeqDirCombo), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(str));

        str = TEXT("REV");
        SendMessage(GetDlgItem(hWnd, SeqDirCombo), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(str));

        SendMessage(GetDlgItem(hWnd, SeqDirCombo), CB_SETCURSEL, (WPARAM)0, (LPARAM)0);

        CreateWindowW(L"STATIC", L"Acc", WS_CHILD | SW_HIDE, 150, 210, 30, 20, hWnd, (HMENU)SeqAccStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 140, 230, 50, 20, hWnd, (HMENU)SeqAccEdit, NULL, NULL);

        CreateWindowW(L"STATIC", L"Speed", WS_CHILD | SW_HIDE, 205, 210, 40, 20, hWnd, (HMENU)SeqSpdStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 200, 230, 50, 20, hWnd, (HMENU)SeqSpdEdit, NULL, NULL);

        CreateWindowW(L"STATIC", L"Dec", WS_CHILD | SW_HIDE, 275, 210, 30, 20, hWnd, (HMENU)SeqDecStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 260, 230, 50, 20, hWnd, (HMENU)SeqDecEdit, NULL, NULL);

        CreateWindowW(L"STATIC", L"Run Dist", WS_CHILD | SW_HIDE, 330, 210, 80, 20, hWnd, (HMENU)SeqDistStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 320, 230, 80, 20, hWnd, (HMENU)SeqDistEdit, NULL, NULL);

        CreateWindowW(L"STATIC", L"Stop Dist", WS_CHILD | SW_HIDE, 420, 210, 80, 20, hWnd, (HMENU)SeqStopStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 410, 230, 80, 20, hWnd, (HMENU)SeqStopEdit, NULL, NULL);

        CreateWindowW(L"STATIC", L"Loop", WS_CHILD | SW_HIDE, 500, 160, 30, 20, hWnd, (HMENU)SeqLoopStatic, NULL, NULL);
        CreateWindowW(L"BUTTON", NULL, WS_CHILD | SW_HIDE | SS_CENTER | BS_CHECKBOX, 500, 180, 50, 20, hWnd, (HMENU)SeqLoopCheckBox, NULL, NULL);
        
        CreateWindowW(L"BUTTON", L"Save", WS_CHILD | SW_HIDE | BS_PUSHLIKE, 460, 280, 100, 30, hWnd, (HMENU)SeqSaveButton, NULL, NULL);

        CreateWindowW(L"STATIC", L"Delay", WS_CHILD | SW_HIDE, 502, 210, 80, 20, hWnd, (HMENU)SeqDelayStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 500, 230, 40, 20, hWnd, (HMENU)SeqDelayEdit, NULL, NULL);
        
        CreateWindowW(L"STATIC", L"Total", WS_CHILD | SW_HIDE, 547, 210, 80, 20, hWnd, (HMENU)SeqTotalStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 550, 230, 30, 20, hWnd, (HMENU)SeqTotalEdit, NULL, NULL);
        
        //Peripheral Commands Section
        CreateWindow(L"LISTBOX", NULL, WS_CHILD | WS_BORDER | SW_HIDE | WS_VSCROLL | LBS_NOTIFY, 20, 50, 200, 255, hWnd, (HMENU)IDC_Peripherals_LISTBOX, NULL, NULL);
        CreateWindowW(L"STATIC", L"Board Address", WS_CHILD | SW_HIDE, 250, 50, 100, 20, hWnd, (HMENU)BoardAddressStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 250, 70, 50, 20, hWnd, (HMENU)BoardAddressEdit, NULL, NULL);
        CreateWindowW(L"STATIC", L"Board Data Byte", WS_CHILD | SW_HIDE, 250, 100, 120, 20, hWnd, (HMENU)BoardDataStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 250, 120, 50, 20, hWnd, (HMENU)BoardDataEdit, NULL, NULL);
        CreateWindowW(L"STATIC", L"Board Data Byte 2", WS_CHILD | SW_HIDE, 250, 150, 120, 20, hWnd, (HMENU)BoardData2Static, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | SW_HIDE | SS_CENTER, 250, 170, 50, 20, hWnd, (HMENU)BoardData2Edit, NULL, NULL);

        CreateWindowW(L"STATIC", L"Sine Wave", WS_CHILD | SW_HIDE, 280, 200, 120, 20, hWnd, (HMENU)SineWaveStatic, NULL, NULL);
        CreateWindowW(L"BUTTON", NULL, WS_CHILD | SW_HIDE | BS_AUTOCHECKBOX, 250, 200, 20, 20, hWnd, (HMENU)SineWaveCheckBox, NULL, NULL);

        CreateWindowW(L"STATIC", L"Audio Waveform", WS_CHILD | SW_HIDE, 280, 230, 120, 20, hWnd, (HMENU)AudioWaveStatic, NULL, NULL);
        CreateWindowW(L"BUTTON", NULL, WS_CHILD | SW_HIDE | BS_AUTOCHECKBOX, 250, 230, 20, 20, hWnd, (HMENU)AudioWaveCheckBox, NULL, NULL);

        CreateWindowW(L"STATIC", L"Triangle Waveform", WS_CHILD | SW_HIDE, 280, 260, 120, 20, hWnd, (HMENU)TriangleWaveStatic, NULL, NULL);
        CreateWindowW(L"BUTTON", NULL, WS_CHILD | SW_HIDE | BS_AUTOCHECKBOX, 250, 260, 20, 20, hWnd, (HMENU)TriangleWaveCheckBox, NULL, NULL);

        CreateWindowW(L"STATIC", L"Composite Video", WS_CHILD | SW_HIDE, 280, 290, 120, 20, hWnd, (HMENU)CompositeVideoStatic, NULL, NULL);
        CreateWindowW(L"BUTTON", NULL, WS_CHILD | SW_HIDE | BS_AUTOCHECKBOX, 250, 290, 20, 20, hWnd, (HMENU)CompositeVideoCheckBox, NULL, NULL);

        //Menu item is disabled until connected
        EnableMenuItem(GetMenu(hWnd), ID_PROGRAMS, MF_BYCOMMAND | MF_GRAYED);

        SendMessage(GetDlgItem(hWnd, DirectionCheckBox), BM_SETCHECK, BST_UNCHECKED, 0);

        //Load Command List into ListBox
        for (int i = 0; i < ARRAYSIZE(ProgramList); i++)
        {
            SendMessage(GetDlgItem(hWnd, IDC_LISTBOX), LB_ADDSTRING, NULL, (LPARAM)ProgramList[i].progName);
            // Set the array index of the Listbox as item data.
            // This enables us to retrieve the item from the array
            // even after the items are sorted by the list box.
            SendMessage(GetDlgItem(hWnd, IDC_LISTBOX), LB_SETITEMDATA, NULL, (LPARAM)i);
        }

        //Load Peripheral Commands List into ListBox
        for (int i = 0; i < ARRAYSIZE(PeripheralCommandsList); i++)
        {
            SendMessage(GetDlgItem(hWnd, IDC_Peripherals_LISTBOX), LB_ADDSTRING, NULL, (LPARAM)PeripheralCommandsList[i].progName);
            // Set the array index of the Listbox as item data.
            // This enables us to retrieve the item from the array
            // even after the items are sorted by the list box.
            SendMessage(GetDlgItem(hWnd, IDC_Peripherals_LISTBOX), LB_SETITEMDATA, NULL, (LPARAM)i);
        }

    }
    break;
    case WM_INITDIALOG:
    {

    }
    break;
    case WM_VSCROLL:

        break;
    
    case WM_PAINT:
        {
            dc = BeginPaint(hWnd, &ps);
 
            SendMessage(GetDlgItem(hWnd, groupBoxTitle), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, groupBox), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, IDC_LISTBOX), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, ProgramListTitleText), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, DevCurText), WM_SETFONT, (WPARAM)BigFont, TRUE);
            SendMessage(GetDlgItem(hWnd, mAText), WM_SETFONT, (WPARAM)BigFont, TRUE);
            SendMessage(GetDlgItem(hWnd, DevVoltsText), WM_SETFONT, (WPARAM)BigFont, TRUE);
            SendMessage(GetDlgItem(hWnd, VText), WM_SETFONT, (WPARAM)BigFont, TRUE);

            SendMessage(GetDlgItem(hWnd, RunButton), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, StopButton), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, ResetButton), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, FreqStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, FreqEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, HzStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, QEIPositionTitle), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, QEIPosition), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, QEIIndexTxt), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, QEIIndex), WM_SETFONT, (WPARAM)hFont, TRUE);

            SendMessage(GetDlgItem(hWnd, DutyCycle), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, DutyCycleText), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, DutyCycleUnits), WM_SETFONT, (WPARAM)hFont, TRUE);
            
            SendMessage(GetDlgItem(hWnd, SpeedEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SpeedStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
 
            SendMessage(GetDlgItem(hWnd, DirectionCheckBox), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, DirectionStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, UpdateButton), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, CurrentSpeedStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, CurrentSpeedTxt), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, CurrentRPMTxt), WM_SETFONT, (WPARAM)hFont, TRUE);

            SendMessage(GetDlgItem(hWnd, ControlByteTxt), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, StatusByteTxt), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, ControlByte), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, StatusByte), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, RunSeqButton), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqNumEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqDirEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqAccEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqSpdEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqNumStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqAccStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqSpdStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqDirStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqDirCombo), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqDecStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqDecEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqDistStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqDistEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqLoopStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqLoopCheckBox), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqSaveButton), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqStopEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqStopStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqDelayEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqDelayStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqTotalEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SeqTotalStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SplashStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, IDC_Peripherals_LISTBOX), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, BoardAddressStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, BoardAddressEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, BoardDataStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, BoardDataEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, BoardData2Static), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, BoardData2Edit), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, SineWaveStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, AudioWaveStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, TriangleWaveStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
            SendMessage(GetDlgItem(hWnd, CompositeVideoStatic), WM_SETFONT, (WPARAM)hFont, TRUE);

            ShowWindow(GetDlgItem(hWnd, groupBox), SW_SHOW);
            ShowWindow(GetDlgItem(hWnd, groupBoxTitle), SW_SHOW);
            ShowWindow(GetDlgItem(hWnd, mAText), SW_SHOW);
            ShowWindow(GetDlgItem(hWnd, VText), SW_SHOW);
            ShowWindow(GetDlgItem(hWnd, DevVoltsText), SW_SHOW);
            ShowWindow(GetDlgItem(hWnd, DevCurText), SW_SHOW);

            //SendMessage(GetDlgItem(hWnd, SeqDirCombo), (UINT)CB_ADDSTRING, NULL, 'FOR');

            EndPaint(hWnd, &ps);

            UpdateWindow(hWnd);
        }
        break;

    case WM_CLOSE:
        if (Connection == isConnected)
        {
            SendDisconnected(hWnd);
        }

        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        if (Connection == isConnected)
        {
            SendDisconnected(hWnd);
        }

        KillTimer(hWnd, MainTimer);
        KillTimer(hWnd, SpeedTimer);
        DeleteObject(hbrBkgnd);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);

    }
    return 0;
}

void SendDisconnected(HWND hWnd)
{
    ULONG bytesSent;
    unsigned char outBuffer[64] = { 0 };

    //the command
    outBuffer[0] = 0;

    //the data
    outBuffer[1] = 5;

    bool writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);
 }

//Message handler for SendByte DialogBox
INT_PTR CALLBACK SendByte(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    ULONG bytesSent;

    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        CreateWindowW(L"STATIC", L"LED Port:", WS_CHILD | WS_VISIBLE, 15, 10, 150, 20, hDlg, (HMENU)SendByteStatic, NULL, NULL);
        CreateWindowW(L"EDIT", L"0", WS_CHILD | WS_BORDER | WS_VISIBLE | ES_NUMBER, 90, 8, 50, 20, hDlg, (HMENU)SendByteEdit, NULL, NULL);
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        if (LOWORD(wParam) == IDOK)
        {
            outBuffer[1] = GetDlgItemInt(hDlg, SendByteEdit, 0, 0);

            bool writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

            if (writeStatus == false)
            {
                Error = GetLastError();
                _itow_s(Error, ErrorBuffer, 10);
                MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

                return 0;
            }

            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    case WM_PAINT:
        SendMessage(GetDlgItem(hDlg, SendByteStatic), WM_SETFONT, (WPARAM)hFont, TRUE);
        SendMessage(GetDlgItem(hDlg, SendByteEdit), WM_SETFONT, (WPARAM)hFont, TRUE);
        dc = GetDC(hDlg);
        SelectObject(dc, hFont);
        EndPaint(hDlg, &ps);

        break;
    }
    return (INT_PTR)FALSE;
}

//Message handler for About DialogBox
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
         return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}


void FindMainBrain(HWND hWnd)
{
    dc = GetDC(hWnd);

    //SetupDiGetClassDevs - Get a list of present interface class devices
    DeviceInfoTable = SetupDiGetClassDevs(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

    if (DeviceInfoTable == INVALID_HANDLE_VALUE)
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(NULL, L"USB SetupDiGetClassDevs\r\nInvalid Handle", ErrorBuffer, MB_OK);

         return;
    }

    //Set the font
    SelectObject(dc, hFont);

    //Display GUID since we passed SetupDiGetClassDevs OK
 /*   LPCWSTR c = L"Our GUID:";
    wchar_t buffer[256];
    int rt = StringFromGUID2(InterfaceClassGuid, buffer, _countof(buffer));

    if (rt > 0)
    {
        //TextOut(dc, hpos, vpos, c, _tcslen(c));
        //vpos = vpos + 20;
        //TextOut(dc, hpos, vpos, (LPCWSTR)buffer, _tcslen(buffer));
        //vpos = vpos + 40;
    }
    */

    InterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    c = L"Devices:";
    TextOut(dc, hpos, vpos, c, (int)_tcslen(c));
    vpos = vpos + 20;

    //buffer for the index conversion to string
    wchar_t index_buffer[20] = { 0 };

    InterfaceIndex = 0;

    while (SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &InterfaceClassGuid, InterfaceIndex, InterfaceDataStructure))
    {
        wchar_t buffer[256];
        int rt = StringFromGUID2(InterfaceDataStructure->InterfaceClassGuid, buffer, _countof(buffer));
        
        //convert index to string
        _itow_s(InterfaceIndex, index_buffer, 10);

        if (rt)
        {
            c = L"Index";
            TextOut(dc, hpos, vpos, c, (int)_tcslen(c));
            hpos = hpos + 40;

            TextOut(dc, hpos, vpos, index_buffer, (int)_tcslen(index_buffer));
            hpos = hpos + 10;

            TextOut(dc, hpos, vpos, (LPCWSTR)buffer, (int)_tcslen(buffer));
            vpos = vpos + 20;
            hpos = hpos - 50;
        }

        InterfaceIndex++;
    }

    vpos = vpos + 20;
    Error = GetLastError();
    //Check to see if the list has been completely read
    if (Error == ERROR_NO_MORE_ITEMS)
    {
        //but if index is 0 that means no items were in the list
        if (!InterfaceIndex)
        {
            LPCWSTR c = L"No matching interfaces found!";
            TextOut(dc, hpos, vpos, c, (int)_tcslen(c));
            vpos = vpos + 20;
            SetupDiDestroyDeviceInfoList(DeviceInfoTable);

            return;
        }
    }
    //Else some other kind of unknown error ocurred...
    else
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(NULL, L"SetupDiEnumDeviceInterfaces\r\nUnknown error", ErrorBuffer, MB_OK);

        return;
    }

    //adjust for last increment
    InterfaceIndex = InterfaceIndex - 1;

    if (InterfaceIndex > 0)
    {
        c = L"Enter the device Index to connect ...";
        TextOut(dc, hpos, vpos, c, (int)_tcslen(c));
        vpos = vpos + 20;
        DeviceIndex = -1;
    }
    else
    {
        c = L"Press any key to connect";
        TextOut(dc, hpos, vpos, c, (int)_tcslen(c));
        vpos = vpos + 20;
    }

}

void SelectDevice(HWND hWnd, BYTE DeviceIndex)
{   
    vpos = 10;
    LPCWSTR c = L"MainBrain MZ";
    TextOut(dc, hpos, vpos, c, (int)_tcslen(c));
    vpos = vpos + 20;

    //Now retrieve the hardware ID from the registry.  The hardware ID contains the VID and PID, which we will then 
    //check to see if it is the correct device or not.
        //Initialize an appropriate SP_DEVINFO_DATA structure.  We need this structure for SetupDiGetDeviceRegistryProperty().
    SP_DEVINFO_DATA DevInfoData;

    DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    if (!SetupDiEnumDeviceInfo(DeviceInfoTable, DeviceIndex, &DevInfoData))
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(NULL, L"SetupDiEnumDeviceInfo\r\nSelect Listed Device", ErrorBuffer, MB_OK);

        SetupDiDestroyDeviceInfoList(DeviceInfoTable);
        return;
    }

    //Lets look at the Device Instance Handle
    c = L"Device Node:";
    TextOut(dc, hpos, vpos, c, (int)_tcslen(c));
    hpos = hpos + 100;

    _itow_s(DevInfoData.DevInst, MyBuffer, 10);
    TextOut(dc, hpos, vpos, MyBuffer, (int)_tcslen(MyBuffer));
    vpos = vpos + 20;
    hpos = hpos - 100;


    //First query for the size of the hardware ID, so we can know how big a buffer to allocate for the data.
    //if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_CONFIGFLAGS, &RegDataType, (PBYTE)&ConfigFlags, sizeof(ConfigFlags), NULL)
    DWORD requested_size;
    DWORD dwRegType;

    SetupDiGetDeviceRegistryProperty(DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &dwRegType, NULL, 0, &requested_size);

    //Allocate a buffer for the hardware ID.
    PBYTE PropertyValueBuffer;

    PropertyValueBuffer = (BYTE*)malloc(requested_size);

    //if null, error, couldn't allocate enough memory
    if (PropertyValueBuffer == NULL)
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(NULL, L"SetupDiGetDeviceRegistryProperty\r\nCouldn't Allocate Enough Memory", ErrorBuffer, MB_OK);

         return;
    }

    //Retrieve the hardware IDs for the current device we are looking at.  PropertyValueBuffer gets filled with a 
    //REG_MULTI_SZ (array of null terminated strings).  To find a device, we only care about the very first string in the
    //buffer, which will be the "device ID".  The device ID is a string which contains the VID and PID, in the example 
    //format "Vid_04d8&Pid_003f".
    SetupDiGetDeviceRegistryProperty(DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &dwRegType, PropertyValueBuffer, requested_size, NULL);

    //Hardware ID
    c = (LPCWSTR)PropertyValueBuffer;
    TextOut(dc, hpos, vpos, c, (int)_tcslen(c));
    vpos = vpos + 20;

    SetupDiGetDeviceRegistryProperty(DeviceInfoTable, &DevInfoData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, &dwRegType, PropertyValueBuffer, requested_size, NULL);

    //Device Object Name
    c = (LPCWSTR)PropertyValueBuffer;
    TextOut(dc, hpos, vpos, c, (int)_tcslen(c));
    vpos = vpos + 20;

    std::free(PropertyValueBuffer);

    //Open WinUSB interface handle now.
    //In order to do this, we will need the actual device path first.
    //We can get the path by calling SetupDiGetDeviceInterfaceDetail(), however, we have to call this function twice:  The first
    //time to get the size of the required structure/buffer to hold the detailed interface data, then a second time to actually 
    //get the structure (after we have allocated enough memory for the structure.)
    DetailedInterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

    DWORD StructureSize = 0;

    //First call populates "StructureSize" with the correct value
    SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, NULL, NULL, &StructureSize, NULL);

    //Allocate enough memory
    DetailedInterfaceDataStructure = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(malloc(StructureSize));

    //if null, error, couldn't allocate enough memory
    if (DetailedInterfaceDataStructure == NULL)
    {
        //Can't really recover from this situation, just exit instead.
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(NULL, L"DetailedInterfaceDataStructure\r\nCouldn't Allocate Enough Memory", ErrorBuffer, MB_OK);

        return;
    }

    DetailedInterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

    //Specify the Index/Node to connect to
    SetupDiEnumDeviceInterfaces(DeviceInfoTable, NULL, &InterfaceClassGuid, DeviceIndex, InterfaceDataStructure);


    //Now call SetupDiGetDeviceInterfaceDetail() again to get the data
    SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, DetailedInterfaceDataStructure, StructureSize, NULL, NULL);

    //Device Path
    c = (LPCWSTR)DetailedInterfaceDataStructure->DevicePath;
    //TextOut(dc, hpos, vpos, c, (int)_tcslen(c));
    vpos = vpos + 20;

    //We now have the proper device path, and we can finally open a device handle to the device.
    //WinUSB requires the device handle to be opened with the FILE_FLAG_OVERLAPPED attribute.
    SetupDiDestroyDeviceInfoList(DeviceInfoTable);

    //WinUSB requires the device handle to be opened with the FILE_FLAG_OVERLAPPED attribute.
    MyDeviceHandle = CreateFile((DetailedInterfaceDataStructure->DevicePath), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

    Error = GetLastError();
    if (Error > 0)
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(NULL, L"CreateFile()\r\nCreate Device Handle", ErrorBuffer, MB_OK);

        return;
    }

    //Now get the WinUSB interface handle by calling WinUsb_Initialize() and providing the device handle.    
    if (WinUsb_Initialize(MyDeviceHandle, &MyWinUSBInterfaceHandle) == false)
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(NULL, L"WinUsb_Initialize()", ErrorBuffer, MB_OK);

        return;
    }

    //Set connection to connected
    Connection = isConnected;

    //Notify Device we are connected
    ULONG bytesSent;

    //the command
    outBuffer[0] = 0;

    //the data
    outBuffer[1] = 2;

    bool writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

    if (writeStatus == false)
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

        //return;
    }

    //Send the current time to the device
    SetTime(hWnd);

    //Grey out the 'Connect' menu item since we are connected
    EnableMenuItem(GetMenu(hWnd), ID_CONNECT, MF_BYCOMMAND | MF_GRAYED);

    //Enable the 'Utilities' menu item
    EnableMenuItem(GetMenu(hWnd), ID_PROGRAMS, MF_BYCOMMAND | MF_ENABLED);

    //show the splash message
    ShowWindow(GetDlgItem(hWnd, SplashStatic), SW_SHOW);

    InvalidateRect(hWnd, NULL, TRUE);
    UpdateWindow(hWnd);

    //We are now ready to exchange data with our USB device

    return;
}

//sends the listbox index to the device
void SendCMD(HWND hWnd, uint8_t lbIndex)
{
    ULONG bytesSent;
    bool writeStatus = false;
    bool readStatus = false;
    unsigned char outBuffer[64] = { 0 };

    isBusy = true;

    if (Connection != isConnected)
    {
        MessageBoxW(NULL, L"Device is not connected ...", L"Connection Status", MB_OK);

        return;
    }

    //This is the byte command for the device
    lbIndex = lbIndex + 1;

    //Comm Check
    if (lbIndex == 1) 
    {
        outBuffer[0] = 0x01;

        writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

        if (writeStatus == false)
        {
            Error = GetLastError();
            _itow_s(Error, ErrorBuffer, 10);
            MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

            return;
        }

        readStatus = WinUsb_ReadPipe(MyWinUSBInterfaceHandle, 0x82, inBuffer, 64, &bytesSent, NULL);

        if (readStatus == false)
        {
            Error = GetLastError();
            _itow_s(Error, ErrorBuffer, 10);
            MessageBoxW(NULL, L"WinUsb_ReadPipe() Failed!", ErrorBuffer, MB_ICONERROR);

            return;
        }

        if (inBuffer[0] == 0x55)
        {
            MessageBoxW(hWnd, L"Success!\r\nDevice is ready", L"Command 0 - Test Connection", MB_OK | MB_ICONINFORMATION);
        }
        else
        {
            MessageBoxW(hWnd, L"Fail!\r\nDevice did not return 0x55 ...", L"Command 0 - Test Connection", MB_OK | MB_ICONERROR);
        }
    }
 
    //command 0x02 - Write to LED Port
    if (lbIndex == 2)
    {
        DialogBox(hInst, MAKEINTRESOURCE(IDD_SENDBYTE), hWnd, SendByte);
    }

    //command 0x03 - Reset Device
    if (lbIndex == 3)
    {
        int msgboxID = MessageBoxW(NULL, L"Warning: This will close this application!", L"Test", MB_OKCANCEL | MB_ICONINFORMATION);

        if (msgboxID == IDCANCEL)
        {
            return;
        }

        outBuffer[0] = 0x04;

        writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

        if (writeStatus == false)
        {
            Error = GetLastError();
            _itow_s(Error, ErrorBuffer, 10);
            MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

            return;
        }

        KillTimer(hWnd, MainTimer);
        KillTimer(hWnd, SpeedTimer);
        DeleteObject(hbrBkgnd);
        PostQuitMessage(0);
     }

    //command 0x04 - Build Motion
    if (lbIndex == 4)
    {      
        ShowWindow(GetDlgItem(hWnd, IDC_LISTBOX), SW_HIDE);
        ShowWindow(GetDlgItem(hWnd, ProgramListTitleText), SW_HIDE);

        ShowWindow(GetDlgItem(hWnd, RunButton), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, StopButton), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, ResetButton), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, FreqStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, FreqEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, HzStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, UpdateButton), SW_SHOW);

        ShowWindow(GetDlgItem(hWnd, QEIPositionTitle), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, QEIPosition), SW_SHOW);

        ShowWindow(GetDlgItem(hWnd, DutyCycle), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, DutyCycleText), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, DutyCycleUnits), SW_SHOW);

        ShowWindow(GetDlgItem(hWnd, QEIIndexTxt), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, QEIIndex), SW_SHOW);
        
        ShowWindow(GetDlgItem(hWnd, SpeedEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SpeedStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, CurrentSpeedStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, CurrentSpeedTxt), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, CurrentRPMTxt), SW_SHOW);

        ShowWindow(GetDlgItem(hWnd, DirectionCheckBox), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, DirectionStatic), SW_SHOW);

        ShowWindow(GetDlgItem(hWnd, ControlByteTxt), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, StatusByteTxt), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, ControlByte), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, StatusByte), SW_SHOW);

        ShowWindow(GetDlgItem(hWnd, RunSeqButton), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqSaveButton), SW_SHOW);

        ShowWindow(GetDlgItem(hWnd, updateGroupBox), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqNumEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqDirEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqAccEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqSpdEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqNumStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqAccStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqSpdStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqDirStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqDirCombo), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqDecEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqDecStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqDistEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqDistStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqLoopCheckBox), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqLoopStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqStopEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqStopStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqDelayEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqDelayStatic), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqTotalEdit), SW_SHOW);
        ShowWindow(GetDlgItem(hWnd, SeqTotalStatic), SW_SHOW);

        InvalidateRect(hWnd, NULL, TRUE);
        UpdateWindow(hWnd);
        
        outBuffer[0] = 0x05;

        writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

        if (writeStatus == false)
        {
            Error = GetLastError();
            _itow_s(Error, ErrorBuffer, 10);
            MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

            return;
        }

        //Get the current value for PWM frequency
        wsprintfW(buf, L"%ld", PWM_Freq);
        SetWindowTextW(GetDlgItem(hWnd, FreqEdit), buf);

        //Load the Sequence data and populate the editboxes
        //Acceleration
        //Convert the numerical value to a string
        wsprintfW(buf, L"%ld", 20);
        // Set the text in the edit box
        SetWindowTextW(GetDlgItem(hWnd, SeqAccEdit), buf);

       //Speed
       //Convert the numerical value to a string
        wsprintfW(buf, L"%ld", 80);
        // Set the text in the edit box
        SetWindowTextW(GetDlgItem(hWnd, SeqSpdEdit), buf);

       //Deceleration
       //Convert the numerical value to a string
        wsprintfW(buf, L"%ld", 50);
        // Set the text in the edit box
        SetWindowTextW(GetDlgItem(hWnd, SeqDecEdit), buf);

        //Distance
        //Get the 4 bytes
        //union byte2dword distance;

        //distance.mByte[0] = inBuffer[27];
        //distance.mByte[1] = inBuffer[28];
        //distance.mByte[2] = inBuffer[29];
        //distance.mByte[3] = inBuffer[30];

        //Convert the numerical value to a string
        wsprintfW(buf, L"%ld", 200000);

        //Set the Initial Run Distance
        SetWindowTextW(GetDlgItem(hWnd, SeqDistEdit), buf);

        //Stop Distance
        //union byte2dword stopDistance;

        //stopDistance.mByte[0] = inBuffer[33];
        //stopDistance.mByte[1] = inBuffer[34];
        //stopDistance.mByte[2] = inBuffer[35];
        //stopDistance.mByte[3] = inBuffer[36];
        // 
        //Set the Initial Stop Distance
       //Convert the numerical value to a string
        wsprintfW(buf, L"%ld", 680000);
        SetWindowTextW(GetDlgItem(hWnd, SeqStopEdit), buf);

        //Set the Initial Total number of sequences to run
        wsprintfW(buf, L"%ld", 1);
        SetWindowTextW(GetDlgItem(hWnd, SeqTotalEdit), buf);

        //Set the Initial Delay between sequences
        wsprintfW(buf, L"%ld", 10);
        SetWindowTextW(GetDlgItem(hWnd, SeqDelayEdit), buf);
    }

    //command 0x05 - Board Comm Check
    if (lbIndex == 5)
    {
        outBuffer[0] = 0x07;

        writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

        if (writeStatus == false)
        {
            Error = GetLastError();
            _itow_s(Error, ErrorBuffer, 10);
            MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

            return;
        }

        readStatus = WinUsb_ReadPipe(MyWinUSBInterfaceHandle, 0x82, inBuffer, 64, &bytesSent, NULL);

        if (readStatus == false)
        {
            Error = GetLastError();
            _itow_s(Error, ErrorBuffer, 10);
            MessageBoxW(NULL, L"WinUsb_ReadPipe() Failed!", ErrorBuffer, MB_ICONERROR);

            return;
        }

        if (inBuffer[0] == 38)
        {
            _itow_s(inBuffer[0], ErrorBuffer, 10);
            MessageBoxW(hWnd, L"Success!\r\nBoard is ready", ErrorBuffer, MB_OK | MB_ICONINFORMATION);
        }
        else
        {
            _itow_s(inBuffer[0], ErrorBuffer, 10);
            MessageBoxW(hWnd, L"Comm Check Failed!", ErrorBuffer, MB_OK | MB_ICONERROR);
        }
    }

    //command 0x06 - Flash Utilities
    if (lbIndex == 6)
    {
        ShowWindow(GetDlgItem(hWnd, IDC_LISTBOX), SW_HIDE);
        ShowWindow(GetDlgItem(hWnd, ProgramListTitleText), SW_HIDE);
        MessageBoxW(hWnd, L"Flash Utilities", ErrorBuffer, MB_OK | MB_ICONERROR);
    }

    //command 0x07 - SRAM Utilities
    if (lbIndex == 7)
    {
        ShowWindow(GetDlgItem(hWnd, IDC_LISTBOX), SW_HIDE);
        ShowWindow(GetDlgItem(hWnd, ProgramListTitleText), SW_HIDE);
        MessageBoxW(hWnd, L"SRAM Utilities", ErrorBuffer, MB_OK | MB_ICONERROR);
    }


    //command 0x08 - Peripheral Commands
    if (lbIndex == 8)
    {
        ShowWindow(GetDlgItem(hWnd, IDC_LISTBOX), SW_HIDE);
        ShowWindow(GetDlgItem(hWnd, ProgramListTitleText), SW_HIDE);
        ShowWindow(GetDlgItem(hWnd, IDC_Peripherals_LISTBOX), SW_SHOW);
        
    }


    /******************************************************************
                        Peripherals Utility
    *******************************************************************/
    wchar_t theBuffer[30];
    uint8_t boardAddress = 0;
    uint8_t boardData[64] = { 0 };
    wchar_t* endPtr;
    uint16_t myWord;

    //Command 0 - Send Data Byte to Board
    if (lbIndex == 101)
    {
        //Get the Address EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardAddressEdit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        DataOutBuffer[1] = (uint8_t)wcstol(theBuffer, &endPtr, 10);

        //Get the DataByte EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardDataEdit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        DataOutBuffer[2] = (uint8_t)wcstol(theBuffer, &endPtr, 10);

        //Command
        DataOutBuffer[0] = 0x65;

        //Send the data
        USBbyteOut();
        
    }

    //Build Board List
    if (lbIndex == 102)
    {
        MessageBoxW(hWnd, L"Build Board List", L"Command", MB_OK | MB_ICONERROR);
        //USBbyteOut(0x66, 2, 0x78);
    }

    //Set DAC
    if (lbIndex == 103)
    {
        //Get the Address EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardAddressEdit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        DataOutBuffer[1] = (uint8_t)wcstol(theBuffer, &endPtr, 10);

        //Get the DataByte EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardDataEdit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        myWord = (uint16_t)wcstol(theBuffer, &endPtr, 10);
        DataOutBuffer[3] = myWord >> 8;
        DataOutBuffer[2] = myWord & 0xff;

        //Command
        DataOutBuffer[0] = 0x67;

        //Send the data
        USBbyteOut();
    }

    //Set PWM
    if (lbIndex == 104)
    {
        //Get the Address EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardAddressEdit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        DataOutBuffer[1] = (uint8_t)wcstol(theBuffer, &endPtr, 10);

        //Get the Period EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardDataEdit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        myWord = (uint16_t)wcstol(theBuffer, &endPtr, 10);
        DataOutBuffer[3] = myWord >> 8;
        DataOutBuffer[2] = myWord & 0xff;

        //Get the Duty Cycle EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardData2Edit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        myWord = (uint16_t)wcstol(theBuffer, &endPtr, 10);
        DataOutBuffer[5] = myWord >> 8;
        DataOutBuffer[4] = myWord & 0xff;

        //Command
        DataOutBuffer[0] = 0x68;

        //Send the data
        USBbyteOut();
    }
    //DAC - Waveforms
    if (lbIndex == 105) //0x69
    {
        //Get the Address EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardAddressEdit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        DataOutBuffer[1] = (uint8_t)wcstol(theBuffer, &endPtr, 10);

        //Get the DataByte EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardDataEdit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        myWord = (uint16_t)wcstol(theBuffer, &endPtr, 10);
        DataOutBuffer[3] = myWord >> 8;
        DataOutBuffer[2] = myWord & 0xff;

        //Get the Duty Cycle EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardData2Edit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        myWord = (uint16_t)wcstol(theBuffer, &endPtr, 10);
        DataOutBuffer[5] = myWord >> 8;
        DataOutBuffer[4] = myWord & 0xff;

        //Sine Wave CheckBox
        if (SendMessage(GetDlgItem(hWnd, SineWaveCheckBox), BM_GETCHECK, 0, 0) == BST_CHECKED)
        {
            //Checked - bit 0           
            DataOutBuffer[6] |= (1 << 0);
        }
        else
        {
            //Unchecked
            DataOutBuffer[6] &= ~(1 << 0);
        }

        //Audio Wave CheckBox
        if (SendMessage(GetDlgItem(hWnd, AudioWaveCheckBox), BM_GETCHECK, 0, 0) == BST_CHECKED)
        {
            //Checked - bit 1;
            DataOutBuffer[6] |= (1 << 1);
        }
        else
        {
            //Unchecked
            DataOutBuffer[6] &= ~(1 << 1);
        }

        //Triangle Wave CheckBox
        if (SendMessage(GetDlgItem(hWnd, TriangleWaveCheckBox), BM_GETCHECK, 0, 0) == BST_CHECKED)
        {
            //Checked - bit 2;
            DataOutBuffer[6] |= (1 << 2);
        }
        else
        {
            //Unchecked
            DataOutBuffer[6] &= ~(1 << 2);
        }

        //Composite Video CheckBox
        if (SendMessage(GetDlgItem(hWnd, CompositeVideoCheckBox), BM_GETCHECK, 0, 0) == BST_CHECKED)
        {
            //Checked - bit 3;
            DataOutBuffer[6] |= (1 << 3);
        }
        else
        {
            //Unchecked
            DataOutBuffer[6] &= ~(1 << 3);
        }


        //Command
        DataOutBuffer[0] = 0x69;

        //Send the data
        USBbyteOut();
    }

    //Read ADC
    if (lbIndex == 106)
    {
        //Get the Address EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardAddressEdit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        DataOutBuffer[1] = (uint8_t)wcstol(theBuffer, &endPtr, 10);

        //Get the DataByte EditBox Data
        GetWindowTextW(GetDlgItem(hWnd, BoardDataEdit), theBuffer, sizeof(theBuffer) / sizeof(theBuffer[0]));
        DataOutBuffer[2] = (uint16_t)wcstol(theBuffer, &endPtr, 10);

        //Command
        DataOutBuffer[0] = 0x6a;

        //Send the data
        USBbyteOut();
    }

    isBusy = false;
  }

    void USBbyteOut(void)
    {
        ULONG bytesSent;

        bool writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)DataOutBuffer, 64, &bytesSent, NULL);

        if (writeStatus == false)
        {
            Error = GetLastError();
            _itow_s(Error, ErrorBuffer, 10);
            MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

            return;
        }
    }

  void MotorRun(HWND hWnd)
  {
      ULONG bytesSent;

      //Command
      outBuffer[0] = 0x06;

      //Run
      //get the control byte and clear the sequence bit
      outBuffer[1] = inBuffer[23] & 0x7f;

      //set the run bit in the control byte
      outBuffer[1] = outBuffer[1] | 0x01;
        
        bool writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

        if (writeStatus == false)
        {
            Error = GetLastError();
            _itow_s(Error, ErrorBuffer, 10);
            MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

            return;
        }
  }

  void MotorStop(HWND hWnd)
  {
      ULONG bytesSent;
      
      //Command
      outBuffer[0] = 0x06;

      //Stop
      outBuffer[1] = inBuffer[23] & 0x7e;

      bool writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

      if (writeStatus == false)
      {
          Error = GetLastError();
          _itow_s(Error, ErrorBuffer, 10);
          MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

          return;
      }

      
  }

  void ResetCounter(HWND hWnd)
  {
      ULONG bytesSent;

      outBuffer[0] = 0x06;
      outBuffer[1] = inBuffer[23] | 0x04;

      bool writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

      if (writeStatus == false)
      {
          Error = GetLastError();
          _itow_s(Error, ErrorBuffer, 10);
          MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

          return;
      }
  }

  void UpdateMotion(HWND hWnd)
  {
      ULONG bytesSent;
      wchar_t buffer[32];

      if (SendMessage(GetDlgItem(hWnd, DirectionCheckBox), BM_GETCHECK, 0, 0) == BST_CHECKED)
      {
          //Checkbox is checked
          
          outBuffer[2] = inBuffer[23] | 0x02;
      }
      else
      {
          //Checkbox is unchecked
          outBuffer[2] = inBuffer[23] & 0xfd;
      }

      GetWindowText(GetDlgItem(hWnd, SpeedEdit), buffer, sizeof(buffer) / sizeof(wchar_t));

      uint8_t value = 0;
      swscanf_s(buffer, L"%hhu", &value);

      outBuffer[0] = 0x09;
      outBuffer[1] = value;

      bool writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

      if (writeStatus == false)
      {
          Error = GetLastError();
          _itow_s(Error, ErrorBuffer, 10);
          MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

          return;
      }
  }
  
  //Build the Sequence of motion
  void RunSeq(HWND hWnd)
  {
      ULONG bytesSent;

      isBusy = true;

      //Command
      outBuffer[0] = 0x06;

      //Run
      //get the control byte and clear the run bit
      outBuffer[1] = inBuffer[23] & 0xfe;

      //set the sequence run bit and run bit in the control byte
      outBuffer[1] = 0x81;// outBuffer[1] | 0x81;

      bool writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

      if (writeStatus == false)
      {
          Error = GetLastError();
          _itow_s(Error, ErrorBuffer, 10);
          MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

          return;
      }

      isBusy = false;
  }

  void SeqSave(HWND hWnd)
  {
      wchar_t buffer[20];
      wchar_t* endPtr;
      ULONG bytesSent;

      isBusy = true;

      //use this union to convert the larger data to bytes
      union Long2Byte
      {
          uint8_t Byte[4];
          long DWordValue;
      };

      union Long2Byte MotionValue;

      //Get the data from the editboxes
      //Seq#, Dir, Acc, Speed, Dec, Dist Loop
      //Seq #
      GetWindowTextW(GetDlgItem(hWnd, SeqNumEdit), buffer, sizeof(buffer) / sizeof(buffer[0]));
      MotionValue.DWordValue = wcstol(buffer, &endPtr, 10);
      outBuffer[1] = MotionValue.Byte[0];

      //Dir
      int index = (int)SendMessage(GetDlgItem(hWnd, SeqDirCombo), CB_GETCURSEL, 0, 0);
      outBuffer[2] = index;

      //Acc
      GetWindowTextW(GetDlgItem(hWnd, SeqAccEdit), buffer, sizeof(buffer) / sizeof(buffer[0]));
      MotionValue.DWordValue = wcstol(buffer, &endPtr, 10);
      outBuffer[3] = MotionValue.Byte[0];

      //Speed
      GetWindowTextW(GetDlgItem(hWnd, SeqSpdEdit), buffer, sizeof(buffer) / sizeof(buffer[0]));
      MotionValue.DWordValue = wcstol(buffer, &endPtr, 10);
      outBuffer[4] = MotionValue.Byte[0];

      //Dec
      GetWindowTextW(GetDlgItem(hWnd, SeqDecEdit), buffer, sizeof(buffer) / sizeof(buffer[0]));
      MotionValue.DWordValue = wcstol(buffer, &endPtr, 10);
      outBuffer[5] = MotionValue.Byte[0];

      //Distance
      GetWindowTextW(GetDlgItem(hWnd, SeqDistEdit), buffer, sizeof(buffer) / sizeof(buffer[0]));

      MotionValue.DWordValue = wcstol(buffer, &endPtr, 10);

      if (index)
      {
          MotionValue.DWordValue = -MotionValue.DWordValue;
          //Convert the numerical value to a string
          wsprintfW(buf, L"%ld", MotionValue.DWordValue);

          // Set the text in the edit box
          SetWindowTextW(GetDlgItem(hWnd, SeqDistEdit), buf);
      }
      else
      {
          if (MotionValue.DWordValue < 0)
          {
              MotionValue.DWordValue = -MotionValue.DWordValue;
              //Convert the numerical value to a string
              wsprintfW(buf, L"%ld", MotionValue.DWordValue);

              // Set the text in the edit box
              SetWindowTextW(GetDlgItem(hWnd, SeqDistEdit), buf);
          }
      }

      outBuffer[6] = MotionValue.Byte[0];
      outBuffer[7] = MotionValue.Byte[1];
      outBuffer[8] = MotionValue.Byte[2];
      outBuffer[9] = MotionValue.Byte[3];

      //Stop Distance
      GetWindowTextW(GetDlgItem(hWnd, SeqStopEdit), buffer, sizeof(buffer) / sizeof(buffer[0]));

      MotionValue.DWordValue = wcstol(buffer, &endPtr, 10);

      if (index)
      {
          MotionValue.DWordValue = ~MotionValue.DWordValue;

          //Convert the numerical value to a string
          wsprintfW(buf, L"%ld", MotionValue.DWordValue);

          // Set the text in the edit box
          SetWindowTextW(GetDlgItem(hWnd, SeqStopEdit), buf);

      }
      else
      {
          if (MotionValue.DWordValue < 0)
          {
              MotionValue.DWordValue = ~MotionValue.DWordValue;
              //Convert the numerical value to a string
              wsprintfW(buf, L"%ld", MotionValue.DWordValue);

              // Set the text in the edit box
              SetWindowTextW(GetDlgItem(hWnd, SeqStopEdit), buf);
          }
      }

      outBuffer[10] = MotionValue.Byte[0];
      outBuffer[11] = MotionValue.Byte[1];
      outBuffer[12] = MotionValue.Byte[2];
      outBuffer[13] = MotionValue.Byte[3];

      //Delay between sequences
      outBuffer[14] = 0;

      //Total Number of sequences to run
      GetWindowTextW(GetDlgItem(hWnd, SeqTotalEdit), buffer, sizeof(buffer) / sizeof(buffer[0]));
      uint8_t seqTotal = (uint8_t)wcstol(buffer, &endPtr, 10);
      seqTotal = seqTotal - 1;

      outBuffer[15] = seqTotal;

      //Send the seqLoopvalue
      if (SendMessage(GetDlgItem(hWnd, SeqLoopCheckBox), BM_GETCHECK, 0, 0) == BST_CHECKED)
      {
          outBuffer[16] = 1;
      }
      else
      {
          outBuffer[16] = 0;
      }

      //Command
      outBuffer[0] = 0x0a;

      bool writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

      if (writeStatus == false)
      {
          Error = GetLastError();
          _itow_s(Error, ErrorBuffer, 10);
          MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);

          return;
      }

      isBusy = false;
  }

  /**********************************************************
  This function gets 64 bytes of data from the device
  Its called by MainTimer to refresh the data continuously
  **********************************************************/

  void getDevData(HWND hWnd)
  {
      if (isBusy == true)
      {
          return;
      }

      ULONG bytesSent;
      bool writeStatus = false;
      bool readStatus = false;
      char dev_volts[32] = { };
      char dev_amps[32] = { };
      char position[32] = { };
      char Index[32] = { };
      char frequency[32] = { };
      char dutycycle[32] = { };     

      OVERLAPPED overlapped = { 0 };

      overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);  // Manual-reset event

      if (overlapped.hEvent == NULL)
      {
          Error = GetLastError();
          _itow_s(Error, ErrorBuffer, 10);
          MessageBoxW(NULL, L"CreateEvent Failed!", ErrorBuffer, MB_ICONERROR);
          return;
      }

      // Union method to interpret the bytes as a float
      union Volts
      {
          uint8_t byte[4];
          float real;
      };

      union Current
      {
          uint8_t byte[4];
          float real;
      };

      // Union method to interpret the bytes as a float
      union DCycle
      {
          uint8_t byte[4];
          float real;
      };

      DCycle convertDC;
      Volts convertVolts;
      Current convertCurrent;

      //This is the command to the device which tells it what we want to do
      outBuffer[0] = 0x64;

      writeStatus = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 1, &bytesSent, &overlapped);

      if (writeStatus == false)
      {
          Error = GetLastError();
          _itow_s(Error, ErrorBuffer, 10);

          if (Error == ERROR_IO_PENDING)
          {
              // The write request is queued for asynchronous processing, wait for completion
              DWORD waitResult = WaitForSingleObject(overlapped.hEvent, 5000); // Wait for up to 5 seconds

              switch (waitResult)
              {
              case WAIT_OBJECT_0:
                  // The write operation completed successfully
                  // Check for result of the overlapped operation
                  if (GetOverlappedResult(MyWinUSBInterfaceHandle, &overlapped, &bytesSent, FALSE))
                  {
                      //MessageBoxW(NULL, L"WinUsb_WritePipe() Success!", L"Operation Complete", MB_ICONINFORMATION);
                  }
                  else
                  {
                      // If GetOverlappedResult fails, get the error code
                      DWORD resultError = GetLastError();
                      wchar_t ErrorBuffer[32];
                      _itow_s(resultError, ErrorBuffer, 10);
                      MessageBoxW(NULL, L"GetOverlappedResult Failed!", ErrorBuffer, MB_ICONERROR);
                  }
                  break;

              case WAIT_TIMEOUT:
                  // Timeout occurred
                  MessageBoxW(NULL, L"Write operation timed out.", L"Timeout Error", MB_ICONERROR);
                  break;

              default:
                  // An error occurred while waiting for the operation to complete
                  DWORD error = GetLastError();
                  wchar_t ErrorBuffer[32];
                  _itow_s(Error, ErrorBuffer, 10);
                  MessageBoxW(NULL, L"Wait failed!", ErrorBuffer, MB_ICONERROR);
                  break;

              }
          }
          else
          {
              // The write failed immediately; handle the error
              wchar_t errorBuffer[32];
              _itow_s(Error, errorBuffer, 10);
              MessageBoxW(NULL, L"WinUsb_WritePipe() Failed!", ErrorBuffer, MB_ICONERROR);
          }
          

      }

      readStatus = WinUsb_ReadPipe(MyWinUSBInterfaceHandle, 0x82, inBuffer, 64, &bytesSent, &overlapped);

      if (readStatus == false)
      {
          Error = GetLastError();
          _itow_s(Error, ErrorBuffer, 10);

          if (Error == ERROR_IO_PENDING)
          {
              // The write request is queued for asynchronous processing, wait for completion
              DWORD waitResult = WaitForSingleObject(overlapped.hEvent, 5000); // Wait for up to 5 seconds

              switch (waitResult)
              {
              case WAIT_OBJECT_0:
                  // The write operation completed successfully
                  // Check for result of the overlapped operation
                  if (GetOverlappedResult(MyWinUSBInterfaceHandle, &overlapped, &bytesSent, FALSE))
                  {
                      //MessageBoxW(NULL, L"WinUsb_ReadPipe() Success!", L"Operation Complete", MB_ICONINFORMATION);
                  }
                  else
                  {
                      // If GetOverlappedResult fails, get the error code
                      DWORD resultError = GetLastError();
                      wchar_t ErrorBuffer[32];
                      _itow_s(resultError, ErrorBuffer, 10);
                      MessageBoxW(NULL, L"GetOverlappedResult Failed!", ErrorBuffer, MB_ICONERROR);
                  }
                  break;

              case WAIT_TIMEOUT:
                  // Timeout occurred
                  MessageBoxW(NULL, L"Read operation timed out. 1786", L"Timeout Error", MB_ICONERROR);
                  break;

              default:
                  // An error occurred while waiting for the operation to complete
                  DWORD error = GetLastError();
                  wchar_t ErrorBuffer[32];
                  _itow_s(Error, ErrorBuffer, 10);
                  MessageBoxW(NULL, L"Wait failed!", ErrorBuffer, MB_ICONERROR);
                  break;

              }
          }
          else
          {
              // The write failed immediately; handle the error
              wchar_t errorBuffer[32];
              _itow_s(Error, errorBuffer, 10);
              MessageBoxW(NULL, L"WinUsb_ReadPipe() Failed!", ErrorBuffer, MB_ICONERROR);
          }


      }

      /*****************************************************************
      Gets the board current useage as 4 bytes and converts it to a Float
      the data is averaged over 10 cycles to increase stability
      ******************************************************************/

      //Average the voltage over 10 measurements but display the first measurement 
      //until 10 interations
      if (curTimeMet == false)
      {
          convertCurrent.byte[0] = inBuffer[3];
          convertCurrent.byte[1] = inBuffer[2];
          convertCurrent.byte[2] = inBuffer[1];
          convertCurrent.byte[3] = inBuffer[0];

          sprintf_s(dev_amps, "%.f", convertCurrent.real);

          SetWindowTextA(GetDlgItem(hWnd, DevCurText), dev_amps);

          curTimeMet = true;
      }

      if (cv > 9)
      {
          avgCurData[10] = (avgCurData[0] + avgCurData[1] + avgCurData[2] + avgCurData[3] + avgCurData[4] + avgCurData[5]
              + avgCurData[6] + avgCurData[7] + avgCurData[8] + avgCurData[9]) / 10;

          sprintf_s(dev_amps, "%.f", avgCurData[10]);

          SetWindowTextA(GetDlgItem(hWnd, DevCurText), dev_amps);

          cv = 0;
      }

      convertCurrent.byte[0] = inBuffer[3];
      convertCurrent.byte[1] = inBuffer[2];
      convertCurrent.byte[2] = inBuffer[1];
      convertCurrent.byte[3] = inBuffer[0];

      avgCurData[cv] = convertCurrent.real;

      cv++;

      /*****************************************************************
      Gets the board input voltage as 4 bytes and converts it to a Float
      the data is averaged over 10 cycles to increase stability
      ******************************************************************/

      //Average the voltage over 10 measurements but display the first measurement 
      //until 10 interations
      if (voltsTimeMet == false)
      {
          convertVolts.byte[0] = inBuffer[7];
          convertVolts.byte[1] = inBuffer[6];
          convertVolts.byte[2] = inBuffer[5];
          convertVolts.byte[3] = inBuffer[4];

          sprintf_s(dev_volts, "%.2f", convertVolts.real);

          SetWindowTextA(GetDlgItem(hWnd, DevVoltsText), dev_volts);

          voltsTimeMet = true;
      }      


    if (vv > 9)
    {
        avgVoltsData[10] = (avgVoltsData[0] + avgVoltsData[1] + avgVoltsData[2] + avgVoltsData[3] + avgVoltsData[4] + avgVoltsData[5]
            + avgVoltsData[6] + avgVoltsData[7] + avgVoltsData[8] + avgVoltsData[9]) / 10;

        sprintf_s(dev_volts, "%.2f", avgVoltsData[10]);

        SetWindowTextA(GetDlgItem(hWnd, DevVoltsText), dev_volts);

        vv = 0;
    }

    convertVolts.byte[0] = inBuffer[7];
    convertVolts.byte[1] = inBuffer[6];
    convertVolts.byte[2] = inBuffer[5];
    convertVolts.byte[3] = inBuffer[4];

    avgVoltsData[vv] = convertVolts.real;

    vv++;

///////////////////////////////////////////////////////////////////////////////
        

   //PWM frequency
   uint16_t PGxPER;
   PGxPER = inBuffer[9] << 8;
   PGxPER = PGxPER + inBuffer[8];

   //This prevents a divide by zero exception
   //if there is an error and inBuffer is empty
   if(PGxPER == 0)
   { 
        PGxPER = 100;
   }

   PWM_Freq = 100000000 / PGxPER;

   sprintf_s(frequency, "%d", PWM_Freq);

   SetWindowTextA(GetDlgItem(hWnd, FreqEdit), frequency);

    //Encoder Position
    
    //LSB
    pos = inBuffer[13];
    pos = pos << 8;
    pos = pos + inBuffer[12];
    pos = pos << 8;
    pos = pos + inBuffer[11];
    pos = pos << 8;
    pos = pos + inBuffer[10];

    sprintf_s(position, "%d", pos);

    SetWindowTextA(GetDlgItem(hWnd, QEIPosition), position);

    //PWM Duty Cycle
    convertDC.byte[3] = inBuffer[17];
    convertDC.byte[2] = inBuffer[16];
    convertDC.byte[1] = inBuffer[15];
    convertDC.byte[0] = inBuffer[14];

    convertDC.real = (convertDC.real / 2500) * 100;

    sprintf_s(dutycycle, "%.0f", convertDC.real);

    SetWindowTextA(GetDlgItem(hWnd, DutyCycle), dutycycle);

    //Index Counter
    uint32_t cnt;
    //LSB
    cnt = inBuffer[21];
    cnt = cnt << 8;
    cnt = cnt + inBuffer[20];
    cnt = cnt << 8;
    cnt = cnt + inBuffer[19];
    cnt = cnt << 8;
    cnt = cnt + inBuffer[18];

    sprintf_s(Index, "%d", cnt);

    SetWindowTextA(GetDlgItem(hWnd, QEIIndex), Index);

    //Control Byte    
    cntl = inBuffer[23];
    std::string binaryString;

    //Convert the uint8_t value to a binary string
    binaryString = ToBinaryString(cntl);

    //Set the text of the static control to the binary string
    SetWindowTextA(GetDlgItem(hWnd, ControlByte), binaryString.c_str());

    //Status Byte
    uint8_t stat;
    stat = inBuffer[24];

    //Convert the uint8_t value to a binary string
    binaryString = ToBinaryString(stat);

    //Set the text of the static control to the binary string
    SetWindowTextA(GetDlgItem(hWnd, StatusByte), binaryString.c_str());
}

void CalculateRPM(HWND hWnd)
{
    //Speed - RPM
    double ft = 0;
    char speed[32] = { };

    //Calculate RPM - get counter and calculate the counts per rotation
    //counts per rotation = 3000
    //TimerCount is incremented every 100mS

    //This will be the previous value
    if (myBool == false)
    {
        TimerTmpA = pos;
        myBool = true;
    }
    else
    {
        TimerTmpB = pos;

        //Change formula to match direction
        if ((cntl & 0x02) == 0)
        {
            ft = (((TimerTmpB - TimerTmpA) / 300) * 60) / 0.88421;
        }
        else
        {
            ft = (((TimerTmpA - TimerTmpB) / 300) * 60) / 0.88421;
        }
        sprintf_s(speed, "%.0f", ft);

        if (ft > 0)
        {
            SetWindowTextA(GetDlgItem(hWnd, CurrentSpeedTxt), speed);
        }

        if (cntl == 0)
        {
            SetWindowTextA(GetDlgItem(hWnd, CurrentSpeedTxt), "0");
        }

        myBool = false;
    }
    
}

void File2Array(HWND hWnd)
{
    ShowWindow(GetDlgItem(hWnd, IDC_LISTBOX), SW_HIDE);
    ShowWindow(GetDlgItem(hWnd, ProgramListTitleText), SW_HIDE);

    //The code
    // Open the text file for writing
    FILE* input_file, * output_file;

    const char* output_filename = "E:\\Project\\IO_Board\\Audio\\myFile.h";
    const char* input_filename = "E:\\Project\\IO_Board\\Audio\\myFile.raw";


    if (fopen_s(&input_file, input_filename, "rb") != 0 || input_file == NULL)
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(hWnd, ErrorBuffer, L"File to Array - Could not Open File!", MB_OK | MB_ICONERROR);

        return;
    }

    // Get file size
    fseek(input_file, 0, SEEK_END);
    long file_size = ftell(input_file);
    rewind(input_file);

    // Allocate memory for file contents
    unsigned char* buffer = (unsigned char*)malloc(file_size);
    if (!buffer)
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(hWnd, ErrorBuffer, L"File to Array - Memory allocation failed!", MB_OK | MB_ICONERROR);

        fclose(input_file);

        return;
    }

    // Read file into buffer
    fread(buffer, 1, file_size, input_file);

    fclose(input_file);

    if (fopen_s(&output_file, output_filename, "w") != 0 || output_file == NULL)
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(hWnd, ErrorBuffer, L"File to Array - Could not open output file!", MB_OK | MB_ICONERROR);

        fclose(input_file);

        return;
    }

    // Write the C array to the output file
    fprintf(output_file, "const unsigned char audio_data[%ld] = {\n    ", file_size);
    for (long i = 0; i < file_size; i++)
    {
        fprintf(output_file, "0x%02X, ", buffer[i]);
        if ((i + 1) % 12 == 0)  // New line every 12 bytes
            fprintf(output_file, "\n    ");
    }

    fprintf(output_file, "\n};\n");

    // Cleanup
    free(buffer);
    fclose(output_file);

    Error = GetLastError();
    _itow_s(Error, ErrorBuffer, 10);


    //get the windows error code and display it's associated text 
    LPVOID eBuffer = {};

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        Error,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPWSTR)&eBuffer,
        0, NULL);

    MessageBoxW(hWnd, (LPWSTR)eBuffer, L"File 2 Array", MB_OK | MB_ICONEXCLAMATION);

    dc = GetDC(hWnd);

    //Set the font
    SelectObject(dc, hFont);

    c = L"File Size: ";
    TextOut(dc, 10, 100, c, (int)_tcslen(c));

    Error = file_size;
    _itow_s(Error, ErrorBuffer, 10);

    TextOut(dc, 100, 100, ErrorBuffer, (int)_tcslen(c));

    c = L"bytes";
    TextOut(dc, 150, 100, c, (int)_tcslen(c));
}

// Function to convert uint8_t to binary string
std::string ToBinaryString(uint8_t value)
{
    // std::bitset automatically creates a binary representation
    std::bitset<8> bits(value); 

    // Returns a string like "11001010"
    return bits.to_string();     
}


//Takes a DWORD and passes it in then coverts to a decimal number
//and displays it in a message box
void Debug_Function(DWORD Error)
{
    _itow_s(Error, ErrorBuffer, 10);
    MessageBoxW(NULL, L"Debug", ErrorBuffer, MB_OK);

}

void SetTime(HWND hWnd)
{  
    char am_pm[] = "AM";

    ULONG bytesSent = 0;
    GetLocalTime(&localTime);

    if (Connection != isConnected)
    {
        MessageBoxW(NULL, L"Device is not connected ...", L"Connection Status", MB_OK);

        return;
    }

    //Get the time from localTime
    outBuffer[0] = 0x03;
    outBuffer[1] = (uint8_t)localTime.wHour;
    outBuffer[2] = (uint8_t)localTime.wMinute;
    outBuffer[3] = (uint8_t)localTime.wSecond;

    //Send the command
    BOOL Status = WinUsb_WritePipe(MyWinUSBInterfaceHandle, 0x01, (PUCHAR)outBuffer, 64, &bytesSent, NULL);

    //Handle any error
    if (Status == FALSE)
    {
        Error = GetLastError();
        _itow_s(Error, ErrorBuffer, 10);
        MessageBoxW(NULL, L"Set Time Command", ErrorBuffer, MB_OK);

        //If we can't send data then we can't be connected
        Connection = notConnected;

        return;
    }
}

