⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scope_control.cpp

📁 一个简单示波器的源代码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//
// 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 + -