domotics-arduino 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,294 @@
1
+ module Domotics
2
+ module Arduino
3
+
4
+ class ArduinoSerialError < StandardError; end
5
+
6
+ module ArduinoSerial
7
+ # Constants from Arduino
8
+ LOW = 0
9
+ HIGH = 1
10
+ STATES = [LOW, HIGH]
11
+ INPUT = 0
12
+ OUTPUT = 1
13
+ INPUTPULLUP = 2
14
+ MODES = [INPUT, OUTPUT, INPUTPULLUP]
15
+ # Replies from board
16
+ SUCCESSREPRLY = 2
17
+ FAILREPRLY = 3
18
+ # Board events
19
+ EVENTS = {'0' => :pin_state_change}
20
+ # Commands for board
21
+ SETPINMODE = 0
22
+ GETDIGITAL = 1
23
+ SETDIGITAL = 2
24
+ GETADC = 3
25
+ SETPWM = 4
26
+ GETWATCH = 5
27
+ SETWATCH = 6
28
+ ECHOREPLY = 7
29
+ DEFAULTS = 8
30
+ SETPWMFREQ = 9
31
+ # Watch states
32
+ WATCHOFF = 0
33
+ WATCHON = 1
34
+ W_STATES = [WATCHOFF, WATCHON]
35
+ # Timers
36
+ TIMER_0 = 0
37
+ TIMER_1 = 1
38
+ TIMER_2 = 2
39
+ TIMER_3 = 3
40
+ TIMER_4 = 4
41
+ TIMER_5 = 5
42
+ def initialize(args_hash = {})
43
+ # grab args from hash
44
+ case @type = args_hash[:type] || :mega
45
+ when :nano
46
+ @port_str = args_hash[:port] || "/dev/ttyUSB0"
47
+ @number_of_pins = 22
48
+ # todo: address of last 2 pins on nano???
49
+ @adc_pins = Array.new(8) { |index| 14+index }
50
+ @pwm_pins = [3,5,6,9,10,11]
51
+ when :mega
52
+ @port_str = args_hash[:port] || "/dev/ttyACM0"
53
+ @number_of_pins = 70
54
+ @adc_pins = Array.new(16) { |index| 54+index }
55
+ @pwm_pins = Array.new(12) { |index| 2+index } + [44,45,46]
56
+ else
57
+ raise ArduinoSerialError, 'Invalid board type.'
58
+ end
59
+ # Not allow multiple command sends
60
+ @command_lock = Mutex.new
61
+ @reply = Queue.new
62
+ # Open connection
63
+ @board = nil
64
+ @board_listener = nil
65
+ connect
66
+ super
67
+ end
68
+
69
+ # ---0--- SETPINMODE
70
+ def set_mode(pin, mode)
71
+ check_pin(pin); check_pin_watch(pin); raise ArgumentError, 'Error! Invalid mode.' unless MODES.include? mode
72
+ $logger.warn { "Already set mode for pin: #{pin}." } if @pin_mode[pin] == mode
73
+ @pin_mode[pin] = mode
74
+ send_command(SETPINMODE, pin, mode)
75
+ end
76
+ def set_input_pullup(pin)
77
+ set_mode(pin, INPUTPULLUP)
78
+ end
79
+
80
+ # ---1--- GETDIGITAL
81
+ def get_digital(pin)
82
+ check_pin(pin)
83
+ send_command(GETDIGITAL, pin)
84
+ end
85
+
86
+ # ---2--- SETDIGITAL
87
+ def set_digital(pin, state)
88
+ check_pin(pin); check_pin_watch(pin); raise ArgumentError, 'Error! Invalid state.' unless STATES.include? state
89
+ set_mode(pin, OUTPUT) unless @pin_mode[pin] == OUTPUT
90
+ send_command(SETDIGITAL, pin, state)
91
+ end
92
+ def set_high(pin)
93
+ set_digital(pin, HIGH)
94
+ end
95
+ def set_low(pin)
96
+ set_digital(pin, LOW)
97
+ end
98
+
99
+ # ---3--- GETADC
100
+ def get_adc(pin)
101
+ check_pin(pin); raise ArgumentError, 'Not ADC pin.' unless @adc_pins.include? pin
102
+ send_command(GETADC, pin)
103
+ end
104
+
105
+ # ---4--- SETPWM
106
+ def set_pwm(pin, value)
107
+ check_pin(pin); check_pin_watch(pin); raise ArgumentError, 'Not PWM or DAC pin.' unless @pwm_pins.include? pin
108
+ raise ArgumentError, 'Invalid PWM value' unless value.is_a?(Integer) and value>=0 and value<=255
109
+ send_command(SETPWM, pin, value)
110
+ end
111
+
112
+ # ---9--- SETPWMFREQ
113
+ def set_pwm_frequency(pin, divisor)
114
+ case @type
115
+ when :nano
116
+ case pin
117
+ when 9,10
118
+ timer = TIMER_1
119
+ when 3,11
120
+ timer = TIMER_2
121
+ else
122
+ timer = nil
123
+ end
124
+ when :mega
125
+ case pin
126
+ when 2,3,5
127
+ timer = TIMER_3
128
+ when 6,7,8
129
+ timer = TIMER_4
130
+ when 9,10
131
+ timer = TIMER_2
132
+ when 11,12
133
+ timer = TIMER_1
134
+ when 44,45,46
135
+ timer = TIMER_5
136
+ else
137
+ timer = nil
138
+ end
139
+ end
140
+ raise ArgumentError, 'Invalid PWM pin for change frequency.' unless timer
141
+ if timer == TIMER_2
142
+ raise ArgumentError, 'Invalid timer divisor.' unless (1..7).include? divisor
143
+ else
144
+ raise ArgumentError, 'Invalid timer divisor.' unless (1..5).include? divisor
145
+ end
146
+ send_command(SETPWMFREQ, timer, divisor)
147
+ end
148
+
149
+ # ---5--- GETWATCH
150
+ def get_watch(pin)
151
+ check_pin(pin)
152
+ send_command(GETWATCH, pin)
153
+ end
154
+
155
+ # ---6--- SETWATCH
156
+ def set_watch(pin, watch)
157
+ check_pin(pin); raise ArgumentError, 'Invalid watch mode.' unless W_STATES.include? watch
158
+ $logger.warn { "Warning! already set watch mode for pin: #{pin}." } if @watch_list[pin] == watch
159
+ set_mode(pin, INPUT) if @pin_mode[pin] == OUTPUT
160
+ @watch_list[pin] = watch
161
+ send_command(SETWATCH, pin, watch)
162
+ end
163
+
164
+ def destroy
165
+ $logger.info { "Destroy board connection..." }
166
+ @command_lock.synchronize do
167
+ @board_listener.exit if @board_listener
168
+ @board.close
169
+ end
170
+ $logger.info { "done." }
171
+ super
172
+ end
173
+
174
+ private
175
+
176
+ # Default event handler simple prints event.
177
+ def event_handler(hash)
178
+ puts hash.inspect
179
+ end
180
+
181
+ # Send command directly to board
182
+ def send_command(command, pin = 0, value = 0)
183
+ @command_lock.synchronize do
184
+ @board.puts("#{command} #{pin} #{value}")
185
+ # Get reply
186
+ case reply = @reply.pop
187
+ when 0
188
+ 0
189
+ when 1
190
+ 1
191
+ when SUCCESSREPRLY
192
+ true
193
+ when FAILREPRLY
194
+ false
195
+ when Array
196
+ reply
197
+ else
198
+ nil
199
+ end
200
+ end
201
+ end
202
+ # Listen for board replies and alarms
203
+ def listen
204
+ @board_listener.exit if @board_listener
205
+ @board_listener = Thread.new do
206
+ begin
207
+ loop do
208
+ message = @board.gets
209
+ raise ArduinoSerialError, 'Board i/o error.' unless message # message nil - board disconected
210
+ message = message.force_encoding("ISO-8859-1").split
211
+ case message.length
212
+ when 1
213
+ @reply.push(message[0].to_i)
214
+ when 3
215
+ event_handler :event => EVENTS[message[0]], :pin => message[1].to_i, :state => message[2].to_i
216
+ when 2
217
+ @reply.push(message.collect{ |m| m.to_i })
218
+ else
219
+ raise ArduinoSerialError, 'Invalid reply from board.'
220
+ end
221
+ end
222
+ rescue ArduinoSerialError => e
223
+ # Continue to operate in new thread
224
+ Thread.new do
225
+ $logger.error e.message
226
+ # Release command lock
227
+ @reply.push(FAILREPRLY) if @command_lock.locked?
228
+ # Close board connection
229
+ @board.close
230
+ $logger.info 'Try to restart board in 5 seconds...'
231
+ sleep 5
232
+ connect
233
+ end
234
+ # Exit errored thread
235
+ @board_listener.exit
236
+ end
237
+ end
238
+ end
239
+ # Connect to board
240
+ def connect
241
+ $logger.info { "Open serial connection to board..." }
242
+ baudrate = 115200; databits = 8; stopbits = 1; parity = SerialPort::NONE
243
+ @board = SerialPort.new(@port_str, baudrate, databits, stopbits, parity)
244
+ @board.read_timeout = 0
245
+ @board.sync = true
246
+ $logger.info { "done." }
247
+ $logger.info { "Initializing arduino board..." }
248
+ # Pin states and mods
249
+ @pin_mode = Array.new(@number_of_pins, INPUT)
250
+ @watch_list = Array.new(@number_of_pins, WATCHOFF)
251
+ # Hard reset board
252
+ @board.dtr = 0
253
+ sleep(2)
254
+ $logger.info { "done." }
255
+ $logger.info { "Starting board listener..." }
256
+ listen
257
+ $logger.info { "done." }
258
+ $logger.info { "Reset board to defaults..." }
259
+ $logger.info { "done." } if send_command(DEFAULTS)
260
+ $logger.info { "Checking connection with board..." }
261
+ random = Random.new
262
+ a, b = 2.times.map { random.rand(0..9) }
263
+ if send_command(ECHOREPLY, a, b) == [b, a]
264
+ $logger.info { "done." }
265
+ else
266
+ $logger.error { "Bad reply from board (wrong firmware?)." }
267
+ raise ArduinoSerialError
268
+ end
269
+ rescue Exception => e
270
+ $logger.error { e.message }
271
+ tries = tries || 0
272
+ tries += 1
273
+ if tries <= 3
274
+ $logger.info { "Attempt #{tries}: try to reconnect in #{5**tries} seconds." }
275
+ sleep 5**tries
276
+ retry
277
+ end
278
+ $logger.error { "Board malfunction. Automatic restart failed." }
279
+ event_handler :event => :malfunction
280
+ end
281
+ # Checks
282
+ def check_pin(pin)
283
+ raise ArgumentError, 'Invalid pin number.' unless pin.is_a?(Integer) and pin>=0 and pin<@number_of_pins
284
+ end
285
+ def check_pin_watch(pin)
286
+ raise ArgumentError, 'Cant access watched pin.' if @watch_list[pin] == WATCHON
287
+ end
288
+
289
+ rescue ArgumentError => e
290
+ $logger.error e.message
291
+ nil
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,28 @@
1
+ # Digital pin
2
+ module Domotics
3
+ module Arduino
4
+ module DigitalPin
5
+ def initialize(args_hash = {})
6
+ @board = Domotics::Device[args_hash[:device]]
7
+ @pin = args_hash[:pin]
8
+ @board.register_pin self, @pin
9
+ super
10
+ end
11
+ def state!
12
+ to_hls @board.get_digital(@pin)
13
+ end
14
+ def set_state(value)
15
+ @board.set_digital @pin, to_lls(value)
16
+ super
17
+ end
18
+ # Convert to High Level State
19
+ def to_hls(value)
20
+ value == ArduinoSerial::HIGH ? :on : :off
21
+ end
22
+ # Convert to Low Level State
23
+ def to_lls(value)
24
+ value == :on ? ArduinoSerial::HIGH : ArduinoSerial::LOW
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/ruby -w
2
+ # coding: utf-8
3
+ module Domotics
4
+ module Arduino
5
+ # Normal_close sensor
6
+ module NCSensor
7
+ include DigitalPin
8
+ def initialize(args_hash = {})
9
+ super
10
+ @board.set_input_pullup @pin
11
+ @board.set_watch @pin, ArduinoSerial::WATCHON
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module Domotics
2
+ module Arduino
3
+ # Normal_open sensor
4
+ module NOSensor
5
+ include DigitalPin
6
+ def initialize(args_hash = {})
7
+ super
8
+ @board.set_watch @pin, ArduinoSerial::WATCHON
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,149 @@
1
+ /*
2
+ * Serial communication for gHome.
3
+ *
4
+ * Input(space separeted):
5
+ * 1. command
6
+ * 2. pin
7
+ * 3. option
8
+ *
9
+ * created 03 Sep 2012
10
+ * by goredar
11
+ */
12
+
13
+
14
+
15
+ // Cons
16
+ // Replys definitions
17
+ const int SuccessReprly = 2;
18
+ const int FailReprly = 3;
19
+ // Input commands definitions
20
+ const int SetPinMode = 0;
21
+ const int GetDigital = 1;
22
+ const int SetDigital = 2;
23
+ const int GetADC = 3;
24
+ const int SetPWM = 4;
25
+ const int GetWatch = 5;
26
+ const int SetWatch = 6;
27
+ const int EchoReply = 7;
28
+ const int Defaults = 8;
29
+ const int SetPWMFreq = 9;
30
+ // Output message definitions
31
+ const int WatchAlarm = 0;
32
+ // Number of pins for board:
33
+ // nano - 22, mega - 70
34
+ const int NumberOfPins = 70;
35
+ // For watch function
36
+ const int WatchOFF = 0;
37
+ const int WatchON = 1;
38
+ // Vars
39
+ int command = 0;
40
+ int pin = 0;
41
+ int option = 0;
42
+ int state = 0;
43
+ boolean watchlist[NumberOfPins];
44
+ int statelist[NumberOfPins];
45
+
46
+ void setup() {
47
+ default_state();
48
+ // Begin serial
49
+ Serial.begin(115200);
50
+ }
51
+ // Main stream
52
+ void loop() {
53
+ if (Serial.available() > 0) {
54
+ // Parse command
55
+ command = Serial.parseInt();
56
+ pin = Serial.parseInt();
57
+ option = Serial.parseInt();
58
+ if (Serial.read() == '\n') {
59
+ switch (command) {
60
+ case SetPinMode:
61
+ pinMode(pin, option);
62
+ Serial.println(SuccessReprly, DEC);
63
+ break;
64
+ case GetDigital:
65
+ Serial.println(digitalRead(pin), DEC);
66
+ break;
67
+ case SetDigital:
68
+ digitalWrite(pin, option);
69
+ Serial.println(SuccessReprly, DEC);
70
+ break;
71
+ case GetADC:
72
+ Serial.println(analogRead(pin), DEC);
73
+ break;
74
+ case SetPWM:
75
+ analogWrite(pin, option);
76
+ Serial.println(SuccessReprly, DEC);
77
+ break;
78
+ case SetPWMFreq:
79
+ switch (pin) {
80
+ case 1: TCCR1B = (TCCR1B & 0xF8) | option; break;
81
+ case 2: TCCR2B = (TCCR2B & 0xF8) | option; break;
82
+ //#ifdef __AVR_ATmega2560__
83
+ case 3: TCCR3B = (TCCR3B & 0xF8) | option; break;
84
+ case 4: TCCR4B = (TCCR4B & 0xF8) | option; break;
85
+ case 5: TCCR5B = (TCCR5B & 0xF8) | option; break;
86
+ //#endif
87
+ }
88
+ Serial.println(SuccessReprly, DEC);
89
+ break;
90
+ case GetWatch:
91
+ if (watchlist[pin]) {
92
+ Serial.println(WatchON, DEC);
93
+ }
94
+ else {
95
+ Serial.println(WatchOFF, DEC);
96
+ }
97
+ break;
98
+ case SetWatch:
99
+ if (option == WatchOFF) {
100
+ watchlist[pin] = false;
101
+ }
102
+ else {
103
+ statelist[pin] = digitalRead(pin);
104
+ watchlist[pin] = true;
105
+ }
106
+ Serial.println(SuccessReprly, DEC);
107
+ break;
108
+ case EchoReply:
109
+ Serial.print(option, DEC);
110
+ Serial.print(' ');
111
+ Serial.println(pin, DEC);
112
+ break;
113
+ case Defaults:
114
+ default_state();
115
+ Serial.println(SuccessReprly, DEC);
116
+ break;
117
+ default:
118
+ // Invalid command
119
+ Serial.println(FailReprly, DEC);
120
+ break;
121
+ }
122
+ }
123
+ else {
124
+ // Invalid input
125
+ Serial.println(FailReprly, DEC);
126
+ }
127
+ }
128
+ for (int i=2; i < NumberOfPins; i++){
129
+ // Watch for changes on digital pins
130
+ if (watchlist[i]) {
131
+ state = digitalRead(i);
132
+ if (state != statelist[i]) {
133
+ statelist[i] = state;
134
+ Serial.print(WatchAlarm, DEC);
135
+ Serial.print(' ');
136
+ Serial.print(i, DEC);
137
+ Serial.print(' ');
138
+ Serial.println(state, DEC);
139
+ }
140
+ }
141
+ }
142
+ }
143
+
144
+ void default_state() {
145
+ for (int i=0; i < NumberOfPins; i++) {
146
+ pinMode(i, INPUT);
147
+ watchlist[i] = false;
148
+ }
149
+ }
@@ -0,0 +1,16 @@
1
+
2
+ int command = 0;
3
+ int pin = 0;
4
+ int option = 0;
5
+ int state = 0;
6
+
7
+ void setup() {
8
+ Serial.begin(115200);
9
+ }
10
+
11
+ void loop() {
12
+ PORTD maps to Arduino digital pins 0 to 7
13
+ PORTB maps to Arduino digital pins 8 to 13
14
+ PORTC maps to Arduino analog pins 0 to 5.
15
+ PORTB |= B1100;
16
+ }
@@ -0,0 +1,26 @@
1
+ module Domotics
2
+ module Arduino
3
+ module PWMPin
4
+ def initialize(args_hash = {})
5
+ @board = Domotics::Device[args_hash[:device]]
6
+ @pin = args_hash[:pin]
7
+ @board.set_pwm_frequency @pin, 1
8
+ super
9
+ end
10
+ def set_state(value = 0)
11
+ value = case value
12
+ when 0, :off
13
+ @board.set_low @pin
14
+ 0
15
+ when 1..254
16
+ @board.set_pwm @pin, value
17
+ value
18
+ when 255, :on
19
+ @board.set_high @pin
20
+ 255
21
+ end
22
+ super value
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,5 @@
1
1
  module Domotics
2
2
  module Arduino
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: domotics-arduino
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -57,6 +57,13 @@ files:
57
57
  - Rakefile
58
58
  - domotics-arduino.gemspec
59
59
  - lib/domotics/arduino.rb
60
+ - lib/domotics/arduino/arduino_serial.rb
61
+ - lib/domotics/arduino/digital_pin.rb
62
+ - lib/domotics/arduino/digital_pin/nc_sensor.rb
63
+ - lib/domotics/arduino/digital_pin/no_sensor.rb
64
+ - lib/domotics/arduino/firmware/duino.pde
65
+ - lib/domotics/arduino/firmware/stepper.c
66
+ - lib/domotics/arduino/pwm_pin.rb
60
67
  - lib/domotics/arduino/version.rb
61
68
  homepage: ''
62
69
  licenses: