aio 0.1.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 70668dcd4f13f77e238662175257cf8b64a621df
4
+ data.tar.gz: 8915cb0cf9a45718b3e72922e085b8d26ea6b842
5
+ SHA512:
6
+ metadata.gz: c906dee14bc8a69610d9d73e18d135130082d5eadd7774284279e3a07cb893a9ab8794e85277f7c22c22a08167ab555302630f614f1f62c832f79b7ec6706bbf
7
+ data.tar.gz: 7805e2d5b780de1c61ae5f84b132a121c8bdcccd1fc6dace35167d7247219f3b67460bf87113126cfdc62236b77a79bf1ee6f43da6497397f00bf990a0228e8e
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "aio"
4
+
5
+ Aio.print_sketch
@@ -0,0 +1,107 @@
1
+ require "aio/constants"
2
+ require "aio/errors"
3
+ require "aio/board"
4
+ require "aio/sketch"
5
+ require "aio/helpers"
6
+
7
+ # {https://github.com/jvalencia80/aio Aio} (Arduino Input/Output) is a robust
8
+ # library with built-in redundancy check for data integrity and command
9
+ # confirmation for remotely controlling {http://arduino.cc Arduino}
10
+ # boards using Ruby code and the serial port.
11
+ #
12
+ # It implements lots of functions found in the
13
+ # {http://arduino.cc/en/Reference/HomePage Arduino Reference} and they even
14
+ # share the same names and parameters for an easier experience.
15
+ #
16
+ # * Currently, these boards are fully supported (and many others should work):
17
+ #
18
+ # * UNO, Duemilanove, Diecimila, Pro
19
+ # * Leonardo, Yun, Micro
20
+ # * Mega, Mega 2560, Mega ADK
21
+ # * Nano, Mini, Fio, Pro Mini
22
+ #
23
+ # * Supported functions implemented in the {Aio::Board Aio::Board} class:
24
+ #
25
+ # * pinMode
26
+ # * digitalRead, digitalWrite
27
+ # * analogRead, analogWrite, analogReference
28
+ # * millis
29
+ #
30
+ # * Supported constants:
31
+ #
32
+ # * LOW, HIGH
33
+ # * INPUT, INPUT_PULLUP, OUTPUT
34
+ # * DEFAULT, INTERNAL, EXTERNAL, INTERNAL1V1, INTERNAL2V56
35
+ #
36
+ # * Other supported functions (see {Aio::Helpers Aio::Helpers} module):
37
+ #
38
+ # * lowByte, highByte, bit, bitClear, bitSet, bitRead, bitWrite
39
+ # * min, max, abs, pow, sqrt, map, constrain
40
+ # * sin, cos, tan
41
+ # * random, randomSeed
42
+ #
43
+ # = Example
44
+ #
45
+ # Blinking a LED:
46
+ #
47
+ # require "aio"
48
+ #
49
+ # Aio::Board.new("/dev/ttyUSB0") do |board|
50
+ # sleep 0.1 until board.ready?
51
+ #
52
+ # board.pinMode(13, Aio::OUTPUT)
53
+ #
54
+ # 5.times do
55
+ # board.digitalWrite(13, Aio::HIGH)
56
+ # sleep 0.5
57
+ # board.digitalWrite(13, Aio::LOW)
58
+ # sleep 0.5
59
+ # end
60
+ # end
61
+ #
62
+ # Check more examples at the {https://github.com/jvalencia80/aio/tree/master/examples Github}
63
+ # page.
64
+ #
65
+ # = Installation
66
+ #
67
+ # 1. Install the {https://rubygems.org/gems/aio Aio} gem:
68
+ #
69
+ # $ gem install aio
70
+ #
71
+ # 2. Print the sketch required by the library:
72
+ #
73
+ # $ aiosketch > sketch.ino
74
+ #
75
+ # or
76
+ #
77
+ # $ ruby -raio -e "Aio.print_sketch" > sketch.ino
78
+ #
79
+ # 3. Compile and burn the sketch using the {http://arduino.cc/en/Main/Software Arduino IDE}.
80
+ #
81
+ # = Limitations
82
+ #
83
+ # - As this library uses the Arduino serial port, digital pins *0* and *1* must not be used.
84
+ #
85
+ # - This library code isn't executed in realtime as Arduino does, and the communication
86
+ # protocol is relatively slow, so trying to make code that requires exact timing is tricky.
87
+ #
88
+ # - Also take into account that this library does not check if *PIN* *X* is available in
89
+ # *BOARD* *Z*, or if the value supplied is valid or not for a specific command,
90
+ # so check your board's documentation first.
91
+ #
92
+ # - This library is *NOT* thread safe.
93
+ #
94
+ # = Issues
95
+ #
96
+ # Post any issues at the {https://github.com/jvalencia80/aio/issues Github issue tracker}.
97
+
98
+ module Aio
99
+ # Prints the Arduino sketch to STDOUT.
100
+ #
101
+ # @return [nil]
102
+
103
+ def self.print_sketch
104
+ STDOUT.puts SKETCH.gsub(/\t/,'')
105
+ nil
106
+ end
107
+ end
@@ -0,0 +1,220 @@
1
+ require "serialport"
2
+
3
+ module Aio
4
+ # This is the main class that communicates with the Arduino board.
5
+ #
6
+ # It implements several mechanisms like ACK/NAK for confirming
7
+ # command execution and {http://en.wikipedia.org/wiki/Longitudinal_redundancy_check redundancy checks}
8
+ # to ensure data integrity.
9
+
10
+ class Board
11
+ # @example Modes of initialization
12
+ # # explicit
13
+ # board = Aio::Board.new("/dev/ttyUSB1")
14
+ #
15
+ # # block mode (closes the connection at the end)
16
+ # Aio::Board.new("/dev/ttyUSB0") do |board|
17
+ # # code...
18
+ # end
19
+ #
20
+ # @param port [String] the device/address used for communication.
21
+ # @yield [self] an optional block of code to execute.
22
+ # @raise [DeviceError] when the serial port is unavailable.
23
+
24
+ def initialize(port)
25
+ @serial = SerialPort.new(port, BAUDRATE, 8, 1, SerialPort::NONE)
26
+ rescue Errno::ENOENT
27
+ raise Aio::DeviceError, "Unavailable serial port at address => '#{port}'"
28
+ else
29
+ @serial.flow_control = SerialPort::NONE
30
+ @serial.read_timeout = TIMEOUT
31
+ @serial.sync = true
32
+
33
+ if block_given?
34
+ yield(self)
35
+ close
36
+ end
37
+ end
38
+
39
+ # Closes the connection with the board.
40
+ #
41
+ # @return [nil]
42
+
43
+ def close
44
+ @serial.close
45
+ nil
46
+ end
47
+
48
+ # Sets the mode of operation for a specific pin.
49
+ #
50
+ # @param pin [Integer] pin number (as stated in the board).
51
+ # @param mode [Integer] mode of operation: {INPUT}, {OUTPUT} or {INPUT_PULLUP}.
52
+ # @return [Boolean] if the command was successful.
53
+ # @raise [DeviceError] on unexpected device errors.
54
+
55
+ def pinMode(pin, mode)
56
+ try(false) {
57
+ sendCMD [1, pin, mode]
58
+ onACK {true}
59
+ }
60
+ end
61
+
62
+ # Reads the value from a specified digital pin.
63
+ #
64
+ # @param pin [Integer] pin number (as stated in the board).
65
+ # @return [Integer, nil] {HIGH} (1), {LOW} (0) or *nil* on error.
66
+ # @raise (see #pinMode)
67
+
68
+ def digitalRead(pin)
69
+ try(nil) {
70
+ sendCMD [2, pin, empty]
71
+ onACK do
72
+ onData(4) do |bytes|
73
+ bytes[0]
74
+ end
75
+ end
76
+ }
77
+ end
78
+
79
+ # Writes a {HIGH} (1) or a {LOW} (0) value to a digital pin.
80
+ #
81
+ # @param pin [Integer] pin number (as stated in the board).
82
+ # @param state [Integer] {HIGH} (1) or {LOW} (0).
83
+ # @return (see #pinMode)
84
+ # @raise (see #pinMode)
85
+
86
+ def digitalWrite(pin, state)
87
+ try(false) {
88
+ sendCMD [3, pin, state]
89
+ onACK {true}
90
+ }
91
+ end
92
+
93
+ # Reads the value from a specified analog pin.
94
+ #
95
+ # @param pin [Integer] pin number (as stated in the board).
96
+ # @return [Integer, nil] an integer between *0* and *1023* or *nil* on error.
97
+ # @raise (see #pinMode)
98
+
99
+ def analogRead(pin)
100
+ try(nil) {
101
+ sendCMD [4, pin, empty]
102
+ onACK do
103
+ onData(4) do |bytes|
104
+ bytes[0] + (bytes[1] << 8)
105
+ end
106
+ end
107
+ }
108
+ end
109
+
110
+ # Writes an analog value (PWM wave) to a pin.
111
+ #
112
+ # @param pin [Integer] pin number (as stated in the board).
113
+ # @param value [Integer] an integer between *0* (always off) and *255* (always on).
114
+ # @return (see #pinMode)
115
+ # @raise (see #pinMode)
116
+
117
+ def analogWrite(pin, value)
118
+ try(false) {
119
+ sendCMD [5, pin, value]
120
+ onACK {true}
121
+ }
122
+ end
123
+
124
+ # Configures the reference voltage used for analog input.
125
+ #
126
+ # @param type [Integer] {DEFAULT}, {EXTERNAL}, {INTERNAL}, {INTERNAL1V1} or {INTERNAL2V56}.
127
+ # @return (see #pinMode)
128
+ # @raise (see #pinMode)
129
+
130
+ def analogReference(type)
131
+ try(false) {
132
+ sendCMD [6, type, empty]
133
+ onACK {true}
134
+ }
135
+ end
136
+
137
+ # Returns the number of milliseconds since the Arduino board began running the current program.
138
+ #
139
+ # @return [Integer, nil] a *32bit* *integer* or *nil* on error.
140
+ # @raise (see #pinMode)
141
+
142
+ def millis
143
+ try(nil) {
144
+ sendCMD [7, empty, empty]
145
+ onACK do
146
+ onData(4) do |bytes|
147
+ bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24)
148
+ end
149
+ end
150
+ }
151
+ end
152
+
153
+ # Tells if the board is ready.
154
+ #
155
+ # @return [Boolean]
156
+ # @raise (see #pinMode)
157
+
158
+ def ready?
159
+ try(false) {
160
+ sendCMD [8, empty, empty]
161
+ onACK {true}
162
+ }
163
+ end
164
+
165
+ private
166
+
167
+ def try(ret, &block)
168
+ instance_eval(&block)
169
+ rescue => e
170
+ @serial.flush_input
171
+ case e
172
+ when EOFError, Aio::CommandError
173
+ return ret
174
+ when Errno::EIO
175
+ raise(Aio::DeviceError, e.message)
176
+ else
177
+ raise
178
+ end
179
+ end
180
+
181
+ def onACK(&block)
182
+ if @serial.readbyte == ACK
183
+ instance_eval(&block)
184
+ else
185
+ raise Aio::CommandError
186
+ end
187
+ end
188
+
189
+ def onData(n, &block)
190
+ bytes = readBytes(n)
191
+ lrc = @serial.readbyte
192
+ if lrc == getLRC(bytes)
193
+ instance_exec(bytes, &block)
194
+ else
195
+ raise Aio::CommandError
196
+ end
197
+ end
198
+
199
+ def sendCMD(ary)
200
+ @serial.putc(SYNCBYTE)
201
+ ary.each {|byte| @serial.putc(byte.to_i)}
202
+ @serial.putc(getLRC(ary))
203
+ end
204
+
205
+ def readBytes(n)
206
+ bytes = []
207
+ n.times {bytes << @serial.readbyte}
208
+ bytes
209
+ end
210
+
211
+ def getLRC(ary)
212
+ lrc = ary.inject(0) {|acc,val| (acc + (val.to_i & 0xff)) & 0xff}
213
+ (lrc ^ 0xff) + 1
214
+ end
215
+
216
+ def empty
217
+ rand(256)
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,28 @@
1
+ module Aio
2
+ # Baud rate (shared with the sketch).
3
+ #
4
+ # Changing it requires printing and burning the sketch again.
5
+
6
+ BAUDRATE = 57600
7
+
8
+ # Read timeout in milliseconds (shared with the sketch).
9
+ #
10
+ # Changing it requires printing and burning the sketch again.
11
+
12
+ TIMEOUT = 100
13
+
14
+ ACK = 246
15
+ NAK = 144
16
+ SYNCBYTE = 255
17
+
18
+ LOW = 0
19
+ HIGH = 1
20
+ INPUT = 0
21
+ OUTPUT = 1
22
+ INPUT_PULLUP = 2
23
+ EXTERNAL = 0
24
+ DEFAULT = 1
25
+ INTERNAL = 3
26
+ INTERNAL1V1 = 2
27
+ INTERNAL2V56 = 3
28
+ end
@@ -0,0 +1,17 @@
1
+ module Aio
2
+ # Generic error.
3
+
4
+ class Error < StandardError
5
+ end
6
+
7
+ # This exception handles serious errors, like an unexpected
8
+ # disconnection between the PC and the Arduino.
9
+
10
+ class DeviceError < Aio::Error
11
+ end
12
+
13
+ # @private
14
+
15
+ class CommandError < Aio::Error
16
+ end
17
+ end
@@ -0,0 +1,86 @@
1
+ module Aio
2
+ # This module adds most of the Arduino Reference functionality.
3
+ #
4
+ # Check the {http://www.arduino.cc/en/reference/homePage Arduino Reference}
5
+ # for more information about them.
6
+
7
+ module Helpers
8
+ def lowByte(num)
9
+ num & 0xff
10
+ end
11
+
12
+ def highByte(num)
13
+ num & 0xff00
14
+ end
15
+
16
+ def bit(n)
17
+ 2**n
18
+ end
19
+
20
+ def bitClear(num, pos)
21
+ num & ~(0x01 << pos)
22
+ end
23
+
24
+ def bitSet(num, pos)
25
+ num | (0x01 << pos)
26
+ end
27
+
28
+ def bitRead(num, pos)
29
+ (num & (0x01 << pos)) >> pos
30
+ end
31
+
32
+ def bitWrite(num, pos, value)
33
+ value == 0 ? bitClear(num, pos) : bitSet(num, pos)
34
+ end
35
+
36
+ def min(x, y)
37
+ x < y ? x : y
38
+ end
39
+
40
+ def max(x, y)
41
+ x < y ? y : x
42
+ end
43
+
44
+ def abs(num)
45
+ num > 0 ? num : -num
46
+ end
47
+
48
+ def pow(base, exponent)
49
+ base ** exponent
50
+ end
51
+
52
+ def sqrt(num)
53
+ Math.sqrt(num)
54
+ end
55
+
56
+ def sin(rad)
57
+ Math.sin(rad)
58
+ end
59
+
60
+ def cos(rad)
61
+ Math.cos(rad)
62
+ end
63
+
64
+ def tan(rad)
65
+ Math.tan(rad)
66
+ end
67
+
68
+ def map(value, min0, max0, min1, max1)
69
+ ((value - min0) * (max1 - min1) / (max0 - min0)) + min0
70
+ end
71
+
72
+ def constrain(value, a, b)
73
+ return a if value < a
74
+ return b if value > b
75
+ value
76
+ end
77
+
78
+ def random(a, b = nil)
79
+ (a and b) ? rand(a..b) : rand(a)
80
+ end
81
+
82
+ def randomSeed(seed)
83
+ srand(seed)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,83 @@
1
+ module Aio
2
+ private
3
+
4
+ # Arduino sketch written in C.
5
+
6
+ SKETCH = <<-SKETCH_END
7
+ #define ISIZE 3
8
+ #define OSIZE 4
9
+
10
+ void setup() {
11
+ Serial.begin(#{BAUDRATE}L);
12
+ Serial.setTimeout(#{TIMEOUT}L);
13
+ }
14
+
15
+ byte input[ISIZE];
16
+ byte output[OSIZE];
17
+
18
+ void loop() {
19
+ byte lrc;
20
+ int param16;
21
+ long param32;
22
+
23
+ while(Serial.read() != #{SYNCBYTE}); /* wait for sync byte */
24
+
25
+ if (readBytes(input, ISIZE) && readBytes(&lrc, 1) && (lrc == getLRC(input, ISIZE))) {
26
+ Serial.write(#{ACK});
27
+ switch(input[0]) {
28
+ case 1: /* pinMode */
29
+ pinMode(input[1], input[2]);
30
+ break;
31
+ case 2: /* digitalRead */
32
+ output[0] = digitalRead(input[1]);
33
+ fill(output, OSIZE, 1);
34
+ Serial.write(output, OSIZE);
35
+ Serial.write(getLRC(output, OSIZE));
36
+ break;
37
+ case 3: /* digitalWrite */
38
+ digitalWrite(input[1], input[2]);
39
+ break;
40
+ case 4: /* analogRead */
41
+ *((int *)output) = analogRead(input[1]);
42
+ fill(output, OSIZE, 2);
43
+ Serial.write(output, OSIZE);
44
+ Serial.write(getLRC(output, OSIZE));
45
+ break;
46
+ case 5: /* analogWrite */
47
+ analogWrite(input[1], input[2]);
48
+ break;
49
+ case 6: /* analogReference */
50
+ analogReference(input[1]);
51
+ break;
52
+ case 7: /* millis */
53
+ *((long *)output) = millis();
54
+ Serial.write(output, OSIZE);
55
+ Serial.write(getLRC(output, OSIZE));
56
+ break;
57
+ case 8: /* ready */
58
+ /* nop */
59
+ break;
60
+ }
61
+ } else {
62
+ Serial.write(#{NAK});
63
+ }
64
+ }
65
+
66
+ byte getLRC(byte *buff, int length) {
67
+ byte lrc = 0;
68
+
69
+ for(int c = 0; c < length; c++)
70
+ lrc += buff[c];
71
+ return ((lrc ^ 0xff) + 1);
72
+ }
73
+
74
+ int readBytes(byte *buff, int length) {
75
+ return (Serial.readBytes(buff, length) == length);
76
+ }
77
+
78
+ void fill(byte *buff, int length, int start) {
79
+ for(int c = start; c < length; c++)
80
+ buff[c] = random(256);
81
+ }
82
+ SKETCH_END
83
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aio
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Javier Valencia
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: serialport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.3.1
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 1.3.1
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ description: "'Aio' is a robust library that implements redundancy checks and command
34
+ confirmation aimed at controlling Arduino boards remotely."
35
+ email:
36
+ - javiervalencia80@gmail.com
37
+ executables:
38
+ - aiosketch
39
+ extensions: []
40
+ extra_rdoc_files: []
41
+ files:
42
+ - bin/aiosketch
43
+ - lib/aio.rb
44
+ - lib/aio/board.rb
45
+ - lib/aio/constants.rb
46
+ - lib/aio/errors.rb
47
+ - lib/aio/helpers.rb
48
+ - lib/aio/sketch.rb
49
+ homepage: http://rubygems.org/gems/aio
50
+ licenses:
51
+ - GPL-2.0
52
+ metadata: {}
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 2.4.5
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: Library for remotely controlling Arduino boards with Ruby code using the
73
+ serial port.
74
+ test_files: []
75
+ has_rdoc: