The following example shows that the same DAC channel, named "dac-ch0", can be shared among two threads of the same process.
Please read the output the test produces.
Run-daccs - setup environment to use .\rulbus.conf, run daccs. Using RULBUS=isa ___ DacCS 1.0 (22 Jan 2004) Use Rulbus DAC from a client and a server thread. This program creates a server thread and a client thread. Server: generate a squarewave on DAC channel 0 [data 1000,3000]. Client: read the data from DAC channel 0 and check its values; also copy data read to DAC channel 1. The server thread is intentionally started somewhat later than the client thread to show an error report from the latter. ISA Rulbus Interface at [0x200], using CanIO port I/O opened Rulbus device 'dac-ch0' at [0:0xD0] opened Rulbus device 'dac-ch1' at [0:0xD2] creating thread for server creating thread for client Press a key to stop... client: reading data from Rulbus device 'dac-ch0' at [0:0xD0] client: copying data to Rulbus device 'dac-ch1' at [0:0xD2] client: dac handle 0 data 1234 not in [1000,3000] client: dac handle 0 data 1234 not in [1000,3000] server: write squarewave on Rulbus device 'dac-ch0' at [0:0xD0] Terminating... prompt>
Here is the Rulbus configuration file used.
# dac client--server test rack "top" { address = 0 rb8510_dac12 "dac-ch0" { address = 0xD0 } rb8510_dac12 "dac-ch1" { address = 0xD2 } }
The C++ source of the program.
/* * daccs.cpp - dac client-server. * * compile: bcc32 -P -q -tWC -tWR -tWM -I..\src .\daccs.cpp ..\bin\rulbus.lib */ #include <iostream> // for std::cout, std::cerr #include <conio.h> // for kbhit() #include <windows.h> // for DWORD HANDLE, Sleep() #include "rulbus.h" // for rb8510_dac12_open() etc. namespace ClientServer { const char *title = "DacCS 1.0 (22 Jan 2004) Use Rulbus DAC from a client and a server thread.\n"; int threads ( ); HANDLE mkThread( const char *msg, DWORD WINAPI (*ThreadFunc)(LPVOID), int32 *pHandle ); DWORD WINAPI client ( LPVOID arg ); DWORD WINAPI server ( LPVOID arg ); int error ( ); volatile bool runthread = true; // true while threads should run const int NoCode = 1234; // DAC 'no' code const int LoCode = 1000; // DAC lower code const int HiCode = 3000; // DAC higher code /* * Rulbus address tuple for channel 0 and 1 */ struct Tuple { int32 dac0; int32 dac1; }; #pragma argsused int main( int argc, char *argv[] ) { std::cout << title << std::endl; return threads(); } int threads() { std::cout << "This program creates a server thread and a client thread.\n" "\n" "Server: generate a squarewave on DAC channel 0 [data " << LoCode << ',' << HiCode << "].\n" "Client: read the data from DAC channel 0 and check its values;\n" " also copy data read to DAC channel 1.\n" "\n" "The server thread is intentionally started somewhat later than\n" "the client thread to show an error report from the latter.\n" << std::endl; /* * report on Rulbus Interface: */ rdl_printRulbusInterface(); /* * open two DAC channels: */ Tuple tuple; if ( rb8510_dac12_open( &tuple.dac0, "dac-ch0" ) || rb8510_dac12_open( &tuple.dac1, "dac-ch1" ) ) { return error(); } std::cerr << "opened "; RulbusDevice_print( tuple.dac0 ); std::cerr << "opened "; RulbusDevice_print( tuple.dac1 ); std::cerr << std::endl; /* * initialize DAC outputs to be different from server output: */ rb8510_dac12_setValue( tuple.dac0, NoCode ); rb8510_dac12_setValue( tuple.dac1, NoCode ); /* * create and resume client and server threads; * intentionally resume the server thread somewhat later * to notice the error report from the client thread. */ HANDLE thread0 = mkThread( "server", server, reinterpret_cast<LONG *>( &tuple ) ); HANDLE thread1 = mkThread( "client", client, reinterpret_cast<LONG *>( &tuple ) ); std::cerr << "\nPress a key to stop...\n" << std::endl; ResumeThread( thread1 ); Sleep( 2000 ); ResumeThread( thread0 ); /* * wait for key pressed; eat character: */ while ( !kbhit() ) Sleep( 10 ); (void) getch(); /* * stop and remove threads and close DACs: */ std::cerr << "\nTerminating..." << std::endl; runthread = 0; Sleep( 10 ); CloseHandle( thread0 ); CloseHandle( thread1 ); if ( rb8510_dac12_close( tuple.dac1 ) || rb8510_dac12_close( tuple.dac0 ) ) { return error(); } return EXIT_SUCCESS; } HANDLE mkThread( const char *msg, DWORD WINAPI (*ThreadFunc)(LPVOID), int32 *pTuple ) { std::cerr << "creating thread for " << msg << std::endl; DWORD id; return CreateThread( NULL, // pointer to thread security attributes 0, // initial thread stack size, in bytes ThreadFunc, // pointer to thread function pTuple, // argument for new thread CREATE_SUSPENDED, // creation flags &id // pointer to returned thread identifier ); } DWORD WINAPI server( LPVOID arg ) { int32 dac0 = reinterpret_cast<Tuple *>(arg)->dac0; std::cerr << "server: write squarewave on "; RulbusDevice_print( dac0 ); while ( runthread ) { rb8510_dac12_setValue( dac0, LoCode ); Sleep( 0 ); rb8510_dac12_setValue( dac0, HiCode ); Sleep( 0 ); } return 0; } DWORD WINAPI client( LPVOID arg ) { int32 dac0 = reinterpret_cast<Tuple *>(arg)->dac0; int32 dac1 = reinterpret_cast<Tuple *>(arg)->dac1; std::cerr << "client: reading data from "; RulbusDevice_print( dac0 ); std::cerr << "client: copying data to "; RulbusDevice_print( dac1 ); while ( runthread ) { int32 n; if ( rb8510_dac12_getValue( dac0, &n ) || rb8510_dac12_setValue( dac1, n ) ) { return error(); } if ( n != LoCode && n!= HiCode ) { std::cerr << "client: dac handle " << dac0 << " data " << n << " not in [" << LoCode << ',' << HiCode << "]" << std::endl; Sleep ( 1000 ); } else { // do nothing // std::cerr << n << " "; Sleep(300); } Sleep(0); } return 0; } int error() { const int len = 100; char msg[len]; rdl_getLastError( msg, len ); std::cerr << msg << std::endl; return EXIT_FAILURE; } } // namespace ClientServer /* * End of file */
This is the batch command file used to invoke the program.
@echo off rem rem run-daccs.bat - setup environment to use .\run-daccs.conf, run daccs. rem cls echo Run-daccs - setup environment to use .\run-daccs.conf, run daccs. echo. set RULBUS.ORG=%RULBUS% set RULBUS_CONFIG_FILE.ORG=%RULBUS_CONFIG_FILE% :set RULBUS=epp,0x378;nocheck set RULBUS=isa echo Using RULBUS=%RULBUS% echo ___ echo. set RULBUS_CONFIG_FILE=run-daccs.conf copy ..\bin\rulbus.dll . >nul daccs rem rem restore environment: rem set RULBUS=%RULBUS.ORG% set RULBUS.ORG= set RULBUS_CONFIG_FILE=%RULBUS_CONFIG_FILE.ORG% set RULBUS_CONFIG_FILE.ORG= rem rem end of file rem