libftdi-ruby 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. data/README.md +42 -0
  2. data/lib/ftdi.rb +204 -18
  3. data/lib/ftdi/version.rb +1 -2
  4. data/test.rb +5 -5
  5. metadata +8 -8
data/README.md CHANGED
@@ -2,3 +2,45 @@ Ruby bindings for [libftdi](http://www.intra2net.com/en/developer/libftdi/index.
2
2
 
3
3
  You must install libftdi itself in addition to this gem.
4
4
 
5
+ ## Synopsys
6
+
7
+ ```ruby
8
+ require 'rubygems'
9
+ require 'ftdi'
10
+
11
+ ctx = Ftdi::Context.new
12
+
13
+ begin
14
+ ctx.usb_open(0x0403, 0x6001)
15
+ begin
16
+ ctx.baudrate = 250000
17
+ ctx.set_line_property(:bits_8, :stop_bit_2, :none)
18
+ ctx.flowctrl = Ftdi::SIO_DISABLE_FLOW_CTRL
19
+
20
+ arr = Array.new(513) { |i| i.zero? ? 0 : 1 }
21
+ ctx.set_line_property2(:bits_8, :stop_bit_2, :none, :break_on)
22
+ sleep 0.001
23
+ ctx.set_line_property2(:bits_8, :stop_bit_2, :none, :break_off)
24
+ sleep 0.001
25
+ ctx.write_data(arr)
26
+
27
+ sleep 1
28
+
29
+ arr = [ 0 ] * 513
30
+ ctx.set_line_property2(:bits_8, :stop_bit_2, :none, :break_on)
31
+ sleep 0.001
32
+ ctx.set_line_property2(:bits_8, :stop_bit_2, :none, :break_off)
33
+ sleep 0.001
34
+ ctx.write_data(arr)
35
+
36
+ puts "Context is:"
37
+ ctx.members.each { |k| puts "#{k} = #{ctx[k]}" }
38
+
39
+ ensure
40
+ ctx.usb_close
41
+ end
42
+ rescue Ftdi::Error => e
43
+ $stderr.puts e.to_s
44
+ end
45
+ ```
46
+
@@ -1,6 +1,8 @@
1
1
  require 'ffi'
2
2
  require "ftdi/version"
3
3
 
4
+ # Represents libftdi ruby bindings.
5
+ # End-user API represented by {Ftdi::Context} class.
4
6
  module Ftdi
5
7
  extend FFI::Library
6
8
 
@@ -9,52 +11,80 @@ module Ftdi
9
11
  # FTDI chip type.
10
12
  ChipType = enum(:type_am, :type_bm, :type_2232c, :type_r, :type_2232h, :type_4232h, :type_232h)
11
13
 
12
- # Automatic loading / unloading of kernel modules
14
+ # Automatic loading / unloading of kernel modules.
13
15
  ModuleDetachMode = enum(:auto_detach_sio_module, :dont_detach_sio_module)
14
16
 
15
- # Number of bits for {Ftdi::Context.set_line_property}
17
+ # Number of bits for {Ftdi::Context#set_line_property}.
16
18
  BitsType = enum(
17
19
  :bits_7, 7,
18
20
  :bits_8, 8
19
21
  )
20
22
 
21
- # Number of stop bits for {Ftdi::Context.set_line_property}
23
+ # Number of stop bits for {Ftdi::Context#set_line_property}.
22
24
  StopbitsType = enum(
23
25
  :stop_bit_1, 0,
24
26
  :stop_bit_15, 1,
25
27
  :stop_bit_2, 2
26
28
  )
27
29
 
28
- # Parity mode for {Ftdi::Context.set_line_property}
30
+ # Parity mode for {Ftdi::Context#set_line_property}.
29
31
  ParityType = enum(:none, :odd, :even, :mark, :space)
30
32
 
31
- # Break type for {Ftdi::Context.set_line_property2}
33
+ # Break type for {Ftdi::Context#set_line_property2}.
32
34
  BreakType = enum(:break_off, :break_on)
33
35
 
36
+ # Port interface for chips with multiple interfaces.
37
+ # @see Ftdi::Context#interface=
38
+ Interface = enum(:interface_any, :interface_a, :interface_b, :interface_c, :interface_d)
39
+
40
+ # Flow control: disable
41
+ # @see Ftdi::Context#flowctrl=
34
42
  SIO_DISABLE_FLOW_CTRL = 0x0
43
+ # @see Ftdi::Context#flowctrl=
44
+ SIO_RTS_CTS_HS = (0x1 << 8)
45
+ # @see Ftdi::Context#flowctrl=
46
+ SIO_DTR_DSR_HS = (0x2 << 8)
47
+ # @see Ftdi::Context#flowctrl=
48
+ SIO_XON_XOFF_HS = (0x4 << 8)
35
49
 
36
50
  # Base error of libftdi.
37
51
  class Error < RuntimeError; end
38
52
 
39
- # Initialization error of libftdi.
53
+ # Represents initialization error of libftdi.
40
54
  class CannotInitializeContextError < Error; end
41
55
 
42
- # Error of libftdi with its status code.
56
+ # Represents error of libftdi with its status code.
43
57
  class StatusCodeError < Error
44
- attr_accessor :status_code
58
+ # Gets status code.
59
+ # @return [Fixnum] Status code.
60
+ attr_reader :status_code
45
61
 
46
62
  def initialize(status_code, message)
47
63
  super(message)
48
- self.status_code = status_code
64
+ @status_code = status_code
49
65
  end
50
66
 
67
+ # Gets string representation of the error.
68
+ # @return [String] Representation of the error.
51
69
  def to_s
52
70
  "#{status_code}: #{super}"
53
71
  end
54
72
  end
55
73
 
56
- # libftdi context
57
- class Context < FFI::Struct
74
+ # Represents libftdi context and end-user API.
75
+ # @example Open USB device
76
+ # ctx = Ftdi::Context.new
77
+ # begin
78
+ # ctx.usb_open(0x0403, 0x6001)
79
+ # begin
80
+ # ctx.baudrate = 250000
81
+ # ensure
82
+ # ctx.usb_close
83
+ # end
84
+ # rescue Ftdi::Error => e
85
+ # $stderr.puts e.to_s
86
+ # end
87
+ class Context < FFI::ManagedStruct
58
88
  layout(
59
89
  # USB specific
60
90
  # libusb's context
@@ -109,6 +139,8 @@ module Ftdi
109
139
  :module_detach_mode, Ftdi::ModuleDetachMode
110
140
  )
111
141
 
142
+ # Initializes new libftdi context.
143
+ # @raise [CannotInitializeContextError] libftdi cannot be initialized.
112
144
  def initialize
113
145
  ptr = Ftdi.ftdi_new
114
146
  raise CannotInitializeContextError.new if ptr.nil?
@@ -116,36 +148,85 @@ module Ftdi
116
148
  end
117
149
 
118
150
  # Deinitialize and free an ftdi context.
119
- def dispose
120
- Ftdi.ftdi_free(ctx)
151
+ # @return [NilClass] nil
152
+ def self.release(p)
153
+ Ftdi.ftdi_free(p)
121
154
  nil
122
155
  end
123
156
 
124
- alias :close :dispose
125
-
157
+ # Gets error text.
158
+ # @return [String] Error text.
126
159
  def error_string
127
160
  self[:error_str]
128
161
  end
129
162
 
130
163
  # Opens the first device with a given vendor and product ids.
164
+ # @param [Fixnum] vendor Vendor id.
165
+ # @param [Fixnum] product Product id.
166
+ # @return [NilClass] nil
167
+ # @raise [StatusCodeError] libftdi reports error.
168
+ # @raise [ArgumentError] Bad arguments.
131
169
  def usb_open(vendor, product)
132
170
  raise ArgumentError.new('vendor should be Fixnum') unless vendor.kind_of?(Fixnum)
133
171
  raise ArgumentError.new('product should be Fixnum') unless product.kind_of?(Fixnum)
134
172
  check_result(Ftdi.ftdi_usb_open(ctx, vendor, product))
135
173
  end
136
174
 
175
+ # Opens the first device with a given vendor and product ids, description and serial.
176
+ # @param [Fixnum] vendor Vendor id.
177
+ # @param [Fixnum] product Product id.
178
+ # @param [String] description Description to search for. Use nil if not needed.
179
+ # @param [String] serial Serial to search for. Use nil if not needed.
180
+ # @return [NilClass] nil
181
+ # @raise [StatusCodeError] libftdi reports error.
182
+ # @raise [ArgumentError] Bad arguments.
183
+ def usb_open_desc(vendor, product, description, serial)
184
+ raise ArgumentError.new('vendor should be Fixnum') unless vendor.kind_of?(Fixnum)
185
+ raise ArgumentError.new('product should be Fixnum') unless product.kind_of?(Fixnum)
186
+ check_result(Ftdi.ftdi_usb_open_desc(ctx, vendor, product, description, serial))
187
+ end
188
+
189
+ # Opens the index-th device with a given vendor and product ids, description and serial.
190
+ # @param [Fixnum] vendor Vendor id.
191
+ # @param [Fixnum] product Product id.
192
+ # @param [String] description Description to search for. Use nil if not needed.
193
+ # @param [String] serial Serial to search for. Use nil if not needed.
194
+ # @param [Fixnum] index Number of matching device to open if there are more than one, starts with 0.
195
+ # @return [NilClass] nil
196
+ # @raise [StatusCodeError] libftdi reports error.
197
+ # @raise [ArgumentError] Bad arguments.
198
+ def usb_open_desc_index(vendor, product, description, serial, index)
199
+ raise ArgumentError.new('vendor should be Fixnum') unless vendor.kind_of?(Fixnum)
200
+ raise ArgumentError.new('product should be Fixnum') unless product.kind_of?(Fixnum)
201
+ raise ArgumentError.new('index should be Fixnum') unless index.kind_of?(Fixnum)
202
+ raise ArgumentError.new('index should be greater than or equal to zero') if index < 0
203
+ check_result(Ftdi.ftdi_usb_open_desc_index(ctx, vendor, product, description, serial, index))
204
+ end
205
+
206
+ # Resets the ftdi device.
207
+ # @raise [StatusCodeError] libftdi reports error.
208
+ # @return [NilClass] nil
209
+ def usb_reset
210
+ check_result(Ftdi.ftdi_usb_reset(ctx))
211
+ end
212
+
137
213
  # Closes the ftdi device.
214
+ # @return [NilClass] nil
138
215
  def usb_close
139
216
  Ftdi.ftdi_usb_close(ctx)
140
217
  nil
141
218
  end
142
219
 
143
220
  # Gets the chip baud rate.
221
+ # @return [Fixnum] Baud rate.
144
222
  def baudrate
145
223
  self[:baudrate]
146
224
  end
147
225
 
148
226
  # Sets the chip baud rate.
227
+ # @raise [StatusCodeError] libftdi reports error.
228
+ # @raise [ArgumentError] Bad arguments.
229
+ # @return [NilClass] nil
149
230
  def baudrate=(new_baudrate)
150
231
  raise ArgumentError.new('baudrate should be Fixnum') unless new_baudrate.kind_of?(Fixnum)
151
232
  check_result(Ftdi.ftdi_set_baudrate(ctx, new_baudrate))
@@ -153,30 +234,126 @@ module Ftdi
153
234
 
154
235
  # Set (RS232) line characteristics.
155
236
  # The break type can only be set via {#set_line_property2} and defaults to "off".
237
+ # @param [BitsType] bits
238
+ # @param [StopbitsType] stopbits
239
+ # @param [ParityType] parity
240
+ # @raise [StatusCodeError] libftdi reports error.
241
+ # @return [NilClass] nil
156
242
  def set_line_property(bits, stopbits, parity)
157
243
  check_result(Ftdi.ftdi_set_line_property(ctx, bits, stopbits, parity))
158
244
  end
159
245
 
160
246
  # Set (RS232) line characteristics.
247
+ # @param [BitsType] bits
248
+ # @param [StopbitsType] stopbits
249
+ # @param [ParityType] parity
250
+ # @param [BreakType] _break
251
+ # @raise [StatusCodeError] libftdi reports error.
252
+ # @return [NilClass] nil
161
253
  def set_line_property2(bits, stopbits, parity, _break)
162
254
  check_result(Ftdi.ftdi_set_line_property2(ctx, bits, stopbits, parity, _break))
163
255
  end
164
256
 
165
- # Set flowcontrol for ftdi chip.
257
+ # Set flow control setting for ftdi chip.
258
+ # @param [Fixnum] new_flowctrl New flow control setting.
259
+ # @raise [StatusCodeError] libftdi reports error.
260
+ # @return [Fixnum] New flow control setting.
261
+ # @see SIO_DISABLE_FLOW_CTRL
262
+ # @see SIO_RTS_CTS_HS
263
+ # @see SIO_DTR_DSR_HS
264
+ # @see SIO_XON_XOFF_HS
166
265
  def flowctrl=(new_flowctrl)
167
266
  check_result(Ftdi.ftdi_setflowctrl(ctx, new_flowctrl))
267
+ new_flowctrl
268
+ end
269
+
270
+ # Gets write buffer chunk size.
271
+ # @return [Fixnum] Write buffer chunk size.
272
+ # @raise [StatusCodeError] libftdi reports error.
273
+ # @see #write_data_chunksize=
274
+ def write_data_chunksize
275
+ p = FFI::MemoryPointer.new(:uint, 1)
276
+ check_result(Ftdi.ftdi_write_data_get_chunksize(ctx, p))
277
+ p.read_uint
278
+ end
279
+
280
+ # Configure write buffer chunk size.
281
+ # Automatically reallocates the buffer.
282
+ # @note Default is 4096.
283
+ # @param [Fixnum] new_chunksize Write buffer chunk size.
284
+ # @return [Fixnum] New write buffer chunk size.
285
+ # @raise [StatusCodeError] libftdi reports error.
286
+ def write_data_chunksize=(new_chunksize)
287
+ check_result(Ftdi.ftdi_write_data_set_chunksize(ctx, new_chunksize))
288
+ new_chunksize
168
289
  end
169
290
 
291
+ # Writes data.
292
+ # @param [String, Array] bytes String or array of integers that will be interpreted as bytes using pack('c*').
293
+ # @return [Fixnum] Number of written bytes.
294
+ # @raise [StatusCodeError] libftdi reports error.
170
295
  def write_data(bytes)
171
296
  bytes = bytes.pack('c*') if bytes.respond_to?(:pack)
172
297
  size = bytes.respond_to?(:bytesize) ? bytes.bytesize : bytes.size
173
298
  mem_buf = FFI::MemoryPointer.new(:char, size)
174
299
  mem_buf.put_bytes(0, bytes)
175
- r = Ftdi.ftdi_write_data(ctx, mem_buf, size)
176
- check_result(r)
300
+ bytes_written = Ftdi.ftdi_write_data(ctx, mem_buf, size)
301
+ check_result(bytes_written)
302
+ bytes_written
303
+ end
304
+
305
+ # Gets read buffer chunk size.
306
+ # @return [Fixnum] Read buffer chunk size.
307
+ # @raise [StatusCodeError] libftdi reports error.
308
+ # @see #read_data_chunksize=
309
+ def read_data_chunksize
310
+ p = FFI::MemoryPointer.new(:uint, 1)
311
+ check_result(Ftdi.ftdi_read_data_get_chunksize(ctx, p))
312
+ p.read_uint
313
+ end
314
+
315
+ # Configure read buffer chunk size.
316
+ # Automatically reallocates the buffer.
317
+ # @note Default is 4096.
318
+ # @param [Fixnum] new_chunksize Read buffer chunk size.
319
+ # @return [Fixnum] New read buffer chunk size.
320
+ # @raise [StatusCodeError] libftdi reports error.
321
+ def read_data_chunksize=(new_chunksize)
322
+ check_result(Ftdi.ftdi_read_data_set_chunksize(ctx, new_chunksize))
323
+ new_chunksize
324
+ end
325
+
326
+ # Reads data in chunks from the chip.
327
+ # Returns when at least one byte is available or when the latency timer has elapsed.
328
+ # Automatically strips the two modem status bytes transfered during every read.
329
+ # @return [String] Bytes read; Empty string if no bytes read.
330
+ # @see #read_data_chunksize
331
+ # @raise [StatusCodeError] libftdi reports error.
332
+ def read_data
333
+ chunksize = read_data_chunksize
334
+ p = FFI::MemoryPointer.new(:char, chunksize)
335
+ bytes_read = Ftdi.ftdi_read_data(ctx, p, chunksize)
336
+ check_result(bytes_read)
337
+ r = p.read_bytes(bytes_read)
338
+ r.force_encoding("ASCII-8BIT") if r.respond_to?(:force_encoding)
177
339
  r
178
340
  end
179
341
 
342
+ # Gets used interface of the device.
343
+ # @return [Interface] Used interface of the device.
344
+ def interface
345
+ Interface[self[:interface]]
346
+ end
347
+
348
+ # Open selected channels on a chip, otherwise use first channel.
349
+ # @param [Interface] new_interface Interface to use for FT2232C/2232H/4232H chips.
350
+ # @raise [StatusCodeError] libftdi reports error.
351
+ # @return [Interface] New interface.
352
+ def interface=(new_interface)
353
+ check_result(Ftdi.ftdi_set_interface(ctx, new_interface))
354
+ new_interface
355
+ end
356
+
180
357
  private
181
358
  def ctx
182
359
  self.to_ptr
@@ -193,11 +370,20 @@ module Ftdi
193
370
  attach_function :ftdi_new, [ ], :pointer
194
371
  attach_function :ftdi_free, [ :pointer ], :void
195
372
  attach_function :ftdi_usb_open, [ :pointer, :int, :int ], :int
373
+ attach_function :ftdi_usb_open_desc, [ :pointer, :int, :int, :string, :string ], :int
374
+ attach_function :ftdi_usb_open_desc_index, [ :pointer, :int, :int, :string, :string, :uint ], :int
375
+ attach_function :ftdi_usb_reset, [ :pointer ], :int
196
376
  attach_function :ftdi_usb_close, [ :pointer ], :void
197
377
  attach_function :ftdi_set_baudrate, [ :pointer, :int ], :int
198
378
  attach_function :ftdi_set_line_property, [ :pointer, BitsType, StopbitsType, ParityType ], :int
199
379
  attach_function :ftdi_set_line_property2, [ :pointer, BitsType, StopbitsType, ParityType, BreakType ], :int
200
380
  attach_function :ftdi_setflowctrl, [ :pointer, :int ], :int
201
381
  attach_function :ftdi_write_data, [ :pointer, :pointer, :int ], :int
382
+ attach_function :ftdi_write_data_set_chunksize, [ :pointer, :uint ], :int
383
+ attach_function :ftdi_write_data_get_chunksize, [ :pointer, :pointer ], :int
384
+ attach_function :ftdi_read_data, [ :pointer, :pointer, :int ], :int
385
+ attach_function :ftdi_read_data_set_chunksize, [ :pointer, :uint ], :int
386
+ attach_function :ftdi_read_data_get_chunksize, [ :pointer, :pointer ], :int
387
+ attach_function :ftdi_set_interface, [ :pointer, Interface ], :int
202
388
  end
203
389
 
@@ -1,6 +1,5 @@
1
- # libftdi ruby bindings.
2
1
  module Ftdi
3
2
  # Gem version.
4
- VERSION = "0.0.2".freeze
3
+ VERSION = "0.0.3".freeze
5
4
  end
6
5
 
data/test.rb CHANGED
@@ -26,18 +26,19 @@ end
26
26
  begin
27
27
  ctx.usb_open(0x0403, 0x6001)
28
28
  begin
29
+ puts "Interface used: #{ctx.interface}"
30
+ puts "Read buffer chunk size: #{ctx.read_data_chunksize}"
31
+ puts "Write buffer chunk size: #{ctx.write_data_chunksize}"
29
32
  ctx.baudrate = BAUD_RATE
30
33
  ctx.set_line_property(:bits_8, :stop_bit_2, :none)
31
34
  ctx.flowctrl = Ftdi::SIO_DISABLE_FLOW_CTRL
32
35
 
33
- arr = [ 0 ]
34
- 512.times { arr << 1 }
36
+ arr = Array.new(513) { |i| i.zero? ? 0 : 1 }
35
37
  dmx_write(ctx, arr)
36
38
 
37
39
  sleep 1
38
40
 
39
- arr = [ 0 ]
40
- 512.times { arr << 0 }
41
+ arr = [ 0 ] * 513
41
42
  dmx_write(ctx, arr)
42
43
 
43
44
  puts "Context is:"
@@ -50,5 +51,4 @@ rescue Ftdi::Error => e
50
51
  $stderr.puts e.to_s
51
52
  end
52
53
 
53
- ctx.dispose
54
54
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libftdi-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-11 00:00:00.000000000 Z
12
+ date: 2012-04-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi
16
- requirement: &2156787020 !ruby/object:Gem::Requirement
16
+ requirement: &2153402300 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '1.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2156787020
24
+ version_requirements: *2153402300
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: yard
27
- requirement: &2156802300 !ruby/object:Gem::Requirement
27
+ requirement: &2153401800 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.7.5
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2156802300
35
+ version_requirements: *2153401800
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: redcarpet
38
- requirement: &2156801320 !ruby/object:Gem::Requirement
38
+ requirement: &2153401340 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: 1.17.2
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2156801320
46
+ version_requirements: *2153401340
47
47
  description: libftdi library bindings to talk to FTDI chips
48
48
  email:
49
49
  - akzhan.abdulin@gmail.com