?? pubmem.cpp
字號:
/************************************************************************
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
* PURPOSE.
************************************************************************/
/************************************************************************
*
* Module: pubmem.cpp
* Long name: VHPD1394 memory publisher example
* Description: This sample demonstrates how to use the VHPD1394
* device driver to publish a portion of the IEEE 1394
* address space of the local node (PC) and to receive
* notifications for access on this address space.
* This sample is based on the VHPDLib C++ class library.
* It mainly demonstrates the usage of the class CVhpdNotifySlave.
*
* Runtime Env.: implemented as Win32 console application
* Used link libraries:
* vhpdlib.lib, setupapi.lib, user32.lib
* Author(s): Frank Senf
* Company: Thesycon GmbH, Ilmenau
************************************************************************/
// standard includes
#include <stdio.h>
#include <conio.h>
// definitions of used classes
#include "NotifySlave.h"
// print prefixes
#define PFX "PUBMEM: "
#define PFXERR "PUBMEM Error: "
// standard help message
static const char g_UseHelp[] = "For help, use PUBMEM -h.";
// GLOBAL VARIABLES
// notify slave instance
CNotifySlave g_NotifySlave;
// zero-based index of the peer device within the Windows-internal
// device list
// not related to the device's node ID, see the "SCAN" example for
// further details
// (default 0)
int g_DevNumber =0;
// IEEE 1394 start address of address space that will be published
// (no default, always has to be specified)
__int64 g_StartAddress;
// size, in bytes, of the address space that will be published
// (default 2048)
// NOTE: do not set to a multiple of 64*1024 bytes (see also "Problems.txt")
unsigned long g_MemoryLength =2048;
// set to zero to disable notifications for all accesses to the published
// address space
int g_Notify =1;
// parameters of the buffer pool used for access notifications
// number of buffers in pool
unsigned long g_NumberOfBuffers =4;
/*******************************************************************/
// support functions
/*******************************************************************/
//
// display usage information
//
void
PrintHelp(void)
{
fprintf(stdout,
"\n"
"usage: PUBMEM Address <Options>\n"
"\n"
" Address (hexadecimal, required)\n"
" IEEE 1394 start address of address space that will be published\n"
"\n"
" Options:\n"
" -dDevNumber: zero-based index of the device (optional, default %d)\n"
" (use the SCAN example to display a list of available devices)\n"
" -sMemorySize: size, in bytes, of the address space to publish\n"
" (do not set to a multiple of 64*1024 bytes, see problems.txt\n"
" for details)\n"
" (optional, default %d)\n"
" -eEnabled: enable notifications for all accesses to the\n"
" published address space\n"
" (optional, 1 -> enabled, 0 -> disabled, default %s)\n"
" -nBufferCount: number of buffers used for access notifications\n"
" (optional, default %d)\n"
,g_DevNumber, g_MemoryLength, (g_Notify==1) ? "enabled" : "disabled",g_NumberOfBuffers);
fprintf(stdout,"\nPress any key to continue\n");
getch();
} // PrintHelp
/*******************************************************************/
// main function
/*******************************************************************/
int __cdecl main(int argc, char *argv[])
{
// used for synchronisation of notification processing
HANDLE hNotifyEvt; hNotifyEvt = NULL;
HANDLE hNotifyCompletedEvt; hNotifyCompletedEvt = NULL;
/*******************************************************************/
// fixed command line argument
// check for required arguments
if ( argc < 2 ) {
// at least Address has to be specified
PrintHelp();
return 1;
}
// store values for required arguments
__int64 val64;
if ( 1==sscanf(argv[1]," %I64x ",&val64) ) {
// store value
g_StartAddress = val64;
} else {
// invalid Address parameter, we cannot continue
fprintf(stderr, PFXERR"Invalid Address argument '%s'\n",argv[1]);
return 4;
}
/*******************************************************************/
// optional command line options
int i;
int val;
char* p;
for ( i=1; i<argc; i++ ) {
p = argv[i];
if ( (*p) == '-' ) {
p++;
switch ( *p ) {
case 'h':
case 'H':
case '?':
// help
PrintHelp();
return 0;
// device number
case 'd':
// read number
if ( 1==sscanf(p+1," %i ",&val) ) {
if ( val>=0 && val<=62 ) {
// store value
g_DevNumber = val;
} else {
// invalid device number, ignore it
fprintf(stderr, PFXERR"Invalid device number %d ignored\n",val);
}
} else {
// invalid option format, ignore it
fprintf(stderr, PFXERR"Invalid argument '%s' ignored\n",argv[i]);
}
break;
// size of published memory space
case 's':
// read number
if ( 1==sscanf(p+1," %i ",&val) ) {
// check for a multiple of 64*1024 bytes, this will cause problems
if ( val % (64*1024) == 0 ) {
fprintf(stderr, PFXERR"Invalid argument '%s'\n",argv[i]);
fprintf(stderr, PFXERR"Multiples of 64*1024 bytes will cause serious problems\n");
return 5;
} else {
// store value
g_MemoryLength = val;
}
} else {
// invalid option format, ignore it
fprintf(stderr, PFXERR"Invalid argument '%s' ignored\n",argv[i]);
}
break;
// notifications enabled ?
case 'e':
// read number
if ( 1==sscanf(p+1," %i ",&val) ) {
// store value
g_Notify = val;
} else {
// invalid option format, ignore it
fprintf(stderr, PFXERR"Invalid argument '%s' ignored\n",argv[i]);
}
break;
// buffer count
case 'n':
// read number
if ( 1==sscanf(p+1," %i ",&val) ) {
// store value
g_NumberOfBuffers = val;
} else {
// invalid option format, ignore it
fprintf(stderr, PFXERR"Invalid argument '%s' ignored\n",argv[i]);
}
break;
// unknown options
default:
fprintf(stderr, PFXERR"Unrecognized option '%s' ignored. %s\n",argv[i],g_UseHelp);
break;
} // switch
}
} // for
/*******************************************************************/
// open a device handle
// prepare an OS-internal device list used for the open call
HDEVINFO DevList; DevList = NULL;
// device list will contain devices that provide the VHPD_IID interface
// please refer to to the documentation (chapter 7.4) for details on how
// to define your private interface (strongly recommended)
const GUID VhpdDefaultIID = VHPD_IID;
DevList = CVhpd::CreateDeviceList(&VhpdDefaultIID);
if ( DevList == NULL ) {
// ERROR !!!
fprintf(stderr, PFXERR"CreateDeviceList failed\n");
return 10;
}
// open a handle to the device
unsigned long Status;
Status = g_NotifySlave.Open(g_DevNumber,DevList,&VhpdDefaultIID);
if ( Status != VHPD_STATUS_SUCCESS ) {
// ERROR !!!
fprintf(stderr, PFXERR"Failed to open device %d (0x%08X)\n",g_DevNumber,Status);
goto Exit;
}
// device opened, destroy the device list, we don't need it anymore
CVhpd::DestroyDeviceList(DevList);
DevList = NULL;
/*******************************************************************/
// setup g_NotifySlave
// fill given start address to interface structure
VHPD_UINT64 StartAddress;
StartAddress.QuadPart = g_StartAddress;
// initialize the g_NotifySlave instance
// this creates an AddressRange object at the device driver
// AddressRange object is created in BufferStoreMode
Status = g_NotifySlave.Setup(
StartAddress, // start address of address space
g_MemoryLength, // size in bytes of address space
StartAddress, // trigger address (not used in BufferStoreMode)
VHPD_FLAG_ADRRNG_ACCESS_READ
| VHPD_FLAG_ADRRNG_ACCESS_WRITE
| VHPD_FLAG_ADRRNG_ACCESS_LOCK, // allowed access options
VHPD_FLAG_ADRRNG_NOTIFY_READ
| VHPD_FLAG_ADRRNG_NOTIFY_WRITE
| VHPD_FLAG_ADRRNG_NOTIFY_LOCK, // requested notification options
g_NumberOfBuffers, // number of notification buffers
sizeof(VHPD_ADRRNG_NOTIFICATION) // size in bytes of a notification buffer
);
if ( Status != VHPD_STATUS_SUCCESS ) {
// ERROR !!!
fprintf(stderr, PFXERR"Failed to initialize g_NotifySlave (0x%08X)\n",Status);
goto Exit;
}
// AddressRange object is configured now, but access to address space is not possible
// before EnableAddressRange is called
// configure notification processing if notifications are enabled
if ( g_Notify != 0 ) {
// create synchronization events
hNotifyEvt = ::CreateEvent(NULL,FALSE,FALSE,NULL);
if ( hNotifyEvt == NULL ) {
// ERROR !!!
fprintf(stderr, PFXERR"CreateEvent(hNotifyEvt) failed (0x%08X)\n",::GetLastError());
goto Exit;
}
hNotifyCompletedEvt = ::CreateEvent(NULL,FALSE,FALSE,NULL);
if ( hNotifyCompletedEvt == NULL ) {
// ERROR !!!
fprintf(stderr, PFXERR"CreateEvent(hNotifyCompletedEvt) failed (0x%08X)\n",::GetLastError());
goto Exit;
}
// init synchronisation events of g_NotifySlave worker thread
g_NotifySlave.SetNotifyEvents(hNotifyEvt,hNotifyCompletedEvt);
// start g_NotifySlave worker thread
if ( !g_NotifySlave.StartThread() ) {
// ERROR !!!
fprintf(stderr, PFXERR"Failed to start worker thread\n");
goto Exit;
}
}
// enable access to the address space
Status = g_NotifySlave.EnableAddressRange();
if ( Status != VHPD_STATUS_SUCCESS ) {
// ERROR !!!
fprintf(stderr, PFXERR"Failed to enable address space access (0x%08X)\n",Status);
goto Exit;
}
// access to address space is possible now
/*******************************************************************/
// now wait for notifications until we are told to exit
fprintf(stdout, PFX"Address space 0x%012I64X to 0x%012I64X published\n",
g_StartAddress,g_StartAddress+g_MemoryLength);
fprintf(stdout, PFX"Waiting for access ... press any key to exit\n");
for(;;) {
if ( g_Notify != 0 ) {
// wait for a address space access notification, loop sometimes to give
// the user a chance to exit
unsigned long res;
res = ::WaitForSingleObject(hNotifyEvt,500);
if ( res == WAIT_TIMEOUT ) {
// wait timed out, just check keyboard input and enter wait again
}
if ( res == WAIT_OBJECT_0 ) {
// notification received, get pointer to current address space access description
VHPD_ADRRNG_NOTIFICATION* access = g_NotifySlave.GetCurrentAccess();
if ( access != NULL ) {
// print access description on screen
fprintf(stdout, PFX"Access on monitored address space detected\n");
fprintf(stdout, " Address 0x%012I64X\n",access->StartAddress.QuadPart + access->Offset);
fprintf(stdout, " Length %d bytes\n",access->Length);
fprintf(stdout, " Tye %s \n",
(access->NotificationEvent&VHPD_FLAG_ADRRNG_NOTIFY_READ)?"READ":
(access->NotificationEvent&VHPD_FLAG_ADRRNG_NOTIFY_WRITE)?"WRITE":
(access->NotificationEvent&VHPD_FLAG_ADRRNG_NOTIFY_LOCK)?"LOCK":"UNKNOWN"
);
// print data to screen for WRITE and LOCK access
if ( (access->NotificationEvent&VHPD_FLAG_ADRRNG_NOTIFY_WRITE)
|| (access->NotificationEvent&VHPD_FLAG_ADRRNG_NOTIFY_LOCK) ) {
fprintf(stdout, " Data");
for (unsigned long i=0; i<access->Length; i++) {
if ( (i%4) == 0 ) {
fprintf(stdout,"\n ");
}
fprintf(stdout,"0x%02X ",access->Data[i]);
}
fprintf(stdout,"\n");
}
}
// notification completely processed, continue worker thread
::SetEvent(hNotifyCompletedEvt);
}
if ( res == WAIT_FAILED ) {
// ERROR !!!
fprintf(stderr,PFX"WaitForSingleObject failed (0x%08X), aborting ...\n",::GetLastError());
break;
}
} else {
// nothing to do, check for errors
if ( g_NotifySlave.GetErrorCount() != 0 ) {
fprintf(stderr, PFX"Avg. rate is %I64d Bytes/s %d buffer errors (last 0x%08X)\n",
g_NotifySlave.GetErrorCount(), g_NotifySlave.GetLastError());
}
// check if thread is still running
// worker thread may terminate itself, even if ShutdownThread was not called
// (e.g. because ProcessNotification returns false or an internal error was detected)
if ( g_NotifySlave.ThreadExited() ) {
fprintf(stdout,"\n"PFX"Worker thread has terminated ... aborting.\n");
break;
}
// suspend some time
Sleep(500);
}
// check for user break
if ( kbhit() ) {
getch();
break;
}
} // for
fprintf(stdout, PFX"Exiting ...\n");
/*******************************************************************/
// ERROR!!! or normal exit
// release claimed resources
Exit:
if ( !g_NotifySlave.ShutdownThread() ) {
// ERROR !!!
fprintf(stderr, PFXERR"FATAL: Failed to stop worker thread\n");
}
g_NotifySlave.SetNotifyEvents(NULL,NULL);
g_NotifySlave.DisableAddressRange();
g_NotifySlave.DeleteSlave();
g_NotifySlave.Close();
if ( hNotifyEvt != NULL ) {
::CloseHandle(hNotifyEvt);
hNotifyEvt = NULL;
}
if ( hNotifyCompletedEvt != NULL ) {
::CloseHandle(hNotifyCompletedEvt);
hNotifyCompletedEvt = NULL;
}
return 0;
} // main
/*************************** EOF **************************************/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -