aio 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: