Introduction
This article explains a generic communication interface to a peripheral device with a slower or faster data transfer rate than the data input. A typical scenario would be transferring data from a file to a serial port or a USB device or to the Internet wherein the data transfer rate is slower.
Buffered Carrier
Buffered carrier is a multi threaded interface which can be used for bulk data transfer to a slower peripheral device or network. If you need to transfer data to an external device to which the data transfer rate is slow, then this interface could be an option. The code is programmed in such way that the users can easily connect between the data provider and peripheral driver.
The diagram above explains the basic structure of the interface. Following are the participants:
Data Provider
Prepare data required to be passed to the terminal device.
Data Carrier
Supply the data to the terminal device or device driver.
Common buffer
This is the critical resource which acts as the channel for data transfer between the data provider and data carrier.
Here there are two threads: one for supplying data to the common buffer and one to push the data from the buffer to a peripheral device. The common buffer acts as the channel between the data provider and the data carrier. This is a critical resource and access to it is synchronized.
Check the flow chart below for more details.
Main Thread (Data provider)
Buffered carrier thread
Usage
To explain the usage of the buffered carrier interface, we will consider an example of copying a file. Here the data provider is the file reader and the device driver is the file writer. We introduce an additional delay of 10ms between each write operation to simulate a peripheral communication.
Dataprovider Code
Step 1
First create a file carrier with the specified buffer size and block size. The buffer size represents the block of data which will be shared between the data provider and the data supplier. The block size represents the unit data taken from the buffer by the carrier for each transfer operation.
BufferedCarrier myBufferedCarrier(BUFFER_SIZE,BLOCK_SIZE);
Step 2
Now prepare data for transfer.
int count = fread(buffer,sizeof(char),BLOCK_SIZE,fpsrc);
Step 3
Now check whether there is space for one more block in the buffer. If there is, push the data. Or else, wait for the buffer to get freed.
while(myBufferedCarrier.getFreeBufferSize() < BLOCK_SIZE)
{
Sleep(20);
CLogger::getInstance()->log(5,"Waiting for enough buffer space.
Buffer size %d\n",myBufferedCarrier.getFreeBufferSize());
}
Step 4
Push data to the buffer once space is available in the buffer.
myBufferedCarrier.writeIOBuffer(buffer,count);
Repeat steps 2 to 4 and push all the data to the buffer.
Step 5
Inform the buffered carrier that there is no more data to transfer.
myBufferedCarrier.stopTransfer();
Step 6
Wait for the buffered carrier to transfer all the data.
while(myBufferedCarrier.isTransferInProgress())
{
Sleep(20);
}
Driver Connection Interface
In the buffered carrier, the user needs to add codes for peripheral communication. The following functions are provided for the same.
void BufferedCarrier::initializeDriver()
{
}
void BufferedCarrier::transferDatadriver()
{
FILE *fpDest = fopen("C:\\temp\\out.txt","ab+");
Sleep(10);
if(fpDest != NULL)
{
fwrite(txBlock,sizeof(char),dataBlkSize,fpDest);
fclose(fpDest);
}
}
void BufferedCarrier::deInitializeDriver()
{
}
To view the sequence of operations, a simple logger code has been provided along with the code. By setting appropriate values for the predefined values in logger.h, you can view the operations.
#define TRACE //Enable or disable logging.
#define TRACE_FILE //Enable file logging.
#define TRACE_FILE_NAME "c:\\temp\\bpt_trace.txt"
#define TRACE_CONSOLE // Enable console logging.
Conclusion
This article is an attempt to provide a generic interface to a communication channel which is much slower or faster than the input data provider (a peripheral device or a slow communication channel). This is implemented using the Windows thread functions and synchronization between threads are achieved using critical section. Similar implementation can be done for Linux using "pthread_
" functions. I can write one for you if you need but on request.
Please send your valuable suggestions and feedback to bobypt@gmail.com.