File Coverage

blib/lib/Win32/FTDI/FTD2XX.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             #!perl
2             ################################################################################
3             #
4             # Description: Perl5 FTDI CDM Driver Interface Module
5             #
6             # Author : Scott K. MacPherson, (c) Copyright 2008, All Rights Reserved
7             #
8             #
9             # $Id: FTD2XX.pm,v 1.4 2008/11/17 15:03:33 395502 Exp $
10             #
11             ################################################################################
12              
13             package Win32::FTDI::FTD2XX;
14              
15 1     1   36230 use 5.008008;
  1         4  
  1         45  
16 1     1   7 use strict;
  1         2  
  1         38  
17             require Exporter;
18 1     1   104548 use AutoLoader qw(AUTOLOAD);
  1         1625  
  1         7  
19              
20 1     1   2013 use Win32::API; # DLL calling interface
  0            
  0            
21              
22             our $VERSION = do { my @r = (q$Revision: 1.4 $ =~ /\d+/g); sprintf( "%d."."%02d" x $#r, @r ) };
23              
24             use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK );
25              
26             our @ISA = qw( Exporter );
27              
28             # default export list
29             our @EXPORT = qw(
30             FT_OK
31             );
32              
33             # available for export to caller
34             our @EXPORT_OK = qw(
35             FT_OK
36             FT_INVALID_HANDLE
37             FT_DEVICE_NOT_FOUND
38             FT_DEVICE_NOT_OPENED
39             FT_IO_ERROR
40             FT_INSUFFICIENT_RESOURCES
41             FT_INVALID_PARAMETER
42             FT_INVALID_BAUD_RATE
43             FT_DEVICE_NOT_OPENED_FOR_ERASE
44             FT_DEVICE_NOT_OPENED_FOR_WRITE
45             FT_FAILED_TO_WRITE_DEVICE
46             FT_EEPROM_READ_FAILED
47             FT_EEPROM_WRITE_FAILED
48             FT_EEPROM_ERASE_FAILED
49             FT_EEPROM_NOT_PRESENT
50             FT_EEPROM_NOT_PROGRAMMED
51             FT_INVALID_ARGS
52             FT_NOT_SUPPORTED
53             FT_OTHER_ERROR
54             FT_DEVICE_LIST_NOT_READY
55             PFTE_INVALID_API
56             PFTE_MAX_HANDLES
57             PFTE_INVALID_HANDLE
58             PFTE_WAIT_TIMEOUT
59             FT_BAUD_300
60             FT_BAUD_600
61             FT_BAUD_1200
62             FT_BAUD_2400
63             FT_BAUD_4800
64             FT_BAUD_9600
65             FT_BAUD_14400
66             FT_BAUD_19200
67             FT_BAUD_38400
68             FT_BAUD_57600
69             FT_BAUD_115200
70             FT_BAUD_230400
71             FT_BAUD_460800
72             FT_BAUD_921600
73             FT_BITS_8
74             FT_BITS_7
75             FT_BITS_6
76             FT_BITS_5
77             FT_STOP_BITS_1
78             FT_STOP_BITS_1_5
79             FT_STOP_BITS_2
80             FT_PARITY_NONE
81             FT_PARITY_ODD
82             FT_PARITY_EVEN
83             FT_PARITY_MARK
84             FT_PARITY_SPACE
85             FT_FLOW_NONE
86             FT_FLOW_RTS_CTS
87             FT_FLOW_DTR_DSR
88             FT_FLOW_XON_XOFF
89             FT_PURGE_RX
90             FT_PURGE_TX
91             FT_DEFAULT_RX_TIMEOUT
92             FT_DEFAULT_TX_TIMEOUT
93             FT_DEVICE_BM
94             FT_DEVICE_AM
95             FT_DEVICE_100AX
96             FT_DEVICE_UNKNOWN
97             FT_DEVICE_2232C
98             FT_DEVICE_232R
99             PFT_FLOW_XonChar
100             PFT_FLOW_XoffChar
101             PFT_MODEM_STATUS_CTS
102             PFT_MODEM_STATUS_DSR
103             PFT_MODEM_STATUS_RI
104             PFT_MODEM_STATUS_DCD
105             PFT_BITMODE_RESET
106             PFT_BITMODE_ASYNCBB
107             PFT_BITMODE_MPSSE
108             PFT_BITMODE_SYNCBB
109             PFT_BITMODE_MHBEM
110             PFT_BITMODE_FOISM
111             PFT_BITMODE_CBUSBB
112             PFT_MAX_SERIAL
113             PFT_MAX_DESCR
114             PFT_MAX_HANDLES
115             );
116              
117             #######################################
118             # Definitions from FTD2XX.H and P5FTD2XX.H
119              
120             # Specific parameter datatypes
121             Win32::API::Type->typedef( 'PFT_HANDLE', 'DWORD' );
122             Win32::API::Type->typedef( 'PPFT_HANDLE', 'LPDWORD' );
123             Win32::API::Type->typedef( 'PFT_STATUS', 'DWORD' );
124              
125             # Enumerated device status types
126             use constant FT_OK => 0;
127             use constant FT_INVALID_HANDLE => 1;
128             use constant FT_DEVICE_NOT_FOUND => 2;
129             use constant FT_DEVICE_NOT_OPENED => 3;
130             use constant FT_IO_ERROR => 4;
131             use constant FT_INSUFFICIENT_RESOURCES => 5;
132             use constant FT_INVALID_PARAMETER => 6;
133             use constant FT_INVALID_BAUD_RATE => 7;
134             use constant FT_DEVICE_NOT_OPENED_FOR_ERASE => 8;
135             use constant FT_DEVICE_NOT_OPENED_FOR_WRITE => 9;
136             use constant FT_FAILED_TO_WRITE_DEVICE => 10;
137             use constant FT_EEPROM_READ_FAILED => 11;
138             use constant FT_EEPROM_WRITE_FAILED => 12;
139             use constant FT_EEPROM_ERASE_FAILED => 13;
140             use constant FT_EEPROM_NOT_PRESENT => 14;
141             use constant FT_EEPROM_NOT_PROGRAMMED => 15;
142             use constant FT_INVALID_ARGS => 16;
143             use constant FT_NOT_SUPPORTED => 17;
144             use constant FT_OTHER_ERROR => 18;
145             use constant FT_DEVICE_LIST_NOT_READY => 19;
146             #PFT specific error additions
147             use constant PFTE_INVALID_API => 100;
148             use constant PFTE_MAX_HANDLES => 101;
149             use constant PFTE_INVALID_HANDLE => 102;
150             use constant PFTE_WAIT_TIMEOUT => 103;
151              
152             # STATUS Translation - accessed only via PFT_STATUS_MSG()
153             my %PFTMsg = (
154             @{[FT_OK]} => "OK",
155             @{[FT_INVALID_HANDLE]} => "FT_INVALID_HANDLE",
156             @{[FT_DEVICE_NOT_FOUND]} => "DEVICE_NOT_FOUND",
157             @{[FT_DEVICE_NOT_OPENED]} => "DEVICE_NOT_OPENED",
158             @{[FT_IO_ERROR]} => "IO_ERROR",
159             @{[FT_INSUFFICIENT_RESOURCES]} => "INSUFFICIENT_RESOURCES",
160             @{[FT_INVALID_PARAMETER]} => "INVALID_PARAMETER",
161             @{[FT_INVALID_BAUD_RATE]} => "INVALID_BAUD_RATE",
162             @{[FT_DEVICE_NOT_OPENED_FOR_ERASE]} => "DEVICE_NOT_OPENED_FOR_ERASE",
163             @{[FT_DEVICE_NOT_OPENED_FOR_WRITE]} => "DEVICE_NOT_OPENED_FOR_WRITE",
164             @{[FT_FAILED_TO_WRITE_DEVICE]} => "FAILED_TO_WRITE_DEVICE",
165             @{[FT_EEPROM_READ_FAILED]} => "EEPROM_READ_FAILED",
166             @{[FT_EEPROM_WRITE_FAILED]} => "EEPROM_WRITE_FAILED",
167             @{[FT_EEPROM_ERASE_FAILED]} => "EEPROM_ERASE_FAILED",
168             @{[FT_EEPROM_NOT_PRESENT]} => "EEPROM_NOT_PRESENT",
169             @{[FT_EEPROM_NOT_PROGRAMMED]} => "EEPROM_NOT_PROGRAMMED",
170             @{[FT_INVALID_ARGS]} => "INVALID_ARGS",
171             @{[FT_NOT_SUPPORTED]} => "NOT_SUPPORTED",
172             @{[FT_OTHER_ERROR]} => "OTHER_ERROR",
173             @{[FT_DEVICE_LIST_NOT_READY]} => "DEVICE_LIST_NOT_READY",
174             @{[PFTE_INVALID_API]} => "INVALID_API",
175             @{[PFTE_MAX_HANDLES]} => "MAX_HANDLES_REACHED",
176             @{[PFTE_INVALID_HANDLE]} => "PFT_INVALID_HANDLE",
177             @{[PFTE_WAIT_TIMEOUT]} => "WAIT_TIMEOUT",
178             );
179              
180             # Baud Rates
181             use constant FT_BAUD_300 => 300;
182             use constant FT_BAUD_600 => 600;
183             use constant FT_BAUD_1200 => 1200;
184             use constant FT_BAUD_2400 => 2400;
185             use constant FT_BAUD_4800 => 4800;
186             use constant FT_BAUD_9600 => 9600;
187             use constant FT_BAUD_14400 => 14400;
188             use constant FT_BAUD_19200 => 19200;
189             use constant FT_BAUD_38400 => 38400;
190             use constant FT_BAUD_57600 => 57600;
191             use constant FT_BAUD_115200 => 115200;
192             use constant FT_BAUD_230400 => 230400;
193             use constant FT_BAUD_460800 => 460800;
194             use constant FT_BAUD_921600 => 921600;
195              
196             # Word Lengths
197             use constant FT_BITS_8 => 0x08;
198             use constant FT_BITS_7 => 0x07;
199             use constant FT_BITS_6 => 0x06;
200             use constant FT_BITS_5 => 0x05;
201              
202             # Stop Bits
203             use constant FT_STOP_BITS_1 => 0x00;
204             use constant FT_STOP_BITS_1_5 => 0x01;
205             use constant FT_STOP_BITS_2 => 0x02;
206              
207             # Parity
208             use constant FT_PARITY_NONE => 0x00;
209             use constant FT_PARITY_ODD => 0x01;
210             use constant FT_PARITY_EVEN => 0x02;
211             use constant FT_PARITY_MARK => 0x03;
212             use constant FT_PARITY_SPACE => 0x04;
213              
214             # Flow Control
215             use constant FT_FLOW_NONE => 0x0000;
216             use constant FT_FLOW_RTS_CTS => 0x0100;
217             use constant FT_FLOW_DTR_DSR => 0x0200;
218             use constant FT_FLOW_XON_XOFF => 0x0400;
219             use constant PFT_FLOW_XonChar => 0x11; # CTRL-Q (ANSI standard)
220             use constant PFT_FLOW_XoffChar => 0x13; # CTRL-S (ANSI standard)
221              
222             # Purge rx and tx buffers
223             use constant FT_PURGE_RX => 1;
224             use constant FT_PURGE_TX => 2;
225              
226             # GetModemStatus() flags
227             use constant PFT_MODEM_STATUS_CTS => 0x00000010;
228             use constant PFT_MODEM_STATUS_DSR => 0x00000020;
229             use constant PFT_MODEM_STATUS_RI => 0x00000040;
230             use constant PFT_MODEM_STATUS_DCD => 0x00000080;
231              
232             # Get/Set BitMode masks
233             use constant PFT_BITMODE_RESET => 0x00;
234             use constant PFT_BITMODE_ASYNCBB => 0x01;
235             use constant PFT_BITMODE_MPSSE => 0x02;
236             use constant PFT_BITMODE_SYNCBB => 0x04;
237             use constant PFT_BITMODE_MHBEM => 0x08;
238             use constant PFT_BITMODE_FOISM => 0x10;
239             use constant PFT_BITMODE_CBUSBB => 0x20;
240              
241             # Events (NOT IMPLEMENTED IN PERL CODE YET)
242             #typedef VOID (*PFT_EVENT_HANDLER)(DWORD,DWORD);
243             #
244             #my $FT_EVENT_RXCHAR = 1;
245             #my $FT_EVENT_MODEM_STATUS = 2;
246              
247             # Timeouts
248             use constant FT_DEFAULT_RX_TIMEOUT => 300;
249             use constant FT_DEFAULT_TX_TIMEOUT => 300;
250              
251             # Enumerated Device types
252             use constant FT_DEVICE_BM => 0;
253             use constant FT_DEVICE_AM => 1;
254             use constant FT_DEVICE_100AX => 2;
255             use constant FT_DEVICE_UNKNOWN => 3;
256             use constant FT_DEVICE_2232C => 4;
257             use constant FT_DEVICE_232R => 5;
258              
259             # FT Device Translation - accessed only via GetDeviceInfo()
260             our %FT_DEVICE_TYPE = (
261             @{[FT_DEVICE_BM]} => 'FT_DEVICE_BM',
262             @{[FT_DEVICE_AM]} => 'FT_DEVICE_AM',
263             @{[FT_DEVICE_100AX]} => 'FT_DEVICE_100AX',
264             @{[FT_DEVICE_UNKNOWN]} => 'FT_DEVICE_UNKNOWN',
265             @{[FT_DEVICE_2232C]} => 'FT_DEVICE_2232C',
266             @{[FT_DEVICE_232R]} => 'FT_DEVICE_232R',
267             );
268              
269             # Misc limits
270             use constant PFT_MAX_SERIAL => 32; # max serial number string buffer
271             use constant PFT_MAX_DESCR => 64; # max description string buffer
272             use constant PFT_MAX_HANDLES => 50; # max allocated PFT_HANDLES
273             use constant PFT_WAIT_POLLTM => 0.25; # default 250ms wait method poll cycle time
274              
275             ################################################################################
276             # DLL functions to import (Win32::API parameter/pack syntax)
277             # Note: As of this writing, the Win32::API prototype interface from v0.55
278             # seemed to have issues handling these correctly, and would abort often.
279             # However, reverting to the legacy positional/pack parameter interface
280             # works fine.
281             ################################################################################
282             my $P5FTD2XX_DLL = "p5ftd2xx";
283              
284             # Note: all functions return L/DWORD type
285             my %PFT_Imports = (
286             'PFT_Version' => 'P',
287             'PFT_New' => 'P',
288             'PFT_Free' => 'L',
289             'PFT_ValidHandle' => 'L',
290             'PFT_Status' => 'L',
291             'PFT_GetSerialByIndex' => 'LLP',
292             'PFT_GetDescrByIndex' => 'LLP',
293             'PFT_OpenByIndex' => 'LL',
294             'PFT_OpenBySerial' => 'LP',
295             'PFT_Rescan' => 'L',
296             'PFT_Reload' => 'LII',
297             'PFT_ResetPort' => 'L',
298             'PFT_CyclePort' => 'L',
299             'PFT_GetDriverVersion' => 'LP',
300             'PFT_GetLibraryVersion' => 'LP',
301             'PFT_GetNumDevices' => 'LP',
302             'PFT_GetDeviceInfo' => 'LPPPP',
303             'PFT_Close' => 'L',
304             'PFT_SetBaudRate' => 'LL',
305             'PFT_SetDivisor' => 'LI',
306             'PFT_SetDataCharacteristics' => 'LIII',
307             'PFT_SetFlowControl' => 'LIII',
308             'PFT_SetTimeouts' => 'LLL',
309             'PFT_SetDtr' => 'L',
310             'PFT_ClrDtr' => 'L',
311             'PFT_SetRts' => 'L',
312             'PFT_ClrRts' => 'L',
313             'PFT_SetBreakOn' => 'L',
314             'PFT_SetBreakOff' => 'L',
315             'PFT_GetStatus' => 'LPPP',
316             'PFT_GetQueueStatus' => 'LP',
317             'PFT_GetModemStatus' => 'LP',
318             'PFT_SetChars' => 'LIIII',
319             'PFT_SetResetPipeRetryCount' => 'LL',
320             'PFT_SetDeadmanTimeout' => 'LL',
321             'PFT_StopInTask' => 'L',
322             'PFT_RestartInTask' => 'L',
323             'PFT_Purge' => 'LL',
324             'PFT_ResetDevice' => 'L',
325             'PFT_Read' => 'LPLP',
326             'PFT_Write' => 'LPLP',
327             'PFT_GetLatencyTimer' => 'LP',
328             'PFT_SetLatencyTimer' => 'LI',
329             'PFT_GetBitMode' => 'LP',
330             'PFT_SetBitMode' => 'LII',
331             'PFT_SetUSBParameters' => 'LLL',
332             );
333             #
334             # End of FTD2XX/P5FTD2XX defs
335             #
336             ################################################################################
337             # Object Constructor/Destructors
338             #
339             sub new
340             {
341             my $class = shift;
342             my $self = {
343             # public/user definable settings
344             PFT_DEBUG => 0, # toggles debug output
345             @_,
346             # private object data
347             _PFT_HANDLE => 0, # handle of opened FTDI device
348             _PFT_STATUS => FT_OK, # status of last PFT call
349             _PFT_ERROR => "", # error message string
350             # _{function} # imported function references
351             };
352             bless( $self, $class );
353              
354             # import the bare minimum from the DLL to get started
355             return( $self ) unless( _importDll( $self, "PFT_New" ) );
356             return( $self ) unless( _importDll( $self, "PFT_Free" ) );
357              
358             my $PFT_HANDLE = pack( 'L', 0 ); # create storage for the handle
359             if( $self->{_PFT_STATUS} = $self->{_PFT_New}->Call( $PFT_HANDLE ) )
360             {
361             return( $self );
362             }
363             $self->{_PFT_HANDLE} = unpack( 'L', $PFT_HANDLE );
364             return( $self );
365              
366             } # new();
367              
368             ########################################
369             #
370             sub DESTROY
371             {
372             my $self = shift;
373             if( $self->{_PFT_Free} && $self->{_PFT_HANDLE} )
374             {
375             printf( STDERR "Win32::FTDI::DESTROY() Freeing PFT_HANDLE: %d\n",
376             $self->{_PFT_HANDLE} ) if( $self->{PFT_DEBUG} );
377             $self->{_PFT_Free}->Call( $self->{_PFT_HANDLE} );
378             }
379             return( 1 );
380             }
381              
382             ################################################################################
383             # Accessor Methods
384             #
385             sub VERSION
386             {
387             my $self = shift;
388             return( $VERSION ); # return our (module) version
389             }
390              
391             ########################################
392             #
393             sub PFT_HANDLE
394             {
395             my $self = shift;
396             return( $self->{_PFT_HANDLE} ); # return PFT handle number in use
397             }
398              
399             ########################################
400             #
401             sub PFT_STATUS
402             {
403             my $self = shift;
404             return( $self->{_PFT_STATUS} );
405             }
406              
407             ########################################
408             #
409             sub PFT_STATUS_MSG
410             {
411             my $self = shift;
412             my $PFT_Errno = shift;
413              
414             # if specific status translation is not requested, return current
415             return( $PFTMsg{$self->{_PFT_STATUS}} ) unless( defined($PFT_Errno) );
416             return( $PFTMsg{$PFT_Errno} );
417             }
418              
419             ########################################
420             #
421             sub PFT_ERROR
422             {
423             my $self = shift;
424             return( $self->{_PFT_ERROR} );
425             }
426              
427             ########################################
428             #
429             sub PFT_DEBUG
430             {
431             my $self = shift;
432             my $new = shift;
433              
434             if( $new )
435             {
436             my $old = $self->{PFT_DEBUG};
437             $self->{PFT_DEBUG} = $new;
438             return( $old ); # return previous debug state
439             }
440             return( $self->{PFT_DEBUG} );
441             }
442              
443             ################################################################################
444             # Private Object Methods
445             #
446             sub _importDll
447             {
448             my $self = shift;
449             my $function = shift;
450              
451             # check to make sure we have an import definition for the requested function
452             unless( exists( $PFT_Imports{$function} ) )
453             {
454             $self->{_PFT_STATUS} = PFTE_INVALID_API;
455             $self->{_PFT_ERROR} = "No '$function' API in DLL import list";
456             return( 0 );
457             }
458              
459             # check to make sure we haven't imported this before
460             if( $self->{"_$function"} )
461             {
462             $self->{_PFT_STATUS} = PFTE_INVALID_API;
463             $self->{_PFT_ERROR} = "API previously imported";
464             return( 0 ); # fail
465             }
466              
467             # import the function
468             print( "Win32::FTDI::_importDll( $function($PFT_Imports{$function}))\n" ) if( $self->{PFT_DEBUG} );
469             my $f = Win32::API->new( $P5FTD2XX_DLL, $function, $PFT_Imports{$function}, 'L', '_cdecl' );
470             unless( $f )
471             {
472             $self->{_PFT_STATUS} = PFTE_INVALID_API;
473             $self->{_PFT_ERROR} = "$!";
474             return( 0 ); # fail
475             }
476              
477             # store the reference for use
478             $self->{"_$function"} = $f;
479             return( 1 ); # success
480              
481             } # _importDll()
482              
483             ################################################################################
484             1;
485             __END__