📄 scope_control.cpp
字号:
//
// scope_control.c - Low level functions allowing control of the Luminary
// Micro Oscilloscope device via USB.
//
#include "stdafx.h"
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>
#include <strsafe.h>
#include "winusb.h"
#include "usb100.h"
#include "scope_guids.h"
#define PACKED
#pragma pack(1)
#include "usb_protocol.h"
#pragma pack()
#include "scope_control.h"
//****************************************************************************
//
// Buffer size definitions.
//
//****************************************************************************
#define MAX_DEVPATH_LENGTH 256
#define MAX_STRING_LEN 256
//****************************************************************************
//
// Various timeouts in milliseconds.
//
//****************************************************************************
#define THREAD_END_TIMEOUT 3000
#define CONNECT_RETRY_DELAY 2000
//****************************************************************************
//
// Structure containing handles and information required to communicate with
// the USB bulk device.
//
//****************************************************************************
typedef struct
{
HANDLE deviceHandle;
HANDLE hConnectEvent;
HANDLE hThreadSignalEvent;
HANDLE hThreadEndEvent;
HANDLE hReadEvent;
HANDLE hThread;
DWORD dwThreadID;
WINUSB_INTERFACE_HANDLE winUSBHandle;
UCHAR deviceSpeed;
UCHAR bulkInPipe;
UCHAR bulkOutPipe;
BOOL bDeviceConnected;
BOOL bCommunicating;
BOOL bInterfaceFound;
HWND hwndNotify;
} tDeviceInfo;
tDeviceInfo devInfo;
typedef enum
{
SCOPE_OK,
SCOPE_TIMEOUT,
SCOPE_DISCONNECTED,
SCOPE_PROTOCOL_ERROR,
SCOPE_READ_ERROR,
SCOPE_END_SIGNALLED
} tDeviceRetcode;
//****************************************************************************
//
// Internal function prototypes.
//
//****************************************************************************
static bool TerminateDevice(tDeviceInfo *pDevice);
static bool InitializeDevice(bool *pbDriverInstalled);
static HANDLE OpenDevice(void);
static DWORD GetDevicePath(LPGUID InterfaceGuid, PCHAR pcDevicePath,
size_t BufLen);
static bool SendScopePacket(unsigned char ucPacketType,
unsigned char ucParam,
unsigned long ulParam,
unsigned long ulDataLength = 0,
void *pData = NULL);
static bool ScopeWaitPacket(unsigned char *pucPacketType,
unsigned char *pucParam,
unsigned long *pulParam,
unsigned long *pulDataLength,
void **ppData);
static tDeviceRetcode ScopeReadPacket(tDeviceInfo *pDevice,
tScopePacket *psPacket,
void **ppvData,
DWORD dwTimeoutmS);
//****************************************************************************
//
// This thread is responsible for handling all reads from the USB device
// and also for polling for connections if the device is not yet connected.
//
//****************************************************************************
static DWORD WINAPI ReadConnectThread(LPVOID lpParam)
{
tDeviceInfo *pDevice = (tDeviceInfo *)lpParam;
tDeviceRetcode eRetcode;
DWORD dwRetcode;
BOOL bResult;
bool bDriverInstalled = false;
bool bDataReadOngoing = false;
tScopePacket sPacket;
tScopeDataStart *psDataStart;
void *pvPacketData;
static char *pData;
static unsigned char ucContinuityCount;
static char *pcElement;
static unsigned long ulDataSize;
while(1)
{
//
// If we are not currently in communication with the device, try to
// open it. If this fails, wait a while and try again.
//
while(!pDevice->bDeviceConnected)
{
//
// Try to connect.
//
pDevice->bDeviceConnected = InitializeDevice(&bDriverInstalled);
//
// Was the connection attempt unsuccessfull?
//
if(pDevice->bDeviceConnected == false)
{
//
// We couldn't connect. Was the correct device driver found?
//
if(!bDriverInstalled)
{
//
// No - post a message to the client telling them that the
// driver isn't there. This will be a periodic message
// until the driver is installed or the function
// ScopeControlTerminate() is called.
//
PostMessage(pDevice->hwndNotify, WM_SCOPE_NO_DRIVER, 0,
0);
}
//
// Sleep for a while but ensure that we catch cases where we
// are signalled to exit.
//
dwRetcode = WaitForSingleObject(pDevice->hThreadEndEvent,
CONNECT_RETRY_DELAY);
//
// A zero return code indicates that the event was signalled.
// On any other return code, we go back and try to connect
// again.
//
if(!dwRetcode)
{
//
// The thread end signal was received so we need to exit
// here.
//
SetEvent(pDevice->hThreadSignalEvent);
ExitThread(0);
}
}
}
//
// At this point, the device is connected but we have not yet
// established communication. We send a message to the client
// telling them that a connection has occurred and wait for them
// to call ScopeControlConnect() to continue the process.
//
PostMessage(pDevice->hwndNotify, WM_SCOPE_DEVICE_AVAILABLE, 0, 0);
//
// Now we continue reading from the device until it disconnects
// or the client tells the thread to exit.
//
while(pDevice->bDeviceConnected)
{
//
// Get a packet from the oscilloscope
//
eRetcode = ScopeReadPacket(pDevice, &sPacket, &pvPacketData,
INFINITE);
//
// Did we read the packet as expected?
//
if(eRetcode == SCOPE_OK)
{
//
// We got a packet. Now decide what to do with it.
//
switch(sPacket.ucPacketType)
{
//
// The oscilloscope has sent a handshake response to our
// SCOPE_PKT_HELLO packet.
//
case SCOPE_PKT_HELLO_RESPONSE:
{
//
// A HELLO_RESPONSE packet tells us that the device is
// running and communicating. Pass this on to the
// client and set our flag to indicate that we are
// in full communication.
//
pDevice->bCommunicating = true;
PostMessage(pDevice->hwndNotify,
WM_SCOPE_DEVICE_CONNECTED,
0, (LPARAM)pvPacketData);
}
break;
//
// The scope has responded to our outgoing SCOPE_PKT_PING
// packet.
//
case SCOPE_PKT_PING_RESPONSE:
{
//
// Pass the ping response back to the client.
//
PostMessage(pDevice->hwndNotify,
WM_SCOPE_PING_RESPONSE,
(WPARAM)sPacket.ucParam,
(LPARAM)sPacket.ulParam);
}
break;
//
// The oscilloscope has sent the packet which indicates
// the start of waveform data transmission.
//
case SCOPE_PKT_DATA_START:
{
//
// The packet payload should be a structure telling us
// about the data we can expect to follow.
//
psDataStart = (tScopeDataStart *)pvPacketData;
//
// If we didn't get a payload, leave before doing
// anything else.
//
if(!psDataStart)
{
break;
}
//
// Start reception of a new data packet. If we have
// a previous incomplete packet, throw it away.
//
if(bDataReadOngoing)
{
LocalFree(pData);
}
//
// Allocate storage for the header info and the
// samples we will be gathering.
//
if(psDataStart->bDualChannel)
{
ulDataSize = sizeof(tScopeDataStart) +
psDataStart->ulTotalElements *
sizeof(tScopeDualDataElement);
}
else
{
ulDataSize = sizeof(tScopeDataStart) +
psDataStart->ulTotalElements *
sizeof(tScopeDataElement);
}
//
// Allocate enough storage to hold the whole data block.
//
pData = (char *)LocalAlloc(LMEM_FIXED, ulDataSize);
//
// If we got the storage, copy the header into it and set up
// our pointers to allow the data to be copied from later
// SCOPE_PKT_DATA packets.
//
if(pData)
{
memcpy(pData, psDataStart, sizeof(tScopeDataStart));
//
// Set up for the new capture.
//
ucContinuityCount = 1;
bDataReadOngoing = true;
pcElement = (pData + sizeof(tScopeDataStart));
ulDataSize -= sizeof(tScopeDataStart);
}
//
// Free the packet payload since we are finished with
// it now.
//
LocalFree(pvPacketData);
}
break;
//
// The oscilloscope is signalling the end of transmission
// for a waveform data block.
//
case SCOPE_PKT_DATA_END:
{
//
// Data reception is complete so pass the completed
// data set back to the client.
//
bResult = PostMessage(pDevice->hwndNotify, WM_SCOPE_DATA,
(WPARAM)sizeof(tScopeDataStart), (LPARAM)pData);
//
// Only free the pData buffer if we failed to post
// the message to the client queue. If the post is
// successful, the client must free the pointer once
// it processes the message.
//
if(!bResult)
{
LocalFree(pData);
}
//
// We are no longer in the midst of a data set so
// record this fact.
//
bDataReadOngoing = false;
pData = NULL;
}
break;
//
// The oscilloscope has sent some of the data comprising
// capture of a waveform.
//
case SCOPE_PKT_DATA:
{
//
// Add this data to the buffer we are collecting for
// the client (assuming we are collecting data). If
// not, merely discard the packet.
//
if(bDataReadOngoing)
{
//
// Check that the packet number is as expected
// and that we have space for the payload.
//
if((sPacket.ucParam == ucContinuityCount++) &&
(ulDataSize >= sPacket.ulDataLength))
{
//
// Copy the payload into our sample buffer.
//
memcpy(pcElement, pvPacketData,
sPacket.ulDataLength);
ulDataSize -= sPacket.ulDataLength;
pcElement += sPacket.ulDataLength;
}
else
{
//
// Packet continuity counter showed an error.
// Tidy up and discard everything to the end
// of the sequence.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -