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