This interface is only used when user programs need more than basic VME cycle generation or handling.
//DriveVME.DLL Header File //Copyright 1996,1997,1999,2007 N4 Communications Co. All rights reserved. //This file supports use of DriveVME.DLL, which encapsulates //some of the functions of DriveVME. All of the functions of //DriveVME are available without using DLLs, this module is //provided for those who desire Microsoft style DLL usage and operations. //DriveVME.DLL is multi thread and multi-processor safe. #include <windows.h> #include <fcntl.h> #include <io.h> #ifdef IS_DMVEDLL_COMPILE #define DllStatus __declspec( dllexport ) #else #define DllStatus __declspec( dllimport ) #endif #ifndef IN #define IN #endif #ifndef OUT #define OUT #endif #ifdef __cplusplus extern "C" { #endif /*************************************************************************************/ /********* Access VME Memory directly via networkable file I/O **************/ //The "rangespec" parameter is an ASCII string identifying the range to reserved, //as well as formatting options. //Use the graphical "AssistVME" program's "Access Via I/O" function to create and test //the VME device's proper operations, then cut the string AssistVME provides, //and paste it in your program as the parameter to these functions. //NOTE: File I/O based VME access functions IS supported over networks. //Note: This function checks the passed in "filename" against the list of //Keys stored in the local chassis DriveVME registry, substituting the stored //value if any match is found. If none is, the passed in name is treated //like a filename in it's own right. This feature allows for user //modification of VME realities without recompliling the program. //Note: The transfer width specified in the setup string is the width //actually used for all transfers, without regard for the size. DllStatus HANDLE Open_VME_Range_by_Name(IN const char *rangespec); #define End_VME_Range_by_File(x) CloseHandle(x) /* //Example: #define linesize 81 void demo_fileIO_vme_resource(){ HANDLE han; char str[linesize+1]; unsigned long got; //Allocate some slave memory, filename from AssistVME. puts("Checkout mapping access via file I/O"); han = Open_VME_Range_by_Name( //This DriveVME string pretty prints the data, other choices include binary. //and space, fixed field or comma delimited variables. See AssistVME. //There is no reason you couldn't use "open()" "read()" "write()" and "close()". "V:\\M\\sEa(a000#100)t(2A)rNwNp(rTwT)c(DC3MS)i(MS800)f(P)e(N)"); if (han!=INVALID_HANDLE_VALUE) { //Did it. //Use the file method to read it back. if (-1==SetFilePointer(han,linesize,NULL,FILE_BEGIN)) errors++; //start on the second line if (ReadFile(han,&str,linesize,&got,FALSE)) { if (got==linesize) { str[got]=0; printf("DriveVME pretty printed range:\n%s\n",str); } else { puts("System Error"); errors++; } } //File I/O Seeking, reading and writing work for remote VME chassis. if (!End_VME_Range_by_File(han)) errors++; //Optional, program termination will also end the map. } else { //Note: If DriveVME is loaded, a full reason for the failure is sent to //the DriveVME log. And AssistVME will pop up to display it. puts("DriveVME is either not running or couldn't allocate the desired resource.\n"); printf("Windows Error Code : %lx\n",GetLastError()); errors++; } } */ /**********************************************************************************/ /********* Access VME Memory directly via a local array **************/ //The "rangespec" parameter is an ASCII string identifying the range to be mapped. //Use the graphical "AssistVME" program's "Map" function to create and test //the VME device's proper operations, then cut the string AssistVME provides, //and paste it in your program as the parameter to these functions. //NOTE: Array based VME access functions are NOT supported over networks. //NOTE: The maximum width of the transfer is set by the specification string, so // for example a Map_D32_.. transfer would actually occur as 4 D8 transfers if the // maximum permitted transfer width specified in the setup string was D8. //NOTE: Every platform may not support all possible VME transfer widths. If the // map function succeeds and returns a non-zero pointer, it //Note: This function checks the passed in "filename" against the list of //Keys stored in the local chassis DriveVME registry, substituting the stored //value if any match is found. If none is, the passed in name is treated //like a filename in it's own right. This feature allows for user //modification of VME realities without recompliling the program. //These routines return 0 if the hardware doesn't support memory mapped at //the desired width. However, if the file handle spec is returned != INVALID_FILE_HANDLE //then the memory is available nevertheless, but it is only accessible via the //Mapped_xxx routines below. This is typically only the case on DEC Alpha computers //when asking to map D8 or D16 cycle limited memory. #define Map_D8_VME_Range_By_Name(rangespec,p_handle) ((unsigned char *)Map_VME_Range_by_Name(rangespec,p_handle)) #define Map_D16_VME_Range_By_Name(rangespec,p_handle) ((unsigned short *)Map_VME_Range_by_Name(rangespec,p_handle)) #define Map_D32_VME_Range_By_Name(rangespec,p_handle) ((unsigned long *)Map_VME_Range_by_Name(rangespec,p_handle)) #define Map_D64_VME_Range_By_Name(rangespec,p_handle) ((unsigned __int64 *)Map_VME_Range_by_Name(rangespec,p_handle)) DllStatus void *Map_VME_Range_by_Name(IN const char *rangespec,OUT HANDLE *map_handle); #define End_VME_Range_Map(map_handle) CloseHandle(map_handle) /* //Example: #include <dvmedll.h> #include <stdio.h> void demo_mapping_vme_resource(){ HANDLE han; unsigned char *A16_offset5; puts("Checkout: Presenting VME memory as a 'C' array."); A16_offset5 = Map_D8_VME_Range_By_Name("V:\\V\\sIa(5-6)t(1)rNwNp(rAwA)c(DC3MS)i(MS800)e(N)",&han); if (A16_offset5) { printf("Offset 5 is %x, 6 is %x.\n",A16_offset5[0],A16_offset5[1]); if (!End_VME_Range_Map(han)) errors++; //Optional, program termination will also end the map. } else { //Note: If DriveVME is loaded, a full reason for the failure is sent to the DriveVME log. //And AssistVME will pop up to display it. puts("DriveVME is either not running or couldn't allocate the desired resource.\n"); printf("Windows Error Code : %lx\n",GetLastError()); errors++; } } */ //Not all interfaces and processors support 8, 16 and 32 bit transfers natively. //For example, DEC Alpha processors in their native mode will only perform D32 cycles, //extracting or splicing in bytes or 16 bit values from these as necessary. //One way to insure the desired transfer width without processor dependance is to use the file //I/O method for VME access outlined above, setting the file position //to the desired offset then reading or writing as many bytes as desired. This method //always uses exactly the specified transfer width. However, these requests may be serialized //or use DMA and so incur substantial overhead. //The purpose of these routines is to provide the lowest overhead method in user mode of accessing //VME resources without serialization. This method is the fastest for short transfers. //These Mapped_xx_Read_1 routines will -1 on any error and //Bus errors will be treated as specified in the file open string. DllStatus unsigned char Mapped_D8_Read_1 (HANDLE Mapped_Range_Handle,unsigned long byte_offset); DllStatus unsigned short Mapped_D16_Read_1(HANDLE Mapped_Range_Handle,unsigned long byte_offset); DllStatus unsigned long Mapped_D32_Read_1(HANDLE Mapped_Range_Handle,unsigned long byte_offset); DllStatus unsigned __int64 Mapped_D64_Read_1(HANDLE Mapped_Range_Handle,unsigned long byte_offset); //The following functions will return TRUE upon success, FALSE if any error. //They all take as arguments the file handle of the map, the offset in bytes from the beginning of the //map to the first desired byte of the transfer, and a pointer to either the source or destination of //the data. If there is a range, filehandle or other boundary error, these routines will return FALSE, //they will not generate any other exceptions. Use these instead of .._Read_1 if exceptions on errors //are not desired. These routines will not align unaligned transfers (use file I/O for that). DllStatus BOOLEAN Mapped_D8_Read_N (HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned int byte_count,unsigned char *values); DllStatus BOOLEAN Mapped_D16_Read_N(HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned int word_count,unsigned short *values); DllStatus BOOLEAN Mapped_D32_Read_N(HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned int long_count,unsigned long *values); DllStatus BOOLEAN Mapped_D64_Read_N(HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned int int64_count,unsigned __int64 *values); DllStatus BOOLEAN Mapped_D8_Write_1 (HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned char value); DllStatus BOOLEAN Mapped_D16_Write_1(HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned short value); DllStatus BOOLEAN Mapped_D32_Write_1(HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned long value); DllStatus BOOLEAN Mapped_D64_Write_1(HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned __int64 value); DllStatus BOOLEAN Mapped_D8_Write_N (HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned int count,unsigned char *values); DllStatus BOOLEAN Mapped_D16_Write_N(HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned int count,unsigned short *values); DllStatus BOOLEAN Mapped_D32_Write_N(HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned int count,unsigned long *values); DllStatus BOOLEAN Mapped_D64_Write_N(HANDLE Mapped_Range_Handle,unsigned long byte_offset,unsigned int count,unsigned __int64 *values); //Users can specify patterns of mapped memory transfers by making arrays of this structure: struct dll_mapped_io_instruction { unsigned long zero_for_VME_read_not_zero_for_VME_write; unsigned long transfer_width; //0->transfer bytes using D8's, //1->transfer words using D16's, //2->transfer DWords using D32's, //3->transfer QWords using D64's. unsigned long cycle_count; //The number of consecutive cycles //So if transfer_width is 2 and this is 1, then 2 D32 cycles //will move 8 bytes. An entry of zero will end the processing. unsigned long vme_offset; //BYTE offset from mapped VME start address range for transfer void *value; //The address of the first byte in user space for the transfer. }; //Passing an array of the above structure to this routine will permit VME master mode //access via (not network enabled) memory maps. These routines are available at all //times and are useful when the processor platform does not permit small memory cycles //natively. On processors which do support such native cycles, these routines are //implemented in the user mode, on processors which don't, the requests are passed //into kernel mode. //Mapped_Pattern_Transfer returns the number of structre elements which were processed //without error, or -1 if the request failed before the first structure element was //considered. DllStatus int Mapped_Pattern_Transfer(HANDLE Mapped_Range_Handle,struct dll_mapped_io_instruction *map,int map_count); /***************************************************************************************/ /***** Offer local memory to VME boards, access locally via array or by network file ****/ //The "rangespec" parameter is an ASCII string identifying the range to be mapped. //Use the graphical "AssistVME" program's "Slave" function to create and test. //Then cut the string AssistVME provides, paste it in your program as the parameter //to these functions. struct Offered_Memory_Details { PVOID *offered_memory_base; //base address of shared memory in local process space unsigned long vme_base_address; //VME offset to (char *)offered_memory_base unsigned long vme_base; //low VME address decoded to support this request. unsigned long vme_bound; //high VME address decoded to support this request. }; //Note: This function checks the passed in "filename" against the list of //Keys stored in the local chassis DriveVME registry, substituting the stored //value if any match is found. If none is, the passed in name is treated //like a filename in it's own right. This feature allows for user //modification of VME realities without recompliling the program. //The function returns result->offered_memory_base DllStatus void *Offer_VME_Local_Memory_by_Name(IN const char *rangespec, OUT HANDLE *map_handle,OUT /*optional*/ struct Offered_Memory_Details *result); #define End_Offering_to_VME(map_handle) CloseHandle(map_handle) /* //Example: #include <dvmedll.h> #include <stdio.h> void demo_offering_local_memory(){ struct Offered_Memory_Details ranges; HANDLE han; unsigned long *A32_offset,test,got; //Allocate some slave memory, filename from AssistVME. puts("Checkout: Offer local memory to VME, access as an array"); A32_offset = Offer_VME_Local_Memory_by_Name( "V:\\S\\sEcNcPp(A)t(N)a(#100)uNuCuIe(N)",&han,&ranges); if (A32_offset) { //Did it. //Use the array method to set a value. A32_offset[2] = 0x01010101; //Assume opening a local VME chassis printf("If not via network: VME Offset %lx is now %lx\n", ranges.vme_base_address+2*sizeof(long), A32_offset[2]); //Use the file method to read it back. if (-1==SetFilePointer(han,2*sizeof(long),NULL,FILE_BEGIN)) errors++; if (ReadFile(han,&test,sizeof(test),&got,FALSE)) { if (got==sizeof(test)) { if (test != 0x01010101) { errors++; puts("DriveVME Data Error."); } else puts("OK File & Array method matched"); } else { puts("System Read Error"); errors++; } } //File I/O Seeking, reading and writing work for remote VME chassis. if (!End_VME_Range_Map(han)) errors++; //Optional, program termination will also end the map. } else { //Note: If DriveVME is loaded, a full reason for the failure is sent to //the DriveVME log. And AssistVME will pop up to display it. puts("DriveVME is either not running or couldn't allocate the desired resource.\n"); printf("Windows Error Code : %lx\n",GetLastError()); errors++; } } */ /**************************************************************************/ /****** Lock the VME bus during uninterruptable operations or to avoid ***/ /****** deadlocks on systems which don't support simultaneous master/slave cycles.*/ // These functions ensure access to the VME bus is locked to this computer // for the duration of the call to the function passed in. Whether the bus // is or is not locked outside the context of this call is undefined, however // the bus does not stay locked outside the context of standing requests from // at least one process. The return value is the value the passed function returns. // NOTE: The calling thread is set to operate at the highest possible scheduling // priority while the bus is locked. Don't execute any busy loops // in expectation of action by other tasks or processes within this call. // The thread is returned to it's previous priority when the call returns. // NOTE: There is some time overhead associated with these calls, it is good // design to perform fewer calls that do more than many sequential calls. // WARNING: While the VME bus is locked to this computer, no other transfers can // occur on the VME bus. DllStatus unsigned char D8_Lock_VME_Bus_Then_Call (unsigned char (*yourfunc )(long arg,void *context),long arg,void *context); DllStatus unsigned short D16_Lock_VME_Bus_Then_Call(unsigned short(*yourfunc)(long arg,void *context),long arg,void *context); DllStatus unsigned int D32_Lock_VME_Bus_Then_Call(unsigned int (*yourfunc)(long arg,void *context),long arg,void *context); DllStatus unsigned __int64 D64_Lock_VME_Bus_Then_Call(__int64 (*yourfunc)(long arg,void *context),long arg,void *context); // NOTE: Some VME hardware implementations suffer from a bug which will result in bus // errors or even deadlocks when concurrent slave/master cycles occur. // If you map memory on such a system, unless you know that no other program // (like bus networks) will _ever_ run concurrently you should only access // VME memory via array in the context of one of these calls. //Returns TRUE iff concurrent master/slave cycles are not supported on this system. DllStatus BOOLEAN VME_MasterSlaveDeadLock_Watch(void); //Returns TRUE iff concurrent master/slave cycles are not supported on this system //AND some process somewhere is currently offering slave cycles. DllStatus BOOLEAN VME_MasterSlaveDeadLock_Warning(void); // These next procedures act as their above counterparts if // VME_MasterSlaveDeadLock_Warning() is true, otherwise they will // just call the supplied function with no VME or other priority changes. // These are the safest calls to use, as the overhead is one test in systems // which support concurrent master/slave operations. DllStatus unsigned char D8F_Lock_VME_Bus_Then_Call (unsigned char (*yourfunc)(long arg,void *context),long arg,void *context); DllStatus unsigned short D16F_Lock_VME_Bus_Then_Call(unsigned short(*yourfunc)(long arg,void *context),long arg,void *context); DllStatus unsigned int D32F_Lock_VME_Bus_Then_Call(unsigned int (*yourfunc)(long arg,void *context),long arg,void *context); DllStatus unsigned __int64 D64F_Lock_VME_Bus_Then_Call(__int64 (*yourfunc)(long arg,void *context),long arg,void *context); /******************************************************************************/ /****************** Kernel C Program Support **********************************/ //These two routines support running a "C" program in the kernel mode of this //processor. First you should use AssistVME's development environment to verify //the operation of the program. Then, you can either pass the source as a string //or the name of a file to these routines. The first action must be a read on the //file handle, this will compile and begin the operations of the program. Anything //output by the program (printf, console writes, etc) will satisfy reads you make //to the provided handle. Writes you make to the handle satisfy console input //functions (scanf, gets, etc..). Overlapped read/writes are satisfied in the //order recieved and are supported (supports double buffering). The program is //terminated either due to run error, normal exit, or closing the file handle. //Upon termination, all pending I/O is satisfied with End of file status. //NOTE: These kernel C programs can generate and service interrupts, have timers, // and many most other usual features. They can also share memory with the // calling program and send windows messages. Use them to do limited, high // priority or real-time system actions, reserving all other processing to // the calling program. //NOTE: If these functions return with a valid handle, the supplied program has // started to run, and may have finished or had some error. Reads or writes // to the handle will be returned immediately with EOF if the program isn't // running, pending asychronous writes/reads will also be returned that way. //NOTE: These functions merely open the file "V:\I\C, write the source to it, then // start the program by doing a zero byte read. (The first read could be of // any size, but zero byte reads are satisfied with no action needed by the // supplied program.) If the V: drive or the V:\I directory is marked as // shared by the operating system, then programs may be submitted via a // network to remote processors, supporting remote diagnostics and debugging, // file I/O, etc. //WARNING: Access to the V:\ drive should be restricted to // authorized system level users. Full internal access to the system is exposed // via this interface. //The "overlapped" parameter if true opens the file in a mode which permits //the ReadFile and WriteFile commands to specify "overlapped" parameter which //permits them to return before the transfer is completed. This is handy for //transferring data in and out of background processing- supplying buffers //before they are needed without waiting for them to be filled. If the //parameter is false, the FILE_FLAG_OVERLAPPED parameter is not part of the //file open call, and the I/O operations block until the transfers are complete. DllStatus HANDLE Run_Win32_Kernel_C_Program_By_String(char *source,BOOLEAN overlapped); DllStatus HANDLE Run_Win32_Kernel_C_Program_By_File(char *source_filename,BOOLEAN overlapped); #define End_Win32_Kernel_C_Program(h) CloseHandle(h) /* Example: Run_Win32_Kernel_C_Program_By_String( "#include <stdio.h>\n\main(){ puts("Hello World"); }"); */ //These two routines work exactly as the above, but offer file handles //as supported by the <fcntl.h> mechanism, "open" "read" "write" "lseek" "close", etc. //These can be converted to streams by run time library functions. //*************WARNING*********** //Be sure to compile any application using the standard library calls to use the //multithreaded DLL version of the C runtime libraries. The statically linked libraries //do not share the file handle data. See the Build "settings" C/C++ "Code generation //menu, or just be sure to use the /MD or (/MDd for debug) flags //******************************* DllStatus int Run_Std_Kernel_C_Program_By_String(char *source); DllStatus int Run_Std_Kernel_C_Program_By_File(char *source_filename); #define End_Std_Kernel_C_Program(h) close(h) //Interrupt Generation //This generates a VME interrupt on the given level (1, 2, 3, 4, 5, 6 or 7) //and responding with the given vector (between 0-255). Using -1 for the vector //will use the system default VME interrupt acknowledgement vector. //Note: If it is necessary to generate more interrupts per second than this //method will accomodate, you should use the overhead reducing interrupt calls //below this one. Otherwise you must craft your own Drive/VME "C" program, which //can run uninterruptibly if need be. If that level of performance is not //sufficient, then you must craft your own Windows/NT device driver, which can //make direct interrupt generation calls to Drive/VME (as well have higher speed //access to all the functionality described here, and more, but at the expense //of complexity and lack of portability. //NOTE: Generate_VME_Interrupt will not return either VME_INT_PENDING or //VME_INT_ISSUED. When it returns, the interrupt will have either been //ackowledged, timed out, or rejected. There is a performance loss associated //with this, because the system waits for the acknowledgement. To queue calls //and process during the timeout or waiting for acknowledge period, (and better //performance generally) use the three calls following this one. DllStatus int Generate_VME_Interrupt(int level,int vector); //Return value is one of: #define VME_INT_ACKED 0 //Interrupt issued, acknowledged, idle. #define VME_INT_PENDING 1 //Interrupt waiting to be issued when cancelled. #define VME_INT_ISSUED 2 //Interrupt issued, not yet acked. #define VME_INT_IACK_TIMEOUT -1 //Interrupt issued, ack took too long. Aborted. #define VME_INT_NOT_ACCEPTED -2 //Interrupt never issued, not acceptable. //!note must agree with dvmeddk.h //The generate interrupt function is easiest for occasional interrupts which //are responded to within 3 seconds. For faster generation of interrupts use //the following three functions. Each returns one of VME_INT_... above. //The savings is in that the overhead of setting up the interrupt is accomplished //once. From then on, it is a matter of much lower overhead to trigger the interrupt. //NOTE: SOME VME implementations can only generate one interrupt at a time. That //means that requests to generate interrupts are serialized within Drive/VME. The //timeout on an interrupt which waits for the acknowledgement does not begin counting //until the interrupt is issued, but if there are many interrupt sources on your CPU //for VME, your requested interrupt may not begin until those "in line" ahead of it //are not only sent but also either timed out or acknowledged. Use AssistVME's //interrupt generation screen to see how many interrupts on any level have been //issued systemwide to check for possible timing contention issues with other //software. NOTE: The default timeout period to wait for an IACK is three seconds. //Note: The each chassis permits its own set of keys, using/setting up the keys //implies a reference to the currently chosen chassis. That is to say, //key one on chassis 1 is not the same as key 1 on chassis 2 unless you //specifically set it up to be that way with a chassis select + key setup calls. #define NUM_GENINT_KEYS 16 //Must agree with DriveVME kernel driver. //The following call sets up an interrupt for future generation. The key value //must be between 1 and below NUM_GENINT_KEYS. (key 0 is reserved for the //Generate_VME_Interrupt call.) If this call returns "ACKED", then future calls //to generate or read the generation status can proceed with the passed in key value. //the timeout is in units of 100ns and must be below 10 seconds, max. The minimum //value is 333. NOTE: Generating a VME interrupt or resetting a key before the //previous one has completed will result in the cancellation of the pending //interrupt if any. DllStatus int Generate_VME_Interrupt_KeySetup(int key,int level,int vector,int timeout); //If the above call returned no error, then initiate an interrupt passing only the //key with this call. If this call does not returns either VME_INT_PENDING //or VME_INT_ISSUED then the acknowledgement did not come in before the call returned. //Before generating another interrupt using key, see the next call. DllStatus int Generate_VME_Interrupt_ByKey(int key); //If the generate interrupt by key returned that the interrupt was either pending or //issued by not acknowledged, then call this until the result is not either pending //or issued. DllStatus int Generate_VME_Interrupt_KeyStatus(int key); //Programming Example: /* //Set up to generate a VME level 2 interrupt vector 0xac waiting at most 3 secs for //the iack. Set this up for key 1. if (!Generate_VME_Interrupt_KeySetup(1,2,0xac,3*10*1000*1000)) { int i,j; //Generate 5 of them as fast as possible, quit on any error. for (j=0;j<5;j++) { i = Generate_VME_Interrupt_ByKey(1); recheck: switch (i){ case VME_INT_PENDING: //When a VME interface can only //generate one interrupt and wait for one iack at a time, DriveVME //serializes interrupt requests in this case, and this one is still //"in line", another (from some source) is pending and not iacked yet. case VME_INT_ISSUED://sent, no iack yet, but not timeout either. i = Generate_VME_Interrupt_KeyStatus(1); goto recheck; case VME_INT_ACKED: break; //Interrupt sent and acknowledged case VME_INT_IACK_TIMEOUT: puts("Interrupt sent, timed out waiting for iack."); j=5; break; case VME_INT_NOT_ACCEPTED: puts("System not able to send VME interrupts."); j=5; break; default: puts("Unexplained error"); errors++; j=5; break; } } } */ #include "../commondist/dvmeinterface.h" //Interrupt sensing //These routines set the system to respond to VME interrupts. //The different VME related interrupt events are: //Note: for ASYNC_TIMER_WAKEUP, "low_limit" below specifies the wakeup //time in 100 nanosecond units. if "high_limit" below is 0, then the //event will recur until watching for it is cancelled, and the timing //period will not drift (though notice of the event may be delayed from //the actual time somewhat). If "high_limit" is not zero, the event //will occur once after the specified delay, then stop. #pragma pack(push,1) struct async_event_entry { int event_count; //count since monitoring began of interrupt events. int error_count; //count of interrupt acknowledgment (bus) errors. __int64 last_event_time;//Ticks since boot count of the last processed event. void *reserved; int last_result; //usually the last interrupt acknowledge vector }; //This structure describes the asynchronous event (like interrupts) //you want to watch or respond to. struct async_event_setup { int event_to_watch; //one of ASYNC_.... above. int high_limit; //like low_limit, except acknowledgement vectors //above high_limit will be ignored. 256 will capture //all interrupts at the chosen level. Note: //it makes no sense to have high limit less than low limit. __int64 low_limit; //in the case of VME interrupts, should the //interrupting source (VME_INT_xx) offer //an acknowledgement vector below low_limit, //the interrupt will not trigger this routine. //use 0 to trap all interrupts at the chosen level //Note that high_limit and low_limit may be ignored for interrupt events //which have no information compontent (all of them above VME_INT_7 except //the timer). }; //This call returns the total number of VME bus errors which have occured //on the target system while it was executing VME master cycles. Note that //there is no good way to detect reliably which process caused the bus error. DllStatus unsigned long Query_VME_Bus_Errors(); //asserts VME sysfail signal for a little over, but at least, 250 milliseconds. DllStatus int Pulse_VME_SysFail(); //vme_bus_locking: //Call with 1 to ask that the bus be locked to this CPU. Returns with bus locked //and priority set above all tasks but below interrupts if it isn't already higher. //Call with 2 to decrement the bus lock counter, which when it hits 0 releases //the bus and resets to the priority extant at the time of bus locking. //Returns: how many outstanding requests this system has outstanding overall to keep //the VME bus locked (not just this process, but instantaneiously system wide). //Call with 0 to just get the return value but otherwise take no action //Note: an error occured if asking for the bus to be locked returns 0. //Note: using this call is generally a bad idea if your program is to //operate with third party VME programs. If your transaction needs the bus //to be locked, write a "kernel C" program to do the transfer quickly, or //second best is to use the DLL calls above for quickly lock the VME //bus, raising this process's task priority, call your function, //then release the VME bus //automatically (if the calling function is the only task that wants it) //upon return. #define VME_LOCK_SET 1 #define VME_LOCK_RELEASE 2 #define VME_LOCK_QUERY 0 DllStatus int vme_bus_locking(int); //By default, the DriveVME dll operates on the local chassis. //If you call set_vme_chassis(NULL), or set_vme_chassis("V:\\"); //operation is (re)set to the local chassis. To set further operations //to a remote chassis, supply the string referring to the shared Drive/VME //drive on that chassis. For example, set_vme_chassis("\\Rack2Chassis5\\V\\"); //Note that calls which explicitly require a filepath DO NOT refer to this //value (like Open_VME_Range_by_Name or Offer_VME_Local_Memory_by_Name) but //all other calls (like vme_bus_locking or Generate_VME_Interrupt and so on) do. //This function will return TRUE if the chassis value was changed to the //supplied value, otherwise FALSE (indicating no network VME chassis available). //To get a list of the available chassis and generally check them out, use //AssistVME's network button. //Note: Changing from one chassis to another does not end operations on //the first chassis. To end operations on a chassis use the call below. //Note: Chassis identifiers are not case sensitive. DllStatus BOOLEAN set_vme_chassis(char *chassis); //Returns the currently set chassis. declare chassis[255] in your code. //If the currently set chassis has been closed, this will return *0. DllStatus void get_vme_chassis(char *chassis); //Drive/VME operations on a chassis consume a thread and other resources, //Chassis operations should be ended if no further calls are planned. //Call this routine with the chassis name to end operations. //The function returns true if ongoing operations were ended, false if //there were no ongoing operations. DllStatus BOOLEAN free_vme_chassis(char *chassis); //Each process using DriveVME.DLL can support concurrent operations on //NUM_CONCURRENT_CHASSIS at the same time. This is an arbitrary figure, //If your application calls for more concurrent operations, contact //your supplier or N4. #define NUM_CONCURRENT_CHASSIS 50 //Front panel lamp management. Assumes two lamps. If the system has //only one lamp, it is implemented as the "Pass" lamp. #define PassLampTest 0 //returns PassLampSetOn or PassLampSetOff #define FailLampTest 1 //returns FailLampSetOn or FailLampSetOff #define LampSetOn 0x100 #define LampSetOff 0x200 #define PassLampSetOn (LampSetOn |PassLampTest) #define FailLampSetOn (LampSetOn |FailLampTest) #define PassLampSetOff (LampSetOff|PassLampTest) #define FailLampSetOff (LampSetOff|FailLampTest) //Returns -1 if error. DllStatus int front_panel_lamps(int lamp_action); //Returns the basic make and model of this particular system. //Note that the software interface to all systems is the same, //to ease porting and design flexibility //error if return is -1. DllStatus int get_vme_system_information(struct s_vme_system_information *sys); #define SYSRESET_QUERY 0 //return 1 if this system will reset upon VME sysreset, 0 if not, else not supported #define SYSRESET_TO_LOCAL 1 //cause sysreset to reset local CPU #define SYSRESET_IGNORE 2 //cause VME sysreset to have no local effect. DllStatus int vme_localsysreset(int action); #define PANELSYSRESET_QUERY 0 //return 1 if front panel switch or button causes SYSRESET, 0 if not, else not supported. #define PANELSYSRESET_SET 1 //Cause the front panel reset button or switch to reset the VME bus #define PANELSYSRESET_LOCAL 2 //Cause the front panel reset button or switch to not affect the VME bus DllStatus int vme_panelsysreset(int action); #define SYSCON_QUERY 0 //no changes, return current setting only #define SYSCON_ON 1 //set this processor as the system controller #define SYSCON_OFF 2 //set this processor as NOT the system controller //This function returns the current state of the processor after any requested //action is taken. Not all processors can enable or disable whether they //are the system controller after power up. A return value of 1 indicates //VME system control services are being provided. 0 -> not. DllStatus int vme_system_controller(int action); //if !vme_system_status(stats), then *stats and stats[1] are set as: //*stats& 2 -> VME interrupt 1 is enabled //*stats& 4 -> VME interrupt 2 is enabled //*stats& 8 -> VME interrupt 3 is enabled //*stats& 16 -> VME interrupt 4 is enabled //*stats& 32 -> VME interrupt 5 is enabled //*stats& 64 -> VME interrupt 6 is enabled //*stats&128 -> VME interrupt 7 is enabled //*stats&0x8000 -> ACFail interrupt enabled //*stats&0x4000 -> SysFail interrupt enabled //*stats&0x2000 -> Front Panel Switch nterrupt enabled //*stats&0x1000 -> Bus error interrupt enabled //stats[1] & 0x8000 -> ACFail asserted //stats[1] & 0x4000 -> Sysfail asserted DllStatus int vme_system_status(int *stats); //USER MODE INTERRUPT PROCESSING. //DriveVME supplies many modes of interrupt processing both for local //chassis and over networks. The interrupts can be due to the result //of physical events or the no-drift timers. These include sending windows //messages to a calling process, calling functions you provide, or providing //what appear to be ordinary files which satisfy read file calls when either //the events of interest or timeouts occur. The information supplied to the //caller of the file read descibes the event and when it happened. There //are two other higher performance methods of handling events and interrupts, //the kernel "C" Java routines, which are available over networks, and //also the Windows/NT kernel driver interface for highest performance. //The information supplied to each file read is: //This is the structure of the data when DriveVME //event structure files are read ( V:\H\....) (interrutps, ticks, alerts) struct DriveVME_Async_Event_ReadFileData { unsigned short status; //This value is ascii 'OK', with the letter 'O' in the low byte if the event //completed normally (whether a bus error or not), or 'TO' with a 'T' in the low byte //if completed due to a timeout. The ascii is to make it easier for high level applications //to use this facility, a simple one byte character read will get the most important information. unsigned short event; //This is the xx of the I(xx) parameter which opened this event file (16 bits) unsigned long number_of_events; //total number of times the event occurred without error //Note the above is incremented whether there was a read pending to record the event //or not. If 100 events happened and only one read request was made just before the //100th event happened, the value returned here would be 100, not 1. unsigned long information; //the acknowledgment IACK value, -1 if bus error during iack. __int64 timestamp; //64 bits, the local performance counter time in QueryPerformanceFrequency() //units since bootup when the event happened. }; #pragma pack(pop) //Programmers can specify that functions of the following type be called when //events and/or interrupts of interest occured, or when there was a //timeout waiting for the event. These functions are called independantly //of whether or not the user has asked that windows messages are sent //upon event or interrupt detection. Remember, these callbacks in particular //and user mode program interrupt handling in general have slower performance //than kernel-"C"-Java routines. If the best interrupt performance is needed, //use the DriveVME Windows/NT kernel driver interface. typedef BOOLEAN (*PON_INTERRUPT_OR_EVENT)( BOOLEAN timeout, //If the event completed due to a timeout or error, this is true. If the //event occured it is false. unsigned short event, //one of ASYNC_xxx described above and also-- //This is the xx of the I(xx) parameter used which opened this event file (16 bits) //IF this event is 0xffff then there was a file read error. The result //of the file read error (GetLastError) is stored in the "information" parameter. //if information is 0, then the error was that a different number of bytes //than expected was returned. unsigned long number_of_events, //Total number of times the event occurred without error //Note the above is incremented whether there was a read pending to record the event //or not. If 100 events happened and only one read request was made just before the //100th event happened, the value returned here would be 100, not 1. unsigned long information, //In responding to an interrupt, the VME acknowledgment IACK value, This //value is -1 if bus error during iack. __int64 timestamp, //64 bits, the local performance counter time in QueryPerformanceFrequency() //units since bootup when the event happened. void *context //whatever parameter was passed to Open_Interrupts_And_Events_Handler ); //If the function returns TRUE, then the function will be called again when the next //event or timeout is detected. If the function returns false, then the function //will not be called again as a result of the event handle. Returning FALSE has the //same effect as calling Close_Interrupts_And_Events_Handler. If you call //Close_Interrupts_And_Event_Handler for a handle after returning FALSE on an event //call, your application will crash with a memory error. Use either one method, or the other, //don't use both. //Note: This function checks the passed in "filename" against the list of //Keys stored in the local chassis DriveVME registry, substituting the stored //value if any match is found. If none is, the passed in name is treated //like a filename in it's own right. This feature allows for user //modification of VME realities without recompliling the program. DllStatus PVOID Open_Interrupts_And_Events_Handler(IN const char *interrupt_spec,PON_INTERRUPT_OR_EVENT callback_func,PVOID context); //This routine expects a local or remote DriveVME filename, as developed in the graphical //AssistVME program's "ISR" section, and as documented in the DriveVME interrupt handler //filespec document. Basically a local or network remote filename that determines the //interrupt or event of interest and what to do when it happens. One option (which can't be //used over networks) is that the calling thread recieve a windows message when the event occurs. //This option can be specified in the filename, and if specified occurs whether or not a //callback function is supplied here. // //The context parameter passed into this function is passed to the interrupt service routine. // //Another option supported by these routines both on the local chassis and on network chassis //is that a function whose name you specify be called //upon the detection of each event (or timeout notice if no event occurs). This is implemented //by creating a second thread of execution in the calling process-- so be advised that if //a function name is supplied to the following function, a thread will be created to run it, //and that the supplied function may be called upon at any time or point of execution in the //caller's program. // //Therefore, if the supplied function makes changes to data that may also be in use by the //user's main thread, the user must use mutex, event or semaphore synchronization objects //to avoid data corruption by synchronizing access to the shared data. // //If the supplied function pointer is NULL, then no function will be called upon event //occurance. If a NULL function is supplied, this presumes that the user's file //specification called for windows mesages be sent to the calling thread //This function returns NULL if there was an error, use GetLastError() to determine the //cause of any failure. Otherwise the function returns a pointer which can be passed to //Close_Interrupts_and_Event_Handler to conclude operations. // //Note: These routines do nothing more than open the supplied file, and if a callback //function is supplied, create a thread which keeps two overlapped reads outstanding, //calling the supplied function with the results of those reads, until such time as the //Close_Interrupts_And_Events_Handler is called. Cleanup upon abnormal program termination //is enabled. // //The user is free to use any file open method to open an event or interrupt handling //file. If asked for in the file specification, windows messages will be sent so long //as the file is open. Any program which can read files can just read the interrupt //file handle, which will return with data when the event happens or there is a timeout. //The format of the returned data is: /* struct DriveVME_Async_Event_Read { unsigned short status; //This value is ascii 'OK', with the letter 'O' in the low byte if the event //completed normally (whether a bus error or not), or 'TO' with a 'T' in the low byte //if completed due to a timeout. The ascii is to make it easier for high level applications //to use this facility, a simple one byte character read will get the most important information. unsigned short event; //This is the xx of the I(xx) parameter which opened this event file (16 bits) unsigned long number_of_events; //total number of times the event occurred without error //Note the above is incremented whether there was a read pending to record the event //or not. If 100 events happened and only one read request was made just before the //100th event happened, the value returned here would be 100, not 1. unsigned long information; //the acknowledgment IACK value, -1 if bus error during iack. __int64 timestamp; //64 bits, the local system time in 100ns units since bootup when the event happened. }; */ //If the file is opened with the Win32 function CreateFile with the FILE_FLAG_WRITE_THROUGH //(for network operations) and FILE_FLAG_OVERLAPPED, then the user may issue read requests //which it can check at it's convenience and so avoid having to contend with synchronization //issues. Check the Win32 functions ReadFile and GetOverlappedResult for programming details, //as well as the DvmeMFCDemo file for programming examples of this sort of use. //This function takes the result of Open_Interrupts_and_Event_Handler, frees //resources used, cleans up, and stops detecting events. NOTE: IT IS AN ERROR //to call this function if a supplied interrupt handling function returned FALSE. //returning FALSE has the same effect as this call. DllStatus void Close_Interrupts_and_Event_Handler(PVOID Open_Interrupts_Result); #ifdef __cplusplus } #endif