home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / rxportio.zip / RXPORTIO.INF (.txt) < prev    next >
OS/2 Help File  |  1998-06-22  |  26KB  |  726 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Description ΓòÉΓòÉΓòÉ
  3.  
  4. rxPortIO ver. 1.01 - is a REXX-callable DLL and provides hardware I/O read and 
  5. write services to OS/2 Warp 3.0 and later REXX programs. With rxPortIO you can 
  6. easily access hardware like digital I/O, data acquisition and other boards that 
  7. require I/O read and writes. rxPortIO is ideal for prototyping hardware for 
  8. both, the Professional and the Hobbyist. rxPortIO is copyrighted freeware. 
  9.  
  10.  
  11. ΓòÉΓòÉΓòÉ 2. Introduction ΓòÉΓòÉΓòÉ
  12.  
  13. Have you been looking for a way to do port I/O in OS/2 without having to 
  14. program in C? Well, here is rxPortIO. It is a dynamic link library that allows 
  15. REXX programs to access anything from digital I/O and data acquisition boards 
  16. to volume controls of sound cards, printer ports and even plug-in radio cards. 
  17. rxPortIO also includes a 1-1000 msec delay and bit manipulation routines that 
  18. are useful with digital I/O manipulation. 
  19.  
  20. Together with REXX or a visual REXX application development tool like 
  21. Vispro/REXX, you can easily and quickly put together a program that supports 
  22. the mentioned hardware. 
  23.  
  24. I wrote an initial version of rxPortIO for accessing my computer FM radio card 
  25. with a native OS/2 program written with Vispro/REXX. A few of you have written 
  26. me, asking how I access I/O with REXX, so I decided to spiff-up the code a bit 
  27. an release it for everybody's use. If you write a program with rxPortIO, return 
  28. the favor and consider making it available to the OS/2 community as well! 
  29.  
  30. rxPortIO uses TESTCFG.SYS, a generic device driver standard to every OS/2 Warp 
  31. 3.0 and 4.0 system. Installing and using rxPortIO does in most cases not 
  32. require to reboot the computer as TESTCFG.SYS is installed by default on every 
  33. Warp system. 
  34.  
  35. rxPortIO includes two sample programs, one is a standard REXX program, the 
  36. other is a compiled Vispro/REXX program to show how to use rxPortIO. 
  37.  
  38. I have used and tested rxPortIO with my plug-in radio, sound card and a relay 
  39. board and found it to work without any problems. 
  40.  
  41. I gathered most information for rxPortIO from the internet and if you would 
  42. like additional information on port I/O or REXX programming, check the section 
  43. on References in this file. 
  44.  
  45. If you will be using rxPortIO with VX-REXX or Vispro/REXX, please read the 
  46. section Important Notes for a possible problem and the fix for it. 
  47.  
  48. Before you go ahead and make plans to use rxPortIO consider these limitations: 
  49.  
  50.   - rxPortIO is a 32-bit DLL but is designed to read 8-bit I/O only.
  51.  
  52.   - rxPortIO does not support interrupt driven devices.
  53.  
  54.   - The cheapest way to do digital I/O is using a printer
  55.    or serial adapter. The problem is that rxPortIO and
  56.    TESTCFG.SYS do not allow to write to printer or serial
  57.    ports that have been loaded by the system. The only
  58.    way I found to access LPT ports with rxPortIO, for example,
  59.    is to set the address of the port to some non-standard value
  60.    if that is possible, or set it to 278hex and remark out the
  61.    line BASEDEV=PRINT01.SYS in the CONFIG.SYS. This will
  62.    remove printer support from your system, but allows to
  63.    access the LPT port to be used as digital I/O by rxPortIO.
  64.    If you know of a better way, let me know.
  65.  
  66.   - Digital I/O and data acquisition boards usually include
  67.    documentation on how to access the cards registers.
  68.    Sound card manufacturers also list that data, so it is easy
  69.    to write an application for these devices. Other devices,
  70.    like radio cards for example, do not come with that
  71.    documentation. So before you decide to write any program
  72.    for such a device, you must know how to access the registers.
  73.    The hardware manufacturers will typically not provide you
  74.    with that information.
  75.  
  76. If you have any suggestions about rxPortIO, please let me know. 
  77.  
  78.  
  79. ΓòÉΓòÉΓòÉ 3. Performance Considerations ΓòÉΓòÉΓòÉ
  80.  
  81. REXX PortIO Functions PIORead and PIOWrite: 
  82.  
  83. Doing I/O using rxPortIO with REXX programs is not going to set speed records. 
  84. It is not possible to do high speed data acquisition, the REXX overhead is too 
  85. high. 
  86.  
  87. Here is an informal tests I did on a 100MHz Pentium: 
  88.  
  89. Using rxPortIO.DLL to access I/O through TESTCFG.SYS:
  90. 10,000 readings in 17.8 sec or 1.8 msec per reading
  91.  
  92. Using a C program to access I/O through TESTCFG.SYS:
  93. 10,000 readings in 2.3 sec or 0.23 msec per reading
  94.  
  95. The C program is over seven times faster. 
  96.  
  97. Despite the slow speed of I/O access using rxPortIO, it is still useful for 
  98. many applications. Any digital I/O cards, especially relay cards can be 
  99. controlled without any problems as the controls attached to these devices are 
  100. usually much slower. Relays have typical response times of 100 msec or slower 
  101. and pose no timing problems to rxPortIO. rxPortIO is also being used to control 
  102. computer radio cards and can be used to control sound card volume and balance 
  103. as well. 
  104.  
  105. Bit Manipulation Functions: 
  106.  
  107. Using the supplied bit manipulation functions makes it convenient to do bit 
  108. operations in REXX and from looking at the code it appears that it will execute 
  109. much faster as well. Not so. The call to the DLL puts quite an overhead on to 
  110. the program and can take up to 20 times longer than using several of the 
  111. built-in REXX functions to do the same operation.  The native REXX function 
  112. example below will execute much faster than the call to rxPortIO using 
  113. PIOBitClear. Both samples achieve the same result. 
  114.  
  115.    /* Native REXX Functions D2C and BITAND - MUCH FASTER */
  116.    BitVal = D2C('255')
  117.    BitResult = BITAND(BitVal, '1'x)
  118.  
  119.    /* Call to rxPortIO - SLOWER */
  120.    BitVal = '255'
  121.    BitResult = PIOBitClear(BitVal, '0')
  122.  
  123. If your program executes the bit manipulation routines many times in a loop, 
  124. you may consider using native REXX functions to perform this operation. 
  125.  
  126. Time Delay PIODelay: 
  127.  
  128. The PIODelay function is included for convenience and provides delays for a 
  129. fraction of a second, something the SysSleep function of REXXUTIL.DLL is not 
  130. able to do. If you are using VX-REXX or Vispro/REXX to write your program, I 
  131. suggest to use the Timer events of these programs whenever possible. This will 
  132. make your programs more responsive, especially if time delays are fairly long. 
  133. PIODelay will essentially wait for the delay to time-out and your program will 
  134. not respond during that time. Using the Timer events of the visual REXX 
  135. programs will consume less CPU cycles and it will allow you to terminate the 
  136. delay through a dedicated button for example. 
  137.  
  138.  
  139. ΓòÉΓòÉΓòÉ 4. rxPortIO Function Description ΓòÉΓòÉΓòÉ
  140.  
  141. Describes all functions available in rxPortIO.DLL and how to use them. 
  142.  
  143.    PIOLoadFuncs
  144.  
  145.    PIODropFuncs
  146.  
  147.    PIORead
  148.  
  149.    PIOWrite
  150.  
  151.    PIODelay
  152.  
  153.    PIOBitPick
  154.  
  155.    PIOBitSet
  156.  
  157.    PIOBitClear
  158.  
  159.  
  160. ΓòÉΓòÉΓòÉ 4.1. PIOLoadFuncs ΓòÉΓòÉΓòÉ
  161.  
  162. This function loads rxPortIO.DLL to be used within your REXX program. A REXX 
  163. program using rxPortIO must contain the following two lines to access other 
  164. functions inside rxPortIO: 
  165.  
  166.    CALL RXFuncAdd 'PIOLoadFuncs', 'RXPORTIO', 'PIOLoadFuncs'
  167.    CALL PIOLoadFuncs
  168.  
  169. Standard REXX errors are returned for this function, for example: Error 43 - 
  170. Routine not found if rxPortIO.DLL can't be found. 
  171.  
  172. This function also opens TESTCFG.SYS for read and write access. No errors are 
  173. returned by this function if opening TESTCFG.SYS fails. For errors returned see 
  174. the PIORead or PIOWrite sections. 
  175.  
  176.  
  177. ΓòÉΓòÉΓòÉ 4.2. PIODropFuncs ΓòÉΓòÉΓòÉ
  178.  
  179. This function drops rxPortIO.DLL from your REXX program and also closes access 
  180. to TESTCFG.SYS. Use it in your REXX program as shown below. 
  181.  
  182.    CALL PIODropFuncs
  183.  
  184.  
  185. ΓòÉΓòÉΓòÉ 4.3. PIORead ΓòÉΓòÉΓòÉ
  186.  
  187. This function reads port_Address and returns the data in return_data. The 
  188. function format is as follows: 
  189.  
  190.    return_data = PIORead( port_Address )
  191.  
  192. The value of port_Address must be a decimal number in the range of 256 to 65535 
  193. which corresponds to the I/O range of the IBM Personal Computer. 
  194.  
  195. If the PIORead was successful, the return_data contains the following string: 
  196.  
  197. Addr: xxx Data: yyy 
  198.  
  199. where xxx is the port_Address and yyy is the data of the port read. All values 
  200. are in decimal form. The range of the data read is 0 to 255. 
  201.  
  202. If the PIORead was unsuccessful, the following errors are returned: 
  203.  
  204. Addr: xx Data: yy 
  205.  
  206.    xx = 10   TESTCFG.SYS could not be opened during PIOLoadFuncs.
  207.    yy = rc   Return code of DOSOpen.
  208.  
  209.    xx = 11   Unsuccessful read.
  210.    yy = rc   Return code of DosDevIOCtl.
  211.  
  212. For error codes of DosOpen and DosDevIOCtl see the section on Error Codes. 
  213.  
  214. Examples: 
  215.  
  216. The code below reads the port at location 768 (300 hex) and results in the 
  217. following output: 
  218.  
  219. port_Address = X2D('300')
  220. return_data = PIORead( port_Address )
  221. SAY 'Data read is ' || return_data
  222.  
  223. Output:
  224. Data read is Addr: 768 Data: 255
  225.  
  226. The code below reads the port at location 888 (378 hex) which is reserved for 
  227. LPT1 and tied up by PRINT01.SYS. It results in the following read error output: 
  228.  
  229. port_Address = X2D('378')
  230. return_data = PIORead( port_Address )
  231. SAY 'Data read is ' || return_data
  232.  
  233. Output:
  234. Data read is Addr: 11 Data: 19
  235.  
  236. The error (19) given here is not listed under the return codes of DosDevIOCtl 
  237. of the Control Programming documentation. Error 19 is listed as 
  238. ERROR_WRITE_PROTECT under the disk access functions. Go figure. 
  239.  
  240. The port_Address range is not directly checked by this function, however, 
  241. TESTCFG.SYS does not allow to read or write to ranges below 256 (100 hex) as 
  242. these contain critical system parameters. Also, it does not allow to read or 
  243. write to ports that are controlled by other drivers, like the printer (LPT1) or 
  244. serial ports (COM1, COM2). 
  245.  
  246.  
  247. ΓòÉΓòÉΓòÉ 4.4. PIOWrite ΓòÉΓòÉΓòÉ
  248.  
  249. If you find that PIOWrite is not working in a VX-REXX or Vispro/REXX program, 
  250. please read the section Important Notes for details. 
  251.  
  252. This function writes data_Value to port_Address. The function format is as 
  253. follows: 
  254.  
  255.    return_data = PIOWrite( port_Address, data_Value )
  256.  
  257. The value of port_Address must be a decimal number in the range of 256 to 65535 
  258. which corresponds to the I/O range of the IBM Personal Computer. The value of 
  259. data_Value must be in decimal and have a range of 0 to 255. 
  260.  
  261. If the PIOWrite was successful, the return_data contains the following string: 
  262.  
  263. Addr: xxx Data: yyy 
  264.  
  265. where xxx is the port_Address and yyy is the data just written to the port. All 
  266. values are in decimal form. 
  267.  
  268. If the PIOWrite was unsuccessful, the following errors are returned: 
  269.  
  270. Addr: xx Data: yy 
  271.  
  272.    xx = 10   TESTCFG.SYS could not be opened during PIOLoadFuncs.
  273.    yy = rc   Return code of DOSOpen.
  274.  
  275.    xx = 12   Unsuccessful write.
  276.    yy = rc   Return code of DosDevIOCtl.
  277.  
  278. For error codes of DosOpen and DosDevIOCtl see the section on Error Codes. 
  279.  
  280. Example: 
  281.  
  282. The code below writes to the port at location 768 (300 hex) and results in the 
  283. following output: 
  284.  
  285. port_Address = X2D('300')
  286. data_Value = 255
  287. return_data = PIOWrite( port_Address, data_Value )
  288. SAY 'Data written is ' || return_data
  289.  
  290. Output:
  291. Data written is Addr: 768 Data: 255
  292.  
  293. The port_Address range is not directly checked by this function, however, 
  294. TESTCFG.SYS does not allow to read or write to ranges below 256 (100 hex) as 
  295. these contain critical system parameters. Also, it does not allow to read or 
  296. write to ports that are controlled by other drivers, like the printer (LPT1) or 
  297. serial ports (COM1, COM2). 
  298.  
  299.  
  300. ΓòÉΓòÉΓòÉ 4.5. PIODelay ΓòÉΓòÉΓòÉ
  301.  
  302. This function provides time delay services to your REXX application. It does 
  303. not read or write to any I/O. REXX provides time delay in one second increments 
  304. only with the function SysSleep in REXXUTIL.DLL. The PIODelay function provides 
  305. time delay in the range of 1 to 1000 milliseconds and is useful if some I/O 
  306. hardware needs this short delay for proper operation. Note: This time delay is 
  307. rounded up to the next system clock tick and is therefore not accurate to the 
  308. millisecond. The format of the function is: 
  309.  
  310.    return_data = PIODelay( delay_value )
  311.  
  312. The delay_value is in the range of 1 to 1000 milliseconds. 
  313.  
  314. return_data returns the following values: 
  315.  
  316.     0    No errors.
  317.     1    Invalid time delay range.
  318.     322   ERROR_TS_WAKEUP (Error given by DosSleep API function).
  319.  
  320. Example: 
  321.  
  322. The code below illustrates the time delay function and shows how to verify the 
  323. delay using the REXX function TIME(). Note that TIME() has a resolution of only 
  324. 10 milliseconds. 
  325.  
  326. delay_value = 500
  327. SAY 'Start delay of ' || delay_value || ' msec...'
  328. verify_delay = TIME('R')
  329. return_data = PIODelay( delay_value )
  330. verify_delay = TIME('E')
  331. SAY "... End Delay. rc = " || return_data
  332. SAY 'elapsed time = ' || verify_delay
  333.  
  334. Output:
  335. Start delay of 500 msec...
  336. ┬╖┬╖┬╖ End Delay. rc = 0
  337. elapsed time = 0.520000
  338.  
  339.  
  340. ΓòÉΓòÉΓòÉ 4.6. PIOBitPick ΓòÉΓòÉΓòÉ
  341.  
  342. This function provides an easy way to pick a certain bit from a value. It does 
  343. not access any I/O, but rather provides a much easier way to pick a bit than 
  344. standard REXX functions do. The format of the function is: 
  345.  
  346.    return_bit_value = PIOBitPick( value, bit_position )
  347.  
  348. The value is in decimal with a range of 0 to 65535. 
  349.  
  350. bit_position is the position of the bit which value is to be extracted. The 
  351. right-most position (and therefore the least significant bit) is 0, the 
  352. left-most (or most significant bit) position is 15. 
  353.  
  354. return_bit_value is the value returned and can only be 0 or 1. 
  355.  
  356. There is no variable range checking, so you must insure that the right values 
  357. are passed along in the function. 
  358.  
  359. Example: 
  360.  
  361. The code below illustrates the PIOBitPick function. 
  362.  
  363. SAY 'The bit position 0 of the value 254 is ' || PIOBitPick( '254', '0' )
  364. SAY 'The bit position 1 of the value 254 is ' || PIOBitPick( '254', '1' )
  365.  
  366. Output:
  367. The bit position 0 of the value 254 is 0
  368. The bit position 1 of the value 254 is 1
  369.  
  370.  
  371. ΓòÉΓòÉΓòÉ 4.7. PIOBitSet ΓòÉΓòÉΓòÉ
  372.  
  373. This function provides an easy way to set a certain bit in a value. It does not 
  374. access any I/O, but rather provides a much easier way to set a bit than 
  375. standard REXX functions do. The format of the function is: 
  376.  
  377.    return_value = PIOBitSet( value, bit_position )
  378.  
  379. The value is in decimal with a range of 0 to 65535. 
  380.  
  381. bit_position is the position of the bit which value is to be set. The 
  382. right-most position (and therefore the least significant bit) is 0, the 
  383. left-most (or most significant bit) position is 15. 
  384.  
  385. return_value is the value returned after the bit has been set. Range is 1 to 
  386. 65535. 
  387.  
  388. There is no variable range checking, so you must insure that the right values 
  389. are passed along in the function. 
  390.  
  391. Example: 
  392.  
  393. The code below illustrates the PIOBitSet function. 
  394.  
  395. SAY 'Setting bit position 0 of the value 254 results in ' || PIOBitSet( '254', '0' )
  396. SAY 'Setting bit position 1 of the value 0 results in ' || PIOBitSet( '0', '1' )
  397.  
  398. Output:
  399. Setting bit position 0 of the value 254 results in 255
  400. Setting bit position 1 of the value 0 results in 2
  401.  
  402.  
  403. ΓòÉΓòÉΓòÉ 4.8. PIOBitClear ΓòÉΓòÉΓòÉ
  404.  
  405. This function provides an easy way to clear a certain bit in a value. It does 
  406. not access any I/O, but rather provides a much easier way to clear a bit than 
  407. standard REXX functions do. The format of the function is: 
  408.  
  409.    return_value = PIOBitClear( value, bit_position )
  410.  
  411. The value is in decimal with a range of 0 to 65535. 
  412.  
  413. bit_position is the position of the bit which value is to be cleared. The 
  414. right-most position (and therefore the least significant bit) is 0, the 
  415. left-most (or most significant bit) position is 15. 
  416.  
  417. return_value is the value returned after the bit has been cleared. Range is 0 
  418. to 65535. 
  419.  
  420. There is no variable range checking, so you must insure that the right values 
  421. are passed along in the function. 
  422.  
  423. Example: 
  424.  
  425. The code below illustrates the PIOBitClear function. 
  426.  
  427. SAY 'Clearing bit position 0 of the value 255 results in ' || PIOBitClear( '255', '0' )
  428. SAY 'Clearing bit position 1 of the value 65535 results in ' || PIOBitClear( '65535', '1' )
  429.  
  430. Output:
  431. Clearing bit position 0 of the value 255 results in 254
  432. Clearing bit position 1 of the value 65535 results in 65533
  433.  
  434.  
  435. ΓòÉΓòÉΓòÉ 5. Error Codes ΓòÉΓòÉΓòÉ
  436.  
  437. Error Codes Returned: 
  438.  
  439. If the port address is not returned by the PIORead and PIOWrite functions, then 
  440. the data portion of the returned value indicates the type of error that 
  441. occurred. 
  442.  
  443. DosOpen returns one of the following values as rc: 
  444.  
  445.     0     NO_ERROR
  446.     2     ERROR_FILE_NOT_FOUND
  447.     3     ERROR_PATH_NOT_FOUND
  448.     4     ERROR_TOO_MANY_OPEN_FILES
  449.     5     ERROR_ACCESS_DENIED
  450.     12     ERROR_INVALID_ACCESS
  451.     26     ERROR_NOT_DOS_DISK
  452.     32     ERROR_SHARING_VIOLATION
  453.     36     ERROR_SHARING_BUFFER_EXCEEDED
  454.     82     ERROR_CANNOT_MAKE
  455.     87     ERROR_INVALID_PARAMETER
  456.     99     ERROR_DEVICE_IN_USE
  457.     108    ERROR_DRIVE_LOCKED
  458.     110    ERROR_OPEN_FAILED
  459.     112    ERROR_DISK_FULL
  460.     206    ERROR_FILENAME_EXCED_RANGE
  461.     231    ERROR_PIPE_BUSY
  462.  
  463. DosDevIOCtl returns one of the following values as rc: 
  464.  
  465.     0     NO_ERROR
  466.     1     ERROR_INVALID_FUNCTION
  467.     6     ERROR_INVALID_HANDLE
  468.     15     ERROR_INVALID_DRIVE
  469.     31     ERROR_GEN_FAILURE
  470.     87     ERROR_INVALID_PARAMETER
  471.     111    ERROR_BUFFER_OVERFLOW
  472.     115    ERROR_PROTECTION_VIOLATION
  473.     117    ERROR_INVALID_CATEGORY
  474.     119    ERROR_BAD_DRIVER_LEVEL
  475.     163    ERROR_UNCERTAIN_MEDIA
  476.     165    ERROR_MONITORS_NOT_SUPPORTED
  477.  
  478.  
  479. ΓòÉΓòÉΓòÉ 6. Important Notes ΓòÉΓòÉΓòÉ
  480.  
  481. It has been reported that the PIOWrite function will sometimes not write to the 
  482. selected port when using VX-REXX or Vispro/REXX based programs. This especially 
  483. is the case when the PIOWrite function is the last statement in an event. To 
  484. fix this problem, simply add any other statement after the PIOWrite function 
  485. call. A simple NOP (no operation) right after the PIOWrite call will fix the 
  486. problem. 
  487.  
  488. This problem does not occur with classical REXX programs. 
  489.  
  490. I have observed this behaviour in the past but can not duplicate it anymore. I 
  491. have tested this on a relay card, by actually checking if the correct outputs 
  492. are turned on and I also have tested it with my FM radio card by changing 
  493. frequency and volume. It appears to work fine. 
  494.  
  495. I would suspect that the reason could be in how VX-REXX and Vispro/REXX poll 
  496. keyboard and mouse events. If anyone has any suggestions why this happens and 
  497. how to fix it, please let me know. 
  498.  
  499.  
  500. ΓòÉΓòÉΓòÉ 7. Example REXX Program ΓòÉΓòÉΓòÉ
  501.  
  502. The program below shows how to use rxPortIO. 
  503.  
  504.  
  505. /* RXPORTIO.CMD */
  506. /* Sample REXX Program to access I/O ports using TESTCFG.SYS */
  507.  
  508. /* Load RXPORTIO.DLL */
  509. CALL RXFuncAdd 'PIOLoadFuncs', 'RXPORTIO', 'PIOLoadFuncs'
  510. CALL PIOLoadFuncs
  511.  
  512. SAY ''
  513. SAY '--- Sample REXX Program to access I/O ports using TESTCFG.SYS.---'
  514. SAY ''
  515.  
  516. SAY 'CAUTION: This program is capable of writing to I/O directly.'
  517. SAY '     Make sure the port_Address is set to a value'
  518. SAY '     that will not cause harm to your system.'
  519. SAY '     Port_Address is set to 768 (300hex) by default.'
  520. SAY ''
  521.  
  522. port_Address = X2D('300')             /* Port_address is converted from hex to decimal */
  523. data_value = 0                   /* initialize I/O data_value to zero */
  524. SAY 'Address is set to ' || port_Address || ' decimal.'
  525.  
  526. keyhit = ""
  527. DO FOREVER
  528.   SAY ""
  529.   SAY "Press w to write 0x55, r to Read; d for 0.5 sec delay;"
  530.   SAY "b for bit manipulation; x for eXit..."
  531.   SAY ""
  532.   PARSE PULL keyhit
  533.   SELECT
  534.    when keyhit = "r" | keyhit = "R" then   /* read */
  535.     do
  536.      return_data = PIORead( port_Address )
  537.      SAY 'Read returned ' || return_data
  538.      PARSE VAR return_data . ': ' port1 . ': ' data1
  539.  
  540.      IF port1 <> port_Address then
  541.       SAY 'error reading port: ' || port_Address || '  rc = ' || data1
  542.      ELSE
  543.       SAY "READ. Address: " || D2X(port1) || "h  Data: " || D2X(data1) || "h = " || X2B(D2X(data1)) || " bin"
  544.  
  545.      keyhit = ""
  546.     end
  547.  
  548.    when keyhit = "w" | keyhit = "W" then   /* write  */
  549.     do
  550.      data_value = X2D('55')  /* data to write */
  551.      return_data = PIOWrite( port_Address, data_value )
  552.      SAY 'Write returned ' || return_data
  553.      PARSE VAR return_data . ': ' port1 . ': ' data1
  554.      SAY "WRITE. Address: " || D2X(port1) || "h  Data: " || D2X(data1) || "h = " || X2B(D2X(data1)) || " bin"
  555.      keyhit = ""
  556.     end
  557.  
  558.    when keyhit = "d" | keyhit = "D" then   /* delay  */
  559.     do
  560.      delay_value = 500                   /* delay 1 to 1000 msec max. */
  561.      SAY 'Start delay of ' || delay_value || ' msec...'
  562.      delay = TIME('R')                   /* delay verification only */
  563.      return_data = PIODelay( delay_value )
  564.      delay = TIME('E')
  565.      SAY "... End Delay (0 = successfull, 322 = error).  rc = " || return_data
  566.      SAY 'elapsed time = ' || delay
  567.      keyhit = ""
  568.     end
  569.  
  570.    when keyhit = "b" | keyhit = "B" then   /* bit manipulations */
  571.     do
  572.      value = X2D('FF')  /* init value to 255 (FFhex) */
  573.      SAY 'BitPick. Bit 0 of ' || value || ' is ' || PIOBitPick(value, '0')
  574.      SAY 'BitClear. Bit 1 cleared of ' || value || ' is ' || PIOBitClear(value, '1')
  575.      SAY 'BitSet. Bit 15 set of 0 is ' || PIOBitSet('0', '15')
  576.      keyhit = ""
  577.     end
  578.  
  579.   otherwise
  580.    DO
  581.     IF keyhit = "x" | keyhit = "X" THEN
  582.      DO
  583.       CALL PIODropFuncs
  584.       SAY 'RXPORTIO dropped.'
  585.       EXIT
  586.      END
  587.     ELSE
  588.      SAY "Invalid Input"
  589.    END
  590.   end  /* select */
  591. end /* do */
  592.  
  593. EXIT
  594.  
  595.  
  596. ΓòÉΓòÉΓòÉ 8. Installation ΓòÉΓòÉΓòÉ
  597.  
  598. Note:  REXX must be installed on your system for this program to work. REXX is 
  599. installed by default, but if you did not install it, then run Warp installation 
  600. again and selectively install REXX support. 
  601.  
  602. rxPortIO.DLL requires the presence of the following statements in the 
  603. CONFIG.SYS: 
  604.  
  605.   IOPL=YES,FXPRINT
  606.   DEVICE=D:\OS2\BOOT\TESTCFG.SYS
  607.  
  608. These statements are present by default on any OS/2 Warp 3.0 or Warp 4.0 
  609. systems. 
  610.  
  611. If you write your own REXX programs, only rxPortIO.DLL is required to access 
  612. the I/O. I suggest to keep rxPortIO.DLL in the same directory as your REXX 
  613. program so it will be able to find it when rxPortIO.DLL is loaded. 
  614.  
  615. As an alternative, put rxPortIO.DLL into a directory called out by the LIBPATH 
  616. in the CONFIG.SYS. A reboot is required for this. Any program loading 
  617. rxPortIO.DLL will then automatically find it. 
  618.  
  619. The following files belong to this program: 
  620.  
  621.        rxPortIO.DLL      REXX-callable Dynamic Link Library for I/O read and 
  622.                          write. 
  623.  
  624.        rxPortIO.INF      Documentation for rxPortIO. 
  625.  
  626.        IOTEST.EXE        Sample Vispro/REXX program to show how to use 
  627.                          rxPortIO.DLL. 
  628.  
  629.        IOTSTSRC.ZIP      Sample Vispro/REXX program source. UNZIP (preserve 
  630.                          paths) in your visprorx subdirectory to recreate 
  631.                          project. 
  632.  
  633.        VPOBJ.DLL         DLL required by IOTEST.EXE. 
  634.  
  635.        rxPortIO.CMD      Sample REXX program to show how to use rxPortIO.DLL. 
  636.  
  637.        README.TXT        Short program description. 
  638.  
  639.  
  640. ΓòÉΓòÉΓòÉ 9. References ΓòÉΓòÉΓòÉ
  641.  
  642. To get more information on programming for OS/2, especially for hardware I/O, 
  643. visit the sites listed below: 
  644.  
  645. www.edm2.com
  646. Look through back issues of articles published on hardware I/O and device drivers.
  647. Also offers online classes for programming for OS/2.
  648.  
  649. http://avenger.mri.psu.edu/os2page.html
  650. Information and source code on how to access I/O ports in OS/2.
  651.  
  652. http://femto.ssp.ameslab.gov
  653. Contains OS/2 Warp Programming information for digital I/O
  654. and GPIB devices.
  655.  
  656. To get information on interfacing to a PC or to get information on digital I/O 
  657. products, visit the sites listed below: 
  658.  
  659. http://shell.rmi.net/~hisys/parport.html
  660. IBM Parallel Port FAQ/Tutorial. Useful if you want to use rxPortIO to
  661. control a device attached to the parallel port.
  662.  
  663. http://www.senet.com.au/~cpeacock/
  664. Craig Peacock's Interfacing the PC. Online tutorial to interface any
  665. device to the parallel or serial ports.
  666. Many additional links to other sites about interfacing to computers.
  667.  
  668. http://www.industry.net/indcompsrc
  669. Industrial Computer Source. Industrial computers and data acquisition products.
  670.  
  671. http://www.natinst.com
  672. National Instruments. Digital I/O and data acquisition products.
  673.  
  674. http://www.acces-usa.com
  675. Acces I/O Products. Carries low-cost digital I/O products.
  676.  
  677. To get more information on programming for OS/2 using REXX visit the sites 
  678. listed below: 
  679.  
  680. http://rexx.hursley.ibm.com/rexx/
  681. Main REXX site.
  682.  
  683. http://www.vispro.com/
  684. Visual programming for OS/2 using REXX. Hockware's Vispro/REXX site.
  685.  
  686. Helpful books about programming for OS/2 using REXX: 
  687.  
  688. Teach Yourself REXX in 21 Days. Schindler&Schindler, SAMS, ISBN 0-672-30529-1
  689.  
  690. REXX Reference Summary Handbook, Dick Goran, CFS Nevada, ISBN 0-9639854-3-4
  691. http://www.cfsrexx.com
  692.  
  693. OS/2 REXX, From Bark to Byte, Document Number GG24-4199-00, read online at:
  694. http://publib.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/GG244199/contents
  695.  
  696.  
  697. ΓòÉΓòÉΓòÉ 10. The Legal Stuff ΓòÉΓòÉΓòÉ
  698.  
  699. rxPortIO.DLL is free, however the author retains the copyright to the source 
  700. code. It may be distributed electronically at no fee or a minimum fee to cover 
  701. media and distribution costs as long as all files are kept together. 
  702.  
  703. DISCLAIMER 
  704.  
  705. rxPortIO has been successfully tested on a variety of systems and with a 
  706. variety of I/O hardware. Use this software at your own risk. The author of 
  707. rxPortIO is in no way responsible for any damage this program may cause to 
  708. computer equipment or other property by running this software on it. 
  709.  
  710.  
  711. ΓòÉΓòÉΓòÉ 11. Contact ΓòÉΓòÉΓòÉ
  712.  
  713. For comments and questions on this program, you can contact me directly via 
  714. e-mail. 
  715.  
  716. My e-mail address: 
  717.  
  718.   ASchw@worldnet.att.net 
  719.  
  720. Visit my home page, "The Warped Code Cellar" at 
  721.  
  722.   http://home.att.net/~ASchw 
  723.  
  724. for other information and applications for OS/2 like HOUSE/2, a home automation 
  725. program using X10 devices, Memory Game and Leave One, two 
  726. speech-navigation-enabled games.