rbuspirate 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +28 -0
- data/README.md +42 -0
- data/Rakefile +2 -0
- data/bin/console +30 -0
- data/bin/setup +8 -0
- data/examples/i2c.rb +37 -0
- data/examples/uart.rb +29 -0
- data/lib/rbuspirate.rb +91 -0
- data/lib/rbuspirate/commands.rb +79 -0
- data/lib/rbuspirate/helpers.rb +16 -0
- data/lib/rbuspirate/interfaces/i2c.rb +170 -0
- data/lib/rbuspirate/interfaces/uart.rb +128 -0
- data/lib/rbuspirate/responses.rb +17 -0
- data/lib/rbuspirate/timeouts.rb +23 -0
- data/lib/rbuspirate/version.rb +3 -0
- data/rbuspirate.gemspec +31 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e5ac21bf23f1ef37bb26f473b2a1af1fedf6f9d0a0acf1ae57b0d4f9bb1ca488
|
4
|
+
data.tar.gz: ab5ef5031437fd16343c12cb9e3001d05698c02fc262f92aab58aeddb3b4f992
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b74422e19fac09ce79f85bbc9e3a51d0868d1972607daffbad6dd19dfafc497095315f5b43f0ad6e17fc81b253e557cbd5636a68a2dae0df7a2315e29d0f4d45
|
7
|
+
data.tar.gz: ff71fbe1589ac130cc8bf301365a3a4e61a18883c91b52de03f69e387b7cad033318851286161c469ac0ea933627b516f14a6c91c58faeee382abda49482fa33
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rbuspirate (0.1.1)
|
5
|
+
serialport (~> 1.3)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
coderay (1.1.2)
|
11
|
+
method_source (0.9.2)
|
12
|
+
pry (0.12.2)
|
13
|
+
coderay (~> 1.1.0)
|
14
|
+
method_source (~> 0.9.0)
|
15
|
+
rake (10.5.0)
|
16
|
+
serialport (1.3.1)
|
17
|
+
|
18
|
+
PLATFORMS
|
19
|
+
ruby
|
20
|
+
|
21
|
+
DEPENDENCIES
|
22
|
+
bundler (~> 2.0)
|
23
|
+
pry (~> 0.12.2)
|
24
|
+
rake (~> 10.0)
|
25
|
+
rbuspirate!
|
26
|
+
|
27
|
+
BUNDLED WITH
|
28
|
+
2.1.4
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Rbuspirate
|
2
|
+
|
3
|
+
Better ruby driver for buspirate
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'rbuspirate'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install rbuspirate
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
See examples/ dir
|
23
|
+
|
24
|
+
## Status
|
25
|
+
|
26
|
+
I2C: Full support
|
27
|
+
UART: Basic support (only bridge mode, no custom speed)
|
28
|
+
Windows not supported, contributions are welcomed
|
29
|
+
|
30
|
+
## Development
|
31
|
+
|
32
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
33
|
+
|
34
|
+
## Contributing
|
35
|
+
|
36
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/sh7d/rbuspirate.
|
37
|
+
|
38
|
+
## Todo
|
39
|
+
* Documentation
|
40
|
+
* Full uart support
|
41
|
+
* SPI
|
42
|
+
* Other protocols
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'rbuspirate'
|
5
|
+
require 'optparse'
|
6
|
+
require 'pry'
|
7
|
+
|
8
|
+
le_options = {}
|
9
|
+
|
10
|
+
optparse = OptParse.new do |opts|
|
11
|
+
opts.on(
|
12
|
+
'-d device', '--device device', String, 'Path to buspirate device'
|
13
|
+
) do |device|
|
14
|
+
dev_stat = File.stat(device).rdev rescue nil
|
15
|
+
raise 'Connect buspirate first' unless dev_stat
|
16
|
+
raise 'Device argument must be device' if dev_stat.zero?
|
17
|
+
|
18
|
+
le_options[:device] = device
|
19
|
+
end
|
20
|
+
end
|
21
|
+
optparse.parse!
|
22
|
+
le_options.freeze
|
23
|
+
if le_options[:device]
|
24
|
+
bp = SerialPort.new(le_options[:device], 115_200, 8, 1, SerialPort::NONE)
|
25
|
+
rs = Rbuspirate::Client.new(bp)
|
26
|
+
|
27
|
+
binding.pry
|
28
|
+
else
|
29
|
+
puts optparse.to_s
|
30
|
+
end
|
data/bin/setup
ADDED
data/examples/i2c.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rbuspirate'
|
2
|
+
|
3
|
+
bp = Rbuspirate::Client.new('/dev/buspirate')
|
4
|
+
bp.enter_i2c
|
5
|
+
# valid settings are :'5khz', :'50khz', :'100khz', :'400khz'
|
6
|
+
bp.interface.speed = :'400khz'
|
7
|
+
# default vaules are false
|
8
|
+
bp.interface.configure_peripherals(
|
9
|
+
power: true, pullup: true, aux: false, cs: false
|
10
|
+
)
|
11
|
+
# you can see definet peripherals config via accesors
|
12
|
+
puts "Power #{bp.interface.power ? 'enabled' : 'disabled'}"
|
13
|
+
puts "Pull-up resitors #{bp.interface.pullup ? 'enabled' : 'disabled'}"
|
14
|
+
# Frist argument is command
|
15
|
+
# second expected data to read
|
16
|
+
# succes_timeout specifies timeout to read data from device
|
17
|
+
# allow_zerobyte: allows one single byte instead of expected data to read
|
18
|
+
data = bp.interface.write_then_read(0xA1.chr, 4, succes_timeout: 5, allow_zerobyte: false)
|
19
|
+
puts "First 4 bytes are #{data.unpack('H*').join}"
|
20
|
+
|
21
|
+
# You can also acces raw mode
|
22
|
+
# Block is optional
|
23
|
+
bp.interface.send_start
|
24
|
+
ack_array = bp.interface.bulk_write("\xA0\x00\x00\xDE\xAD".b, ack_timeout: 1, &method(:puts))
|
25
|
+
bp.interface.send_stop
|
26
|
+
puts ack_array
|
27
|
+
|
28
|
+
# And read
|
29
|
+
bp.interface.send_start
|
30
|
+
bp.interface.bulk_write("\xA0\x00\x00".b)
|
31
|
+
bp.interface.send_stop
|
32
|
+
bp.interface.send_start
|
33
|
+
bp.interface.bulk_write("\xA1".b)
|
34
|
+
# default vaules are true for acks, and 1 for readbyte_timeout
|
35
|
+
data = bp.interface.read(4, auto_ack: true, auto_nack: true, readbyte_timeout: 1)
|
36
|
+
bp.interface.send_stop
|
37
|
+
puts "First 4 bytes are: #{data.unpack('H*').join}"
|
data/examples/uart.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rbuspirate'
|
2
|
+
|
3
|
+
bp = Rbuspirate::Client.new('/dev/buspirate')
|
4
|
+
bp.enter_uart
|
5
|
+
# set speed
|
6
|
+
bp.interface.speed = 115_200
|
7
|
+
# parity_data possible vaules are: :n8, :e8, :o8, :n9
|
8
|
+
bp.interface.config_uart(
|
9
|
+
pin_out_33: true, stop_bits: 1, parity_data: :n8, rx_idle: true
|
10
|
+
)
|
11
|
+
# you can see defined settings via accesors
|
12
|
+
puts "Pin out voltage #{bp.interface.pin_out_33 ? '3.3V' : '5V'}"
|
13
|
+
# Enable power
|
14
|
+
bp.interface.configure_peripherals(
|
15
|
+
power: false, pullup: false, aux: false, cs: false
|
16
|
+
)
|
17
|
+
# you can call to configure_peripherals like configure_peripherals(power: true)
|
18
|
+
# rest of arguments will be in default state (false)
|
19
|
+
# you can also see peripherals config state via accesors
|
20
|
+
puts "Power #{bp.interface.power ? 'enabled' : 'disabled'}"
|
21
|
+
# Bridge mode
|
22
|
+
bp.interface.enter_bridge
|
23
|
+
|
24
|
+
# raw port is exposed via port accesor
|
25
|
+
port = bp.interface.port
|
26
|
+
|
27
|
+
while (line = port.readline)
|
28
|
+
puts line
|
29
|
+
end
|
data/lib/rbuspirate.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'expect'
|
2
|
+
require 'serialport'
|
3
|
+
|
4
|
+
require 'rbuspirate/commands'
|
5
|
+
require 'rbuspirate/helpers'
|
6
|
+
require 'rbuspirate/responses'
|
7
|
+
require 'rbuspirate/timeouts'
|
8
|
+
require 'rbuspirate/interfaces/i2c'
|
9
|
+
require 'rbuspirate/interfaces/uart'
|
10
|
+
|
11
|
+
module Rbuspirate
|
12
|
+
class Client
|
13
|
+
attr_reader :mode, :interface, :needs_reset
|
14
|
+
|
15
|
+
def initialize(dvc, sync: true)
|
16
|
+
raise ArgumentError, 'Shitty arg' unless [SerialPort, String].include?(dvc.class)
|
17
|
+
|
18
|
+
if dvc.instance_of?(String)
|
19
|
+
raise 'Connect buspirate first' unless File.exist?(dvc)
|
20
|
+
raise 'Device argument must be device' if File.stat(dvc).rdev.zero?
|
21
|
+
|
22
|
+
dvc = SerialPort.new(dvc, 115_200, 8, 1, SerialPort::NONE)
|
23
|
+
end
|
24
|
+
@le_port = dvc
|
25
|
+
@le_port.sync = true if sync
|
26
|
+
@needs_reset = false
|
27
|
+
reset_binary_mode
|
28
|
+
end
|
29
|
+
|
30
|
+
def reset_binary_mode
|
31
|
+
raise 'Device needs reset to change mode' if @needs_reset
|
32
|
+
|
33
|
+
20.times do
|
34
|
+
@le_port.putc(Commands::RESET_BITBANG)
|
35
|
+
resp = @le_port.expect(
|
36
|
+
Responses::BITBANG_MODE, Timeouts::BINARY_RESET
|
37
|
+
)
|
38
|
+
|
39
|
+
if resp
|
40
|
+
@interface = nil
|
41
|
+
@mode = :bitbang
|
42
|
+
return true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
raise 'Enter to bitbang failied'
|
47
|
+
end
|
48
|
+
|
49
|
+
def enter_i2c
|
50
|
+
raise 'Device needs reset to change mode' if @needs_reset
|
51
|
+
|
52
|
+
switch_mode(
|
53
|
+
:i2c, Commands::I2C::ENTER,
|
54
|
+
Timeouts::I2C::ENTER, Responses::I2C::ENTER,
|
55
|
+
Interfaces::I2C
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def enter_uart
|
60
|
+
raise 'Device needs reset to change mode' if @needs_reset
|
61
|
+
|
62
|
+
switch_mode(
|
63
|
+
:uart, Commands::UART::ENTER,
|
64
|
+
Timeouts::UART::ENTER, Responses::UART::ENTER,
|
65
|
+
Interfaces::UART
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def switch_mode(
|
72
|
+
name_symbol, switch_command,
|
73
|
+
wait_timeout, enter_response,
|
74
|
+
interface_class
|
75
|
+
)
|
76
|
+
raise 'Device needs reset to change mode' if @needs_reset
|
77
|
+
|
78
|
+
@le_port.write(switch_command.chr)
|
79
|
+
resp = @le_port.expect(
|
80
|
+
enter_response, wait_timeout
|
81
|
+
)
|
82
|
+
if resp
|
83
|
+
@mode = name_symbol
|
84
|
+
@interface = interface_class.new(@le_port, self)
|
85
|
+
return true
|
86
|
+
end
|
87
|
+
|
88
|
+
raise "Switch to #{name_symbol.to_s.upcase} failied"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Encoding: binary
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Rbuspirate
|
5
|
+
module Commands
|
6
|
+
RESET_BITBANG = 0b00000000
|
7
|
+
|
8
|
+
module I2C
|
9
|
+
ENTER = 0b00000010
|
10
|
+
PREPARE_WRITE = 0b00010000
|
11
|
+
READBYTE = 0b00000100
|
12
|
+
WRITE_THEN_READ = 0x8
|
13
|
+
|
14
|
+
module Config
|
15
|
+
CONF_PER = 0b01000000
|
16
|
+
|
17
|
+
module Peripherals
|
18
|
+
POWER = 0b00001000
|
19
|
+
PULLUP = 0b00000100
|
20
|
+
AUX = 0b00000010
|
21
|
+
CS = 0b00000001
|
22
|
+
end
|
23
|
+
|
24
|
+
module Speed
|
25
|
+
S5KHZ = 0b01100000
|
26
|
+
S50KZ = 0b01100001
|
27
|
+
S100KHZ = 0b01100010
|
28
|
+
S400KHZ = 0b01100011
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module Flow
|
33
|
+
START = 0b00000010
|
34
|
+
STOP = 0b00000011
|
35
|
+
ACK = 0b00000110
|
36
|
+
NACK = 0b00000111
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module UART
|
41
|
+
ENTER = 0b00000011
|
42
|
+
START_BRIDGE = 0b00001111
|
43
|
+
|
44
|
+
module Config
|
45
|
+
CONF_PER = 0b01000000
|
46
|
+
CONF_UART = 0b10000000
|
47
|
+
|
48
|
+
module Peripherals
|
49
|
+
POWER = 0b00001000
|
50
|
+
PULLUP = 0b00000100
|
51
|
+
AUX = 0b00000010
|
52
|
+
CS = 0b00000001
|
53
|
+
end
|
54
|
+
|
55
|
+
module Speed
|
56
|
+
S300 = 0b01100000
|
57
|
+
S1200 = 0b01100001
|
58
|
+
S2400 = 0b01100010
|
59
|
+
S4800 = 0b01100011
|
60
|
+
S9600 = 0b01100100
|
61
|
+
S19200 = 0b01100101
|
62
|
+
S31250 = 0b01100110
|
63
|
+
S38400 = 0b01100111
|
64
|
+
S57600 = 0b01101000
|
65
|
+
S115200 = 0b01101010
|
66
|
+
end
|
67
|
+
|
68
|
+
module UartConf
|
69
|
+
PIN_OUT_33 = 0b00010000
|
70
|
+
DAT_PARITY_8E = 0b00000100
|
71
|
+
DAT_PARITY_80 = 0b00001000
|
72
|
+
DAT_PARITY_9N = 0b00001100
|
73
|
+
STOP_BIT_2 = 0b00000010
|
74
|
+
DISABLE_RX_IDLE = 0b00000001
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Encoding: binary
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Rbuspirate
|
5
|
+
module Helpers
|
6
|
+
private
|
7
|
+
|
8
|
+
def simplex_command(command, tout, ex_message)
|
9
|
+
@le_port.write(command.chr)
|
10
|
+
resp = @le_port.expect(Responses::SUCCESS, tout)
|
11
|
+
return true if resp
|
12
|
+
|
13
|
+
raise ex_message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# Encoding: binary
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
module Rbuspirate
|
7
|
+
module Interfaces
|
8
|
+
class I2C
|
9
|
+
include Helpers
|
10
|
+
attr_reader :speed, :power, :pullup, :aux, :cs
|
11
|
+
|
12
|
+
def initialize(serial, bup)
|
13
|
+
raise 'Bus pirate must be in i2c mode' unless bup.mode == :i2c
|
14
|
+
|
15
|
+
@le_port = serial
|
16
|
+
end
|
17
|
+
|
18
|
+
def configure_peripherals(
|
19
|
+
power: false, pullup: false, aux: false, cs: false
|
20
|
+
)
|
21
|
+
[power, pullup, aux, cs].map(&:class).each do |cls|
|
22
|
+
raise ArgumentError, 'All args must be true or false' unless [FalseClass, TrueClass].include?(cls)
|
23
|
+
end
|
24
|
+
|
25
|
+
bit_config = Commands::I2C::Config::CONF_PER
|
26
|
+
bit_config |= Commands::I2C::Config::Peripherals::POWER if power
|
27
|
+
bit_config |= Commands::I2C::Config::Peripherals::PULLUP if pullup
|
28
|
+
bit_config |= Commands::I2C::Config::Peripherals::AUX if aux
|
29
|
+
bit_config |= Commands::I2C::Config::Peripherals::CS if cs
|
30
|
+
|
31
|
+
simplex_command(
|
32
|
+
bit_config,
|
33
|
+
Timeouts::SUCCESS,
|
34
|
+
'Unable to confgure peripherals'
|
35
|
+
)
|
36
|
+
@power, @pullup, @aux, @cs = power, pullup, aux, cs
|
37
|
+
end
|
38
|
+
|
39
|
+
def speed=(le_speed)
|
40
|
+
bit_speed = case le_speed.to_sym
|
41
|
+
when :'5khz'
|
42
|
+
Commands::I2C::Config::Speed::S5KHZ
|
43
|
+
when :'50khz'
|
44
|
+
Commands::I2C::Config::Speed::S50KHZ
|
45
|
+
when :'100khz'
|
46
|
+
Commands::I2C::Config::Speed::S100KHZ
|
47
|
+
when :'400khz'
|
48
|
+
Commands::I2C::Config::Speed::S400KHZ
|
49
|
+
else
|
50
|
+
raise ArgumentError, 'Bad speed argument'
|
51
|
+
end
|
52
|
+
|
53
|
+
simplex_command(bit_speed, Timeouts::SUCCESS, 'Unable to set speed')
|
54
|
+
end
|
55
|
+
|
56
|
+
def send_start
|
57
|
+
simplex_command(
|
58
|
+
Commands::I2C::Flow::START,
|
59
|
+
Timeouts::I2C::STARTSTOP,
|
60
|
+
'Unable to sent start bit'
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def send_stop
|
65
|
+
simplex_command(
|
66
|
+
Commands::I2C::Flow::STOP,
|
67
|
+
Timeouts::I2C::STARTSTOP,
|
68
|
+
'Unable to sent stop bit'
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
def send_ack
|
73
|
+
simplex_command(
|
74
|
+
Commands::I2C::Flow::ACK,
|
75
|
+
Timeouts::I2C::ACKNACK,
|
76
|
+
'Unable to sent ack'
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def send_nack
|
81
|
+
simplex_command(
|
82
|
+
Commands::I2C::Flow::NACK,
|
83
|
+
Timeouts::I2C::ACKNACK,
|
84
|
+
'Unable to sent nack'
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
def read(bytes = 1, auto_ack: true, auto_nack: true, readbyte_timeout: Timeouts::I2C::READ)
|
89
|
+
result = ''.dup.b
|
90
|
+
bytes.times do |t|
|
91
|
+
@le_port.write(Commands::I2C::READBYTE.chr)
|
92
|
+
Timeout.timeout(readbyte_timeout) do
|
93
|
+
result << @le_port.read(1)
|
94
|
+
end
|
95
|
+
send_ack if auto_ack && t + 1 != bytes
|
96
|
+
send_nack if auto_nack && t + 1 == bytes
|
97
|
+
end
|
98
|
+
result
|
99
|
+
end
|
100
|
+
|
101
|
+
def bulk_write(data, ack_timeout: Timeouts::I2C::SLAVE_ACKNACK)
|
102
|
+
raise ArgumentError, 'data must be String instance' unless data.instance_of?(String)
|
103
|
+
|
104
|
+
if !data.instance_of?(String) || data.instance_of?(String) && data.empty?
|
105
|
+
raise ArgumentError, 'Bad data argument'
|
106
|
+
end
|
107
|
+
raise ArgumentError, 'Data is too long' if data.bytesize > 16
|
108
|
+
|
109
|
+
bit_bulk_write = Commands::I2C::PREPARE_WRITE | data.bytesize - 1
|
110
|
+
simplex_command(
|
111
|
+
bit_bulk_write.chr,
|
112
|
+
Timeouts::I2C::PREPARE_WRITE,
|
113
|
+
'Unable to prepare write mode'
|
114
|
+
)
|
115
|
+
ack_array = []
|
116
|
+
data.each_byte do |data_byte|
|
117
|
+
@le_port.write(data_byte.chr)
|
118
|
+
Timeout.timeout(ack_timeout) do
|
119
|
+
ack_array << case @le_port.read(1).ord
|
120
|
+
when 0
|
121
|
+
:ack
|
122
|
+
when 1
|
123
|
+
:nack
|
124
|
+
else
|
125
|
+
raise 'Unknown bytewrite response'
|
126
|
+
end
|
127
|
+
yield(ack_array.last) if block_given?
|
128
|
+
end
|
129
|
+
end
|
130
|
+
ack_array.freeze
|
131
|
+
end
|
132
|
+
|
133
|
+
def write_then_read(
|
134
|
+
data, expected_bytes = 0,
|
135
|
+
succes_timeout: Timeouts::I2C::WRITE_THEN_READ_S,
|
136
|
+
allow_zerobyte: false
|
137
|
+
)
|
138
|
+
raise ArgumentError, 'Bad data type' unless data.instance_of?(String)
|
139
|
+
raise ArgumentError, 'Data is too long' if data.bytesize > 4096
|
140
|
+
raise ArgumentError, 'Bad expected_bytes type' unless expected_bytes.instance_of?(Integer)
|
141
|
+
raise ArgumentError, 'Bad expected_bytes value' if expected_bytes.negative? || expected_bytes > 4096
|
142
|
+
|
143
|
+
binary_command = Commands::I2C::WRITE_THEN_READ.chr +
|
144
|
+
[data.bytesize, expected_bytes].pack('S>S>') +
|
145
|
+
data
|
146
|
+
@le_port.write(binary_command)
|
147
|
+
result = nil
|
148
|
+
# So fucking ugly
|
149
|
+
begin
|
150
|
+
Timeout.timeout(succes_timeout) do
|
151
|
+
result = @le_port.read(1)
|
152
|
+
end
|
153
|
+
rescue Timeout::Error
|
154
|
+
return false
|
155
|
+
end
|
156
|
+
return false if allow_zerobyte && result.ord.zero?
|
157
|
+
raise 'Write failed' if result.ord.zero?
|
158
|
+
|
159
|
+
if expected_bytes != 0
|
160
|
+
Timeout.timeout(Timeouts::I2C::WRITE_THEN_READ_D) do
|
161
|
+
result = @le_port.read(expected_bytes)
|
162
|
+
end
|
163
|
+
result
|
164
|
+
else
|
165
|
+
true
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# Encoding: binary
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
module Rbuspirate
|
7
|
+
module Interfaces
|
8
|
+
class UART
|
9
|
+
include Helpers
|
10
|
+
attr_reader :bridge, :speed, :power, :pullup, :aux, :cs,
|
11
|
+
:pin_out_33, :parity_data, :stop_bits, :rx_idle,
|
12
|
+
:port
|
13
|
+
|
14
|
+
def initialize(serial, bup)
|
15
|
+
raise 'Bus pirate must be in uart mode' unless bup.mode == :uart
|
16
|
+
|
17
|
+
@bridge = false
|
18
|
+
@bup = bup
|
19
|
+
@le_port = serial
|
20
|
+
end
|
21
|
+
|
22
|
+
def configure_peripherals(
|
23
|
+
power: false, pullup: false, aux: false, cs: false
|
24
|
+
)
|
25
|
+
raise 'Device needs reset in order to reconfigure it' if @bridge
|
26
|
+
|
27
|
+
[power, pullup, aux, cs].map(&:class).each do |cls|
|
28
|
+
raise ArgumentError, 'All args must be true or false' unless [FalseClass, TrueClass].include?(cls)
|
29
|
+
end
|
30
|
+
|
31
|
+
bit_config = Commands::UART::Config::CONF_PER
|
32
|
+
bit_config |= Commands::UART::Config::Peripherals::POWER if power
|
33
|
+
bit_config |= Commands::UART::Config::Peripherals::PULLUP if pullup
|
34
|
+
bit_config |= Commands::UART::Config::Peripherals::AUX if aux
|
35
|
+
bit_config |= Commands::UART::Config::Peripherals::CS if cs
|
36
|
+
|
37
|
+
simplex_command(
|
38
|
+
bit_config,
|
39
|
+
Timeouts::SUCCESS,
|
40
|
+
'Unable to confgure peripherals'
|
41
|
+
)
|
42
|
+
@power, @pullup, @aux, @cs = power, pullup, aux, cs
|
43
|
+
end
|
44
|
+
|
45
|
+
def speed=(le_speed)
|
46
|
+
raise 'Device needs reset in order to reconfigure it' if @bridge
|
47
|
+
|
48
|
+
bit_speed = case le_speed
|
49
|
+
when 300
|
50
|
+
Commands::UART::Config::Speed::S300
|
51
|
+
when 1200
|
52
|
+
Commands::UART::Config::Speed::S1200
|
53
|
+
when 2400
|
54
|
+
Commands::UART::Config::Speed::S2400
|
55
|
+
when 4800
|
56
|
+
Commands::UART::Config::Speed::S4800
|
57
|
+
when 9600
|
58
|
+
Commands::UART::Config::Speed::S9600
|
59
|
+
when 19_200
|
60
|
+
Commands::UART::Config::Speed::S19200
|
61
|
+
when 31_250
|
62
|
+
Commands::UART::Config::Speed::S31250
|
63
|
+
when 38_400
|
64
|
+
Commands::UART::Config::Speed::S38400
|
65
|
+
when 57_600
|
66
|
+
Commands::UART::Config::Speed::S57600
|
67
|
+
when 115_200
|
68
|
+
Commands::UART::Config::Speed::S115200
|
69
|
+
else
|
70
|
+
raise ArgumentError, 'Unsupported speed'
|
71
|
+
end
|
72
|
+
|
73
|
+
simplex_command(bit_speed, Timeouts::SUCCESS, 'Unable to set speed')
|
74
|
+
@speed = bit_speed
|
75
|
+
end
|
76
|
+
|
77
|
+
def config_uart(
|
78
|
+
pin_out_33: false, parity_data: :n8, stop_bits: 1, rx_idle: true
|
79
|
+
)
|
80
|
+
raise 'Device needs reset in order to reconfigure it' if @bridge
|
81
|
+
|
82
|
+
raise ArgumentError, 'Pin out should be false or true' unless [true, false].include?(pin_out_33)
|
83
|
+
raise ArgumentError, 'Unknown praity and databits mode' unless [:n8, :e8, :o8, :n9].include?(parity_data)
|
84
|
+
raise ArgumentError, 'Unknown stop bits mode' unless [1, 2].include?(stop_bits)
|
85
|
+
raise ArgumentError, 'Rx idle should be false or true' unless [true, false].include?(rx_idle)
|
86
|
+
|
87
|
+
bit_conf_uart = Commands::UART::Config::CONF_UART
|
88
|
+
|
89
|
+
bit_conf_uart |= Commands::UART::Config::UartConf::PIN_OUT_33 if pin_out_33
|
90
|
+
bit_conf_uart |= case parity_data
|
91
|
+
when :e8
|
92
|
+
Commands::UART::Config::UartConf::DAT_PARITY_8E
|
93
|
+
when :o8
|
94
|
+
Commands::UART::Config::UartConf::DAT_PARITY_8O
|
95
|
+
when :n9
|
96
|
+
Commands::UART::Config::UartConf::DAT_PARITY_9N
|
97
|
+
else
|
98
|
+
0
|
99
|
+
end
|
100
|
+
bit_conf_uart |= Commands::UART::Config::UartConf::STOP_BIT_2 if stop_bits == 2
|
101
|
+
bit_conf_uart |= Commands::UART::Config::UartConf::DISABLE_RX_IDLE unless rx_idle
|
102
|
+
|
103
|
+
simplex_command(bit_conf_uart, Timeouts::SUCCESS, 'Unable to config uart')
|
104
|
+
|
105
|
+
@pin_out_33, @parity_data, @stop_bits, @rx_idle = pin_out_33, parity_data, stop_bits, rx_idle
|
106
|
+
end
|
107
|
+
|
108
|
+
def enter_bridge
|
109
|
+
return @bridge if @bridge
|
110
|
+
|
111
|
+
@le_port.write(Commands::UART::START_BRIDGE.chr)
|
112
|
+
@bridge = true
|
113
|
+
@bup.instance_variable_set(:@needs_reset, true)
|
114
|
+
@port = @le_port
|
115
|
+
end
|
116
|
+
|
117
|
+
def read(bytes = 0)
|
118
|
+
raise 'Enter to bridge mode first' unless @bridge
|
119
|
+
bytes.positive? ? @le_port.read(bytes) : @le_port.read
|
120
|
+
end
|
121
|
+
|
122
|
+
def write(data)
|
123
|
+
raise 'Enter to bridge mode first' unless @bridge
|
124
|
+
@le_port.write(data.to_s.b)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Encoding: binary
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Rbuspirate
|
5
|
+
module Timeouts
|
6
|
+
BINARY_RESET = 0.05
|
7
|
+
SUCCESS = 0.1
|
8
|
+
module I2C
|
9
|
+
ENTER = 0.2
|
10
|
+
STARTSTOP = 0.5
|
11
|
+
PREPARE_WRITE = 0.1
|
12
|
+
ACKNACK = 0.3
|
13
|
+
READ = 1
|
14
|
+
SLAVE_ACKNACK = 0.5
|
15
|
+
WRITE_THEN_READ_S = 5
|
16
|
+
WRITE_THEN_READ_D = 5
|
17
|
+
end
|
18
|
+
|
19
|
+
module UART
|
20
|
+
ENTER = 0.2
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/rbuspirate.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "rbuspirate/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "rbuspirate"
|
7
|
+
spec.version = Rbuspirate::VERSION
|
8
|
+
spec.authors = ["sh7d"]
|
9
|
+
spec.email = ["sh7d@sh7d"]
|
10
|
+
|
11
|
+
spec.summary = %q{Ruby better buspirate interface}
|
12
|
+
spec.description = %q{Simple buspirate ruby interface}
|
13
|
+
spec.homepage = "https://github.com/sh7d/rbuspirate"
|
14
|
+
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
+
|
17
|
+
# Specify which files should be added to the gem when it is released.
|
18
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
19
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
20
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
21
|
+
end
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ['lib'] + Dir.glob('lib/**').select(&File.method(:directory?))
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "pry", "~> 0.12"
|
29
|
+
spec.add_dependency "serialport", "~> 1.3"
|
30
|
+
end
|
31
|
+
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rbuspirate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- sh7d
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-01-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.12'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.12'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: serialport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
69
|
+
description: Simple buspirate ruby interface
|
70
|
+
email:
|
71
|
+
- sh7d@sh7d
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- Gemfile
|
78
|
+
- Gemfile.lock
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- bin/console
|
82
|
+
- bin/setup
|
83
|
+
- examples/i2c.rb
|
84
|
+
- examples/uart.rb
|
85
|
+
- lib/rbuspirate.rb
|
86
|
+
- lib/rbuspirate/commands.rb
|
87
|
+
- lib/rbuspirate/helpers.rb
|
88
|
+
- lib/rbuspirate/interfaces/i2c.rb
|
89
|
+
- lib/rbuspirate/interfaces/uart.rb
|
90
|
+
- lib/rbuspirate/responses.rb
|
91
|
+
- lib/rbuspirate/timeouts.rb
|
92
|
+
- lib/rbuspirate/version.rb
|
93
|
+
- rbuspirate.gemspec
|
94
|
+
homepage: https://github.com/sh7d/rbuspirate
|
95
|
+
licenses: []
|
96
|
+
metadata:
|
97
|
+
homepage_uri: https://github.com/sh7d/rbuspirate
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
- lib/rbuspirate
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubygems_version: 3.1.2
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Ruby better buspirate interface
|
118
|
+
test_files: []
|