Book Links: ...
CEDriverWiz generates a custom Stream Driver project along with optional test applications. The main function of the driver is to implement a simple strings buffer that writes a string passed it to via an application stream write() call and reads the same string back with a read() to the stream. Whilst there are many options for the driver, the Stream Driver project generated by CEDriverWizStandardV2.00 does not implement some of these features. They are noted in the source file (.cpp) as comments and in most cases a debug message. The main option not implemented is the buffer mechanism. This example will implement the buffer in one of three modes.
The string buffer can be implemented in one of three modes:
This example will implement the buffer in a Global context. Our book covers Device Context in Chapter 32. (See also the chapter download). The Open Context can be inferred from Device Context methodology. See also the Whitepapers on the Windows Embedded Site:
With this method, the buffer is statically implemented in the shared memory that is the same for all instances of the driver DLL. That way all instances of the driver use the same DLL. That is, is STR1: , STR2: STR3: are all loaded for a stream driver, any read or write with any stream would use the same buffer. This would not normally be a desirable feature. But in reality where the driver is communicating directly with hardware registers, they are effectively in shared memory. The same registers would be addressable by all instances of a driver. The driver instances would make sure they refer to their assigned registers only. For example, a serial driver, COM1 would write to its transmit buffer whereas COM2, using the same NS16C2552 Dual UART would write to the other transmit buffer on the IC. The UART transmit and receive buffers are effectively write-only and read-only buffers in global memory.
A stream driver would typically instantiate data buffers in device context. That way each instance would have its own buffers. They would be instantiated on the heap in the stream XXX_Init() function and disposed of in the stream XXX_Deinit() function. See Chapter 32 for details.
When a driver is opened (XXX_Open() )by an application Open Context buffers would be instantiated (not when the driver is loaded) and disposed of when the stream is being closed (XX_Close()) (not when the driver is unloaded). Open context could be used to buffer data for a a thread where asynchronous IO is being used but an aspect of asynchronous IO is to provide application buffers to the driver to use, so perhaps not.
An application would open a stream, then call write() to write to a buffer and read() to read from it. This I/O is reflected in the driver as XXX_Write() and XXX_Read().Regardless of whichever context is used for the buffer, the write and read is performed in the same manner. The buffer is a fixed memory allocation and is implemented as a simple in/out system. It is not a FIFO, LIFO or Ring buffer. The write is placed from the start of the buffer and the read also is from the start of the buffer.
Open MyStream.cpp in the Stream Driver subproject.
In global space at the top of the file
Replace:
1: #pragma data_seg(".MYSEG")
2:
3: //Shared Memory devCount Global Declaration code not yet implemented
4:
5: //Shared Memory Buffer Global Declaration(Initialisation) code not yet implemented
6:
7: #pragma data_seg()
with:
3: static DWORD devCount=0;
5: static LPWSTR Buffer[BUFFER_SIZE/sizeof(WCHAR)];
In MyStreamInit()
Replace
1: //Shared Memory code to initialise devCount not yet implemented
1: DWORD max_devices = MAX_DEVICES;
2: if (devCount >= max_devices)
3: {
4: RETAILMSG(1,(TEXT("MyStream: STR_Init() Max devices has already been reached %d\n"),devCount));
5: return NULL;
6: }
7:
8: //Increment the device count
9: devCount++;
10: RETAILMSG(1,(TEXT("MyStream: STR_Init() Init No. devices: %d\n"),devCount));
In MyStream_Deinit()
1: //Report on device count as start of function' code not yet implemented
3: //Decrement the devCount
4: //Shared Memory code to decrement devCount not yet implemented
1: RETAILMSG(1,(TEXT("MyStream: STR_Deinit() IN devCount = %d\n"),devCount));
4: devCount--;
5: RETAILMSG(1,(TEXT("MyStream: STR_Deinit() OUT devCount = %d \n"),devCount));
In MyStream_Wrtite()
1: //Copy from pSourceBytes to the buffer
3: //Shared Memory Buffer code 'To copy from pSourceBytes to the Shared Memory Buffer' not yet implemented
4: RETAILMSG(1,(TEXT("MyStream: STR_Write() Copy from pSourceBytes to the Shared Memory Buffer not yet implemented.\n")));
3: // Copy the smaller of buffer size or number of bytes they send us.
4: DWORD numToWrite min(BUFFER_SIZE, NumberOfBytes);
5: //Note: numToWrite gets corrupted ??
6: dwRet = numToWrite;
8: memcpy((void *)Buffer, (void *)pSourceBytes, numToWrite);
9:
10: RETAILMSG(1,(TEXT("MyStream: STR_Write() Wrote %d pSourceBytes to the Open Context Buffer.\n"),dwRet));
In MyStream_Read()
1: //Copy from Buffer to pDestinationBytes
3: //Shared Memory Buffer code to copy from Shared Memory Buffer to pDestinationBytes not yet implemented
4: RETAILMSG(1,(TEXT("MyStream: STR_Read() Copy from Shared Memory Buffer to pDestinationBytes not yet implemented.\n")));
4: DWORD numToRead min(BUFFER_SIZE, NumberOfBytes);
6: dwRet = numToRead;
8: memcpy((void *)pDestinationBytes,(void *)Buffer, numToRead);
10: RETAILMSG(1,(TEXT("MyStream: STR_Read() Wrote %d bytes from Open Context to pDestinationBytes.\n"),dwRet));
Running MyStreamTestApp before modifications:
203394 PID:15a0076 TID:109000a MyStream: STR_Open() BEGIN
203394 PID:15a0076 TID:109000a MyStream: STR_Open() END
203394 PID:107000a TID:109000a MyStreamTestApp: Openned STR1:
203394 PID:15a0076 TID:109000a MyStream: STR_Write() BEGIN
203394 PID:15a0076 TID:109000a MyStream: STR_Write() Copy from pSourceBytes to the Shared Memory Buffer not yet implemented.
203394 PID:15a0076 TID:109000a MyStream: STR_Write() END
203395 PID:107000a TID:109000a MyStreamTestApp: Wrote to buffer: "This is a test of the MyStream Driver. This is only a test."
203395 PID:107000a TID:109000a MyStreamTestApp: Wrote to buffer 1 bytes
203395 PID:15a0076 TID:109000a MyStream: STR_Read() BEGIN
203395 PID:15a0076 TID:109000a MyStream: STR_Read() Copy from Shared Memory Buffer to pDestinationBytes not yet implemented.
203395 PID:15a0076 TID:109000a MyStream: STR_Read() END
203395 PID:107000a TID:109000a MyStreamApp: Read from buffer 1 bytes
203395 PID:107000a TID:109000a MyStreamTestApp: Read OK
203395 PID:107000a TID:109000a MyStreamTestApp: (OK) Num bytes read = num written. 1
203395 PID:107000a TID:109000a MyStreamTestApp: Read from buffer: ""
203396 PID:15a0076 TID:109000a MyStream: STR_PreClose() BEGIN
203396 PID:15a0076 TID:109000a MyStream: STR_PreClose() END
203396 PID:15a0076 TID:109000a MyStream: STR_Close() BEGIN
203396 PID:15a0076 TID:109000a MyStream: STR_Close() END
Note that the buffer is not yet implemented and reports one byte copied. It isn’t really one byte. The return value from XXX_Read() and XXX_Write() has to be non zero (error otherwise) so for unimplemented buffer it is set to one.
Running MyStreamTestApp before after modifications:
35107 PID:400002 TID:23a016a RELFSD: Opening file MyStreamTestApp.exe from desktop
35223 PID:2fe00b2 TID:23a016a MyStream: STR_Open() BEGIN
35223 PID:2fe00b2 TID:23a016a MyStream: STR_Open() END
35224 PID:204017a TID:23a016a MyStreamTestApp: Openned STR1:
35224 PID:2fe00b2 TID:23a016a MyStream: STR_Write() BEGIN
35224 PID:2fe00b2 TID:23a016a MyStream: STR_Write() Wrote 118 pSourceBytes to the Open Context Buffer.
35224 PID:2fe00b2 TID:23a016a MyStream: STR_Write() END
35224 PID:204017a TID:23a016a MyStreamTestApp: Wrote to buffer: "This is a test of the MyStream Driver. This is only a test."
35224 PID:204017a TID:23a016a MyStreamTestApp: Wrote to buffer 118 bytes
35225 PID:2fe00b2 TID:23a016a MyStream: STR_Read() BEGIN
35225 PID:2fe00b2 TID:23a016a MyStream: STR_Read() Wrote 118 bytes from Open Context to pDestinationBytes.
35225 PID:2fe00b2 TID:23a016a MyStream: STR_Read() END
35225 PID:204017a TID:23a016a MyStreamApp: Read from buffer 118 bytes
35225 PID:204017a TID:23a016a MyStreamTestApp: Read OK
35225 PID:204017a TID:23a016a MyStreamTestApp: (OK) Num bytes read = num written. 118
35225 PID:204017a TID:23a016a MyStreamTestApp: Read from buffer: "This is a test of the MyStream Driver. This is only a test."
35225 PID:2fe00b2 TID:23a016a MyStream: STR_Close() BEGIN
35225 PID:2fe00b2 TID:23a016a MyStream: STR_Close() END
Note that the buffer is now implemented and it reports 118 bytes transferred in both directions. Wala!
Loading the driver:
31160 PID:4d60002 TID:4d80002 Registry key created OK
31160 PID:4d60002 TID:4d80002 Registry key DLL written OK
31161 PID:4d60002 TID:4d80002 Registry key prefix written OK
31161 PID:4d60002 TID:4d80002 Registry Flag (UserMode Load=16) Drivers\MyStream set OK
31161 PID:4d60002 TID:4d80002 Registry key closed OK
31270 PID:5d20006 TID:4d80002 MyStream: STR_Init() BEGIN
31270 PID:5d20006 TID:4d80002 MyStream: STR_Init() Active Registry Key= Drivers\Active\48
31270 PID:5d20006 TID:4d80002 MyStream: STR_Init() DEVICE CONTEXT BEGIN
31271 PID:5d20006 TID:4d80002 MyStream: STR_Init() Device Context ptr is: 30B50
31271 PID:5d20006 TID:4d80002 MyStream: STR_Init() DEVICE CONTEXT END
31271 PID:5d20006 TID:4d80002 MyStream: STR_Init() END
31271 PID:4d60002 TID:4d80002 MyStreamLoadApp: Device HANDLE is CEE93364
31271 PID:4d60002 TID:4d80002 MyStreamLoadApp STRx: Loaded OK
Running Unload app:
297219 PID:400002 TID:107000e RELFSD: Opening file MyStreamUnloadApp.exe from desktop
297335 PID:15a0076 TID:107000e MyStream: STR_Open() BEGIN
297335 PID:15a0076 TID:107000e MyStream: STR_Open() END
297336 PID:10a000e TID:107000e MyStreamUnloadApp: Device HANDLE is CC555FF4
297336 PID:15a0076 TID:107000e MyStream: STR_PreClose() BEGIN
297336 PID:15a0076 TID:107000e MyStream: STR_PreClose() END
297336 PID:15a0076 TID:107000e MyStream: STR_Close() BEGIN
297336 PID:15a0076 TID:107000e MyStream: STR_Close() END
297337 PID:15a0076 TID:107000e MyStream: STR_PreDeinit() BEGIN
297337 PID:15a0076 TID:107000e MyStream: STR_PreDeinit() END
297337 PID:15a0076 TID:107000e MyStream: STR_Deinit() BEGIN
297337 PID:15a0076 TID:107000e MyStream: STR_Deinit() Device Context ptr is: 30B50
297337 PID:15a0076 TID:107000e MyStream: STR_Deinit() END
297339 PID:10a000e TID:107000e MyStreamUnloadApp: Unloaded driver instance: STR1: