farmbot-serial 0.0.6 → 0.0.7
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.
- checksums.yaml +4 -4
- data/README.md +22 -6
- data/Rakefile +7 -7
- data/example.rb +39 -11
- data/lib/arduino.rb +58 -22
- data/lib/arduino/event_machine.rb +4 -7
- data/lib/arduino/incoming_handler.rb +50 -0
- data/lib/arduino/outgoing_handler.rb +57 -0
- data/lib/arduino/status.rb +29 -4
- data/lib/gcode.rb +12 -2
- data/lib/gcode.yml +4 -4
- data/spec/fixtures/stub_serial_port.rb +2 -13
- data/spec/lib/arduino_spec.rb +26 -0
- data/spec/lib/gcode_spec.rb +41 -0
- data/spec/spec_helper.rb +1 -8
- metadata +9 -8
- data/lib/arduino/command_set.rb +0 -39
- data/lib/param.yml +0 -21
- data/spec/lib/ramps_arduino_values_received_spec.rb +0 -54
- data/testcommands.csv +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52d9fa1d6b06912cce708e6ef54f9b07035678d1
|
4
|
+
data.tar.gz: 665482bd2b934eea96f01a820b886f07df5c3170
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75aefd6382c999e9af8d5417cfbb540122c2bcbe3808c522bef641731ba586ec9fbb4452a1cc42f1356a765b219318f37c8208fc5c31c74581b05070dcd08f73
|
7
|
+
data.tar.gz: 09c86b75932a49c9dbd486e15b906a3ce7982dd243bfcee092584014c6910e3fd8e59fcca3d1f1cac88fda5c8f128f615d0d6fe2d9f581f4c95e7682d774f590
|
data/README.md
CHANGED
@@ -9,22 +9,38 @@ gem install farmbot-serial, '0.0.5'
|
|
9
9
|
```
|
10
10
|
|
11
11
|
```ruby
|
12
|
+
require 'farmbot-serial'
|
13
|
+
|
12
14
|
bot = FB::Arduino.new # Defaults to '/dev/ttyACM0', can be configured.
|
13
15
|
|
14
16
|
EM.run do
|
15
17
|
FB::ArduinoEventMachine.connect(bot)
|
16
18
|
|
17
19
|
# Example 1: Writing to the serial line the "correct way" every 1.5 seconds.
|
18
|
-
|
19
|
-
|
20
|
+
EventMachine::PeriodicTimer.new(1.5) do
|
21
|
+
bot.commands.move_relative(x: 100, y: 50)
|
22
|
+
end
|
20
23
|
|
21
|
-
# Example 2: Writing raw
|
22
|
-
EventMachine::PeriodicTimer.new(2.5) { bot.write("F31 P8") }
|
24
|
+
# Example 2: Writing raw gcode object to serial every 2.5
|
25
|
+
EventMachine::PeriodicTimer.new(2.5) { bot.write FB::Gcode.new("F31 P8") }
|
23
26
|
|
24
27
|
# This will execute after status has been updated / internal code.
|
25
|
-
bot.onmessage { |gcode| puts "
|
28
|
+
bot.onmessage { |gcode| puts "Message just came in." }
|
26
29
|
|
27
30
|
# Try pulling the USB cable out to test this one.
|
28
|
-
bot.onclose { EM.stop }
|
31
|
+
bot.onclose { puts "bye!"; EM.stop }
|
29
32
|
end
|
33
|
+
|
30
34
|
```
|
35
|
+
|
36
|
+
# Upgrading to Ruby 2.2
|
37
|
+
|
38
|
+
This gem requires Ruby 2.2. As of this writing, a Pi is loaded with 1.9.3 by default.
|
39
|
+
|
40
|
+
To upgrade your ruby version, try this:
|
41
|
+
|
42
|
+
```
|
43
|
+
curl -L https://get.rvm.io | bash -s stable --ruby
|
44
|
+
```
|
45
|
+
|
46
|
+
This will take about 2 hours on a standard pi.
|
data/Rakefile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'rake/testtask'
|
1
|
+
# require 'rake/testtask'
|
2
2
|
|
3
|
-
Rake::TestTask.new do |t|
|
4
|
-
|
5
|
-
|
6
|
-
end
|
3
|
+
# Rake::TestTask.new do |t|
|
4
|
+
# t.libs << 'test'
|
5
|
+
# t.test_files = Dir.glob('test/**/*_test.rb')
|
6
|
+
# end
|
7
7
|
|
8
|
-
desc "Run tests"
|
9
|
-
task :default => :test
|
8
|
+
# desc "Run tests"
|
9
|
+
# task :default => :test
|
data/example.rb
CHANGED
@@ -3,19 +3,47 @@ require 'pry'
|
|
3
3
|
|
4
4
|
bot = FB::Arduino.new # Defaults to '/dev/ttyACM0', can be configured.
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
puts """
|
7
|
+
FARMBOT SERIAL SANDBOX. WELCOME!
|
8
|
+
================================"""
|
9
|
+
$commands = {
|
10
|
+
"q" => "bot.commands.emergency_stop",
|
11
|
+
"w" => "bot.commands.move_relative(x: 600)",
|
12
|
+
"s" => "bot.commands.move_relative(x: -600)",
|
13
|
+
"e" => "bot.commands.home_x",
|
14
|
+
"r" => "bot.commands.home_y",
|
15
|
+
"t" => "bot.commands.home_z",
|
16
|
+
"y" => "bot.commands.home_all",
|
17
|
+
"u" => "bot.commands.read_parameter(8)",
|
18
|
+
"i" => "bot.commands.write_parameter",
|
19
|
+
"p" => "bot.commands.read_status(8)",
|
20
|
+
}
|
21
|
+
|
22
|
+
$commands.each { |k, v| puts "#{k}: #{v}" }
|
8
23
|
|
9
|
-
|
10
|
-
|
11
|
-
EventMachine::PeriodicTimer.new(1.5) { bot.commands.move_relative(command) }
|
24
|
+
class KeyboardHandler < EM::Connection
|
25
|
+
include EM::Protocols::LineText2
|
12
26
|
|
13
|
-
|
14
|
-
EventMachine::PeriodicTimer.new(2.5) { bot.write("F31 P8") }
|
27
|
+
attr_reader :bot
|
15
28
|
|
16
|
-
|
17
|
-
|
29
|
+
def initialize(bot)
|
30
|
+
@bot = bot
|
31
|
+
end
|
18
32
|
|
19
|
-
|
20
|
-
|
33
|
+
def receive_line(data)
|
34
|
+
cmd = $commands[data] || ""
|
35
|
+
eval(cmd)
|
36
|
+
end
|
21
37
|
end
|
38
|
+
|
39
|
+
puts "Starting now."
|
40
|
+
|
41
|
+
EM.run do
|
42
|
+
FB::ArduinoEventMachine.connect(bot)
|
43
|
+
bot.onmessage { |gcode| print "#{gcode.name}; " }
|
44
|
+
bot.onchange { |diff| print "#{diff}; " }
|
45
|
+
bot.onclose { puts "bye!"; EM.stop } # Unplug the bot and see
|
46
|
+
# EventMachine::PeriodicTimer.new(2) { bot.serial_port.puts "G82" }
|
47
|
+
EM.open_keyboard(KeyboardHandler, bot)
|
48
|
+
end
|
49
|
+
|
data/lib/arduino.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'serialport'
|
2
2
|
require_relative 'default_serial_port'
|
3
|
-
require_relative 'arduino/
|
3
|
+
require_relative 'arduino/incoming_handler'
|
4
|
+
require_relative 'arduino/outgoing_handler'
|
4
5
|
require_relative 'arduino/event_machine'
|
5
6
|
require_relative 'arduino/status'
|
6
7
|
# Communicate with the arduino using a serial interface
|
@@ -8,14 +9,23 @@ module FB
|
|
8
9
|
class Arduino
|
9
10
|
class EmergencyStop < StandardError; end # Not yet used.
|
10
11
|
|
11
|
-
attr_reader :serial_port, :logger, :commands, :
|
12
|
+
attr_reader :serial_port, :logger, :commands, :inbound_queue, :status,
|
13
|
+
:inputs, :outbound_queue
|
12
14
|
|
13
|
-
#
|
15
|
+
# Initialize and provide a serial object, as well as an IO object to send
|
14
16
|
# log messages to. Default SerialPort is DefaultSerialPort. Default logger
|
15
17
|
# is STDOUT
|
16
|
-
def initialize(serial_port
|
17
|
-
@
|
18
|
-
@
|
18
|
+
def initialize(serial_port: DefaultSerialPort.new, logger: STDOUT)
|
19
|
+
@outbound_queue = [] # Pi -> Arduino Gcode
|
20
|
+
@inbound_queue = EM::Channel.new # Pi <- Arduino
|
21
|
+
|
22
|
+
@serial_port = serial_port
|
23
|
+
@logger = logger
|
24
|
+
@commands = FB::OutgoingHandler.new(self)
|
25
|
+
@inputs = FB::IncomingHandler.new(self)
|
26
|
+
@status = FB::Status.new(self)
|
27
|
+
|
28
|
+
start_event_listeners
|
19
29
|
end
|
20
30
|
|
21
31
|
# Log to screen/file/IO stream
|
@@ -23,36 +33,62 @@ module FB
|
|
23
33
|
logger.puts(message)
|
24
34
|
end
|
25
35
|
|
26
|
-
#
|
27
|
-
|
28
|
-
|
29
|
-
|
36
|
+
# Send outgoing test to arduino from pi
|
37
|
+
def write(string)
|
38
|
+
@outbound_queue.unshift string
|
39
|
+
execute_command_next_tick
|
40
|
+
end
|
41
|
+
|
42
|
+
def onchange(&blk)
|
43
|
+
@onchange = blk
|
30
44
|
end
|
31
45
|
|
32
46
|
# Handle incoming text from arduino into pi
|
33
47
|
def onmessage(&blk)
|
34
|
-
|
35
|
-
@queue.subscribe do |gcodes|
|
36
|
-
gcodes.each do |gcode|
|
37
|
-
parse_incoming(gcode)
|
38
|
-
blk.call(gcode)
|
39
|
-
end
|
40
|
-
end
|
48
|
+
@onmessage = blk
|
41
49
|
end
|
42
50
|
|
43
51
|
def onclose(&blk)
|
44
52
|
@onclose = blk
|
45
53
|
end
|
46
54
|
|
47
|
-
# Send outgoing test to arduino from pi
|
48
|
-
def write(string)
|
49
|
-
serial_port.puts string
|
50
|
-
end
|
51
|
-
|
52
55
|
# Handle loss of serial connection
|
53
56
|
def disconnect
|
54
57
|
log "Connection to device lost"
|
55
58
|
@onclose.call if @onclose
|
56
59
|
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# Highest priority message when processing incoming Gcode. Use for system
|
64
|
+
# level status changes.
|
65
|
+
def parse_incoming(gcode)
|
66
|
+
inputs.execute(gcode)
|
67
|
+
end
|
68
|
+
|
69
|
+
def execute_command_next_tick
|
70
|
+
EM.next_tick do
|
71
|
+
if status.ready?
|
72
|
+
diff = (Time.now - (@time || Time.now)).to_i
|
73
|
+
log "Sending queue after #{diff}s delay" if diff > 0
|
74
|
+
serial_port.puts @outbound_queue.pop
|
75
|
+
@time = nil
|
76
|
+
else
|
77
|
+
@time ||= Time.now
|
78
|
+
serial_port.puts "F31 P8"
|
79
|
+
execute_command_next_tick
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def start_event_listeners
|
85
|
+
status.onchange { |diff| @onchange.call(diff) if @onchange }
|
86
|
+
inbound_queue.subscribe do |gcodes|
|
87
|
+
gcodes.each do |gcode|
|
88
|
+
parse_incoming(gcode)
|
89
|
+
@onmessage.call(gcode) if @onmessage
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
57
93
|
end
|
58
94
|
end
|
@@ -7,12 +7,9 @@ module FB
|
|
7
7
|
attr_accessor :arduino
|
8
8
|
end
|
9
9
|
|
10
|
-
def self.poll(interval, &blk)
|
11
|
-
EventMachine::PeriodicTimer.new(interval.to_f, &blk)
|
12
|
-
end
|
13
|
-
|
14
10
|
def initialize
|
15
|
-
@
|
11
|
+
@bot = self.class.arduino
|
12
|
+
@q, @buffer = @bot.inbound_queue, ''
|
16
13
|
end
|
17
14
|
|
18
15
|
# Gets called when data arrives.
|
@@ -23,7 +20,7 @@ module FB
|
|
23
20
|
send_buffer
|
24
21
|
clear_buffer
|
25
22
|
else
|
26
|
-
add_to_buffer(chunk)
|
23
|
+
add_to_buffer(chunk) # Keep RXing the buffer until chunk completes.
|
27
24
|
end
|
28
25
|
end
|
29
26
|
end
|
@@ -32,7 +29,7 @@ module FB
|
|
32
29
|
# splits the data on \r\n. Unlike Ruby's split() method, this method will
|
33
30
|
# preserve the \r\n.
|
34
31
|
def split_into_chunks(data)
|
35
|
-
data.gsub("\r\n", '
|
32
|
+
data.gsub("\r\n", '\b\a').split('\a').map{ |d| d.gsub('\b', "\r\n") }
|
36
33
|
end
|
37
34
|
|
38
35
|
def clear_buffer
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module FB
|
2
|
+
# Handles Gcode that moves from the Arduino to the Pi (Arduino -> Pi).
|
3
|
+
class IncomingHandler
|
4
|
+
attr_reader :bot
|
5
|
+
|
6
|
+
class UnhandledGcode < StandardError; end
|
7
|
+
|
8
|
+
def initialize(bot)
|
9
|
+
@bot = bot
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute(gcode)
|
13
|
+
self.send(gcode.name, gcode)
|
14
|
+
rescue NoMethodError
|
15
|
+
bot.log "#{gcode.name} is a valid GCode, but no input handler method exists"
|
16
|
+
end
|
17
|
+
|
18
|
+
def unknown(gcode)
|
19
|
+
bot.log "Don't know how to parse incoming GCode: #{gcode}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def received(gcode)
|
23
|
+
bot.status[:busy] = 1
|
24
|
+
end
|
25
|
+
|
26
|
+
def reporting_end_stops(gcode)
|
27
|
+
bot.status.gcode_update(gcode)
|
28
|
+
end
|
29
|
+
|
30
|
+
def report_current_position(gcode)
|
31
|
+
bot.status.gcode_update(gcode)
|
32
|
+
end
|
33
|
+
|
34
|
+
def done(gcode)
|
35
|
+
bot.status[:busy] = 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def busy(gcode)
|
39
|
+
bot.status[:busy] = 1
|
40
|
+
end
|
41
|
+
|
42
|
+
def report_status_value(gcode)
|
43
|
+
bot.status.gcode_update(gcode)
|
44
|
+
end
|
45
|
+
|
46
|
+
def report_software_version(gcode)
|
47
|
+
nil # Don't need the info right now.
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module FB
|
2
|
+
# Responsible for writing to the serial line. Sends Gcode from the pi to the
|
3
|
+
# arduino. (Pi -> Arduino)
|
4
|
+
class OutgoingHandler
|
5
|
+
attr_reader :bot
|
6
|
+
|
7
|
+
class UnhandledGcode < StandardError; end
|
8
|
+
|
9
|
+
def initialize(bot)
|
10
|
+
@bot = bot
|
11
|
+
end
|
12
|
+
|
13
|
+
def emergency_stop(*)
|
14
|
+
bot.outbound_queue = [] # Dump pending commands.
|
15
|
+
bot.serial_port.puts "E" # Don't queue this one- write to serial line.
|
16
|
+
end
|
17
|
+
|
18
|
+
def move_relative(x: 0, y: 0, z: 0, s: 100)
|
19
|
+
write "G00 X#{x} Y#{y} Z#{z}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def home_x
|
23
|
+
write "F11"
|
24
|
+
end
|
25
|
+
|
26
|
+
def home_y
|
27
|
+
write "F12"
|
28
|
+
end
|
29
|
+
|
30
|
+
def home_z
|
31
|
+
write "F13"
|
32
|
+
end
|
33
|
+
|
34
|
+
def home_all
|
35
|
+
write "G28"
|
36
|
+
end
|
37
|
+
|
38
|
+
def read_parameter(num)
|
39
|
+
write "F21 P#{num}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def write_parameter(num, val)
|
43
|
+
write "F22 P#{num} V#{val}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def read_status(pin)
|
47
|
+
write "F31 P#{pin}"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def write(str)
|
53
|
+
bot.write(FB::Gcode.new(str))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
data/lib/arduino/status.rb
CHANGED
@@ -3,23 +3,48 @@ module FB
|
|
3
3
|
# Map of informational status and default values for status within Arduino.
|
4
4
|
DEFAULT_INFO = {X: 0, Y: 0, Z: 0, S: 10, Q: 0, T: 0, C: '', P: 0, V: 0,
|
5
5
|
W: 0, L: 0, E: 0, M: 0, XA: 0, XB: 0, YA: 0, YB: 0, ZA: 0,
|
6
|
-
ZB: 0,
|
7
|
-
# Put it into a struct.
|
6
|
+
ZB: 0,YR: 0, R: 0, BUSY: 0}
|
8
7
|
Info = Struct.new(*DEFAULT_INFO.keys)
|
9
8
|
|
10
9
|
attr_reader :bot
|
11
10
|
|
12
11
|
def initialize(bot)
|
12
|
+
@changes = EM::Channel.new
|
13
13
|
@bot, @info = bot, Info.new(*DEFAULT_INFO.values)
|
14
14
|
end
|
15
15
|
|
16
|
+
def transaction(&blk)
|
17
|
+
old = @info.to_h
|
18
|
+
yield
|
19
|
+
emit_updates(old)
|
20
|
+
end
|
21
|
+
|
16
22
|
def []=(register, value)
|
17
|
-
|
18
|
-
@info[value.upcase.to_sym] = value
|
23
|
+
transaction { @info[register.upcase.to_sym] = value }
|
19
24
|
end
|
20
25
|
|
21
26
|
def [](value)
|
22
27
|
@info[value.upcase.to_sym]
|
23
28
|
end
|
29
|
+
|
30
|
+
def gcode_update(gcode)
|
31
|
+
transaction do
|
32
|
+
gcode.params.each { |p| @info.send("#{p.head}=", p.tail) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def onchange
|
37
|
+
@changes.subscribe { |diff| yield(diff) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def ready?
|
41
|
+
self[:BUSY] == 0
|
42
|
+
end
|
43
|
+
|
44
|
+
def emit_updates(old)
|
45
|
+
# calculate a diff between the old status and new status
|
46
|
+
diff = (@info.to_h.to_a - old.to_a).to_h
|
47
|
+
@changes << diff unless diff.empty?
|
48
|
+
end
|
24
49
|
end
|
25
50
|
end
|
data/lib/gcode.rb
CHANGED
@@ -8,7 +8,7 @@ module FB
|
|
8
8
|
def initialize(str)
|
9
9
|
@str = str
|
10
10
|
@params = str.split(' ').map{|line| GcodeToken.new(line)}
|
11
|
-
@cmd = @params.shift
|
11
|
+
@cmd = @params.shift || 'NULL'
|
12
12
|
end
|
13
13
|
|
14
14
|
# Turns a string of many gcodes into an array of many gcodes. Used to parse
|
@@ -22,6 +22,10 @@ module FB
|
|
22
22
|
GCODE_DICTIONARY[cmd.to_sym] || :unknown
|
23
23
|
end
|
24
24
|
|
25
|
+
def to_s
|
26
|
+
[@cmd, *@params].map(&:to_s).join(" ")
|
27
|
+
end
|
28
|
+
|
25
29
|
# A head/tail pair of a single node of GCode. Ex: R01 = [:R, '01']
|
26
30
|
class GcodeToken
|
27
31
|
attr_reader :head, :tail, :name
|
@@ -29,10 +33,16 @@ module FB
|
|
29
33
|
def initialize(str)
|
30
34
|
nodes = str.scan(/\d+|\D+/) # ["R", "01"]
|
31
35
|
@head, @tail = nodes.shift.to_sym, nodes.join(" ")
|
36
|
+
# Coerce to ints if possible, since serial line is all string types.
|
37
|
+
@tail = @tail.to_i if @tail.match(/^\d+$/)
|
32
38
|
end
|
33
39
|
|
34
40
|
def to_sym
|
35
|
-
|
41
|
+
to_s.to_sym
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"#{head}#{tail}"
|
36
46
|
end
|
37
47
|
end
|
38
48
|
end
|
data/lib/gcode.yml
CHANGED
@@ -26,10 +26,10 @@
|
|
26
26
|
:F82: :report_current_position
|
27
27
|
:F83: :report_software_version
|
28
28
|
:E: :emergency_stop
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
29
|
+
:R1: :received
|
30
|
+
:R2: :done
|
31
|
+
:R3: :error
|
32
|
+
:R4: :busy
|
33
33
|
:R21: :report_parameter_value
|
34
34
|
:R31: :report_status_value
|
35
35
|
:R41: :report_pin_value
|
@@ -1,17 +1,6 @@
|
|
1
1
|
## SERIAL PORT SIMULATION
|
2
2
|
## **********************
|
3
|
-
|
4
|
-
|
5
|
-
class StubSerialPort # TODO: Inherit from StringIO?
|
6
|
-
def initialize(comm_port, parameters)
|
7
|
-
end
|
8
|
-
|
9
|
-
def write(text)
|
10
|
-
text
|
11
|
-
end
|
12
|
-
|
13
|
-
def read(characters)
|
14
|
-
characters
|
15
|
-
end
|
3
|
+
class StubSerialPort < StringIO
|
4
|
+
def initialize(comm_port, parameters)
|
16
5
|
end
|
17
6
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FB::Arduino do
|
4
|
+
let(:logger) { StringIO.new("") }
|
5
|
+
let(:bot) do
|
6
|
+
FB::Arduino.new(StubSerialPort.new(0, 0), logger)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "initializes" do
|
10
|
+
expect(bot).to be_kind_of(FB::Arduino)
|
11
|
+
expect(bot.serial_port).to be_kind_of(StubSerialPort)
|
12
|
+
expect(bot.logger).to be_kind_of(StringIO)
|
13
|
+
expect(bot.commands).to be_kind_of(FB::OutgoingHandler)
|
14
|
+
expect(bot.queue).to be_kind_of(EM::Channel)
|
15
|
+
expect(bot.status).to be_kind_of(FB::Status)
|
16
|
+
expect(bot.inputs).to be_kind_of(FB::IncomingHandler)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'prints to the logger object' do
|
20
|
+
bot.log "Hello, World!"
|
21
|
+
bot.logger.rewind
|
22
|
+
expect(bot.logger.gets.chomp).to eq("Hello, World!")
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe FB::Gcode do
|
3
|
+
let(:gcode) { FB::Gcode.new("F31 P8 ")}
|
4
|
+
|
5
|
+
it("initializes from string") { expect(gcode).to be_kind_of(FB::Gcode) }
|
6
|
+
|
7
|
+
it("infers Gcode name") { expect(gcode.name).to eq(:read_status) }
|
8
|
+
|
9
|
+
it "returns :unknown for bad Gcode tokens" do
|
10
|
+
unknown = FB::Gcode.new("QQQ31 F32 ").name
|
11
|
+
expect(unknown).to eq(:unknown)
|
12
|
+
end
|
13
|
+
|
14
|
+
it("sets the original input string") { expect(gcode.str).to eq("F31 P8 ") }
|
15
|
+
|
16
|
+
it("sets @cmd using the first Gcode node") do
|
17
|
+
expect(gcode.cmd).to be_kind_of(FB::Gcode::GcodeToken)
|
18
|
+
expect(gcode.cmd.head).to eq(:F)
|
19
|
+
expect(gcode.cmd.tail).to eq(31)
|
20
|
+
end
|
21
|
+
|
22
|
+
it("sets @params using the last Gcode node(s)") do
|
23
|
+
expect(gcode.params).to be_kind_of(Array)
|
24
|
+
expect(gcode.params[0]).to be_kind_of(FB::Gcode::GcodeToken)
|
25
|
+
expect(gcode.params[0].head).to eq(:P)
|
26
|
+
expect(gcode.params[0].tail).to eq(8)
|
27
|
+
end
|
28
|
+
|
29
|
+
it("serializes back to string via #to_s") do
|
30
|
+
expect(gcode.to_s).to eq("F31 P8")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "parses multiple Gcodes in a single string via parse_lines" do
|
34
|
+
codes = FB::Gcode.parse_lines("A12 B34\nC56 D78\r\n")
|
35
|
+
expect(codes.count).to eq(2)
|
36
|
+
expect(codes.first).to be_kind_of(FB::Gcode)
|
37
|
+
expect(codes.last.cmd.head).to eq(:C)
|
38
|
+
expect(codes.first.params.first.tail).to eq(34)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -5,13 +5,6 @@ SimpleCov.start do
|
|
5
5
|
end
|
6
6
|
require 'pry'
|
7
7
|
require 'farmbot-serial'
|
8
|
-
|
8
|
+
require_relative 'fixtures/stub_serial_port'
|
9
9
|
RSpec.configure do |config|
|
10
|
-
config.expect_with :rspec do |expectations|
|
11
|
-
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
12
|
-
end
|
13
|
-
|
14
|
-
config.mock_with :rspec do |mocks|
|
15
|
-
mocks.verify_partial_doubles = true
|
16
|
-
end
|
17
10
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: farmbot-serial
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Evers
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-04-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -122,18 +122,18 @@ files:
|
|
122
122
|
- Rakefile
|
123
123
|
- example.rb
|
124
124
|
- lib/arduino.rb
|
125
|
-
- lib/arduino/command_set.rb
|
126
125
|
- lib/arduino/event_machine.rb
|
126
|
+
- lib/arduino/incoming_handler.rb
|
127
|
+
- lib/arduino/outgoing_handler.rb
|
127
128
|
- lib/arduino/status.rb
|
128
129
|
- lib/default_serial_port.rb
|
129
130
|
- lib/farmbot-serial.rb
|
130
131
|
- lib/gcode.rb
|
131
132
|
- lib/gcode.yml
|
132
|
-
- lib/param.yml
|
133
133
|
- spec/fixtures/stub_serial_port.rb
|
134
|
-
- spec/lib/
|
134
|
+
- spec/lib/arduino_spec.rb
|
135
|
+
- spec/lib/gcode_spec.rb
|
135
136
|
- spec/spec_helper.rb
|
136
|
-
- testcommands.csv
|
137
137
|
homepage: http://github.com/farmbot/farmbot-serial
|
138
138
|
licenses:
|
139
139
|
- MIT
|
@@ -146,7 +146,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
146
|
requirements:
|
147
147
|
- - ">="
|
148
148
|
- !ruby/object:Gem::Version
|
149
|
-
version:
|
149
|
+
version: 2.2.0
|
150
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
151
|
requirements:
|
152
152
|
- - ">="
|
@@ -160,5 +160,6 @@ specification_version: 4
|
|
160
160
|
summary: Serial library for Farmbot
|
161
161
|
test_files:
|
162
162
|
- spec/fixtures/stub_serial_port.rb
|
163
|
-
- spec/lib/
|
163
|
+
- spec/lib/arduino_spec.rb
|
164
|
+
- spec/lib/gcode_spec.rb
|
164
165
|
- spec/spec_helper.rb
|
data/lib/arduino/command_set.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
module FB
|
2
|
-
# Composes all logic related to controlling a bot into a single object.
|
3
|
-
# Responsible for writing to the serial line.
|
4
|
-
class ArduinoCommandSet
|
5
|
-
attr_reader :bot
|
6
|
-
|
7
|
-
def initialize(bot)
|
8
|
-
@bot = bot
|
9
|
-
end
|
10
|
-
|
11
|
-
def execute(gcode)
|
12
|
-
puts "SERIAL OUT: #{gcode.name}"
|
13
|
-
self.send(gcode.name, gcode)
|
14
|
-
end
|
15
|
-
|
16
|
-
def emergency_stop(*)
|
17
|
-
bot.write("E")
|
18
|
-
end
|
19
|
-
|
20
|
-
def move_relative(gcode)
|
21
|
-
end
|
22
|
-
|
23
|
-
def received(gcode)
|
24
|
-
end
|
25
|
-
|
26
|
-
def reporting_end_stops(gcode)
|
27
|
-
end
|
28
|
-
|
29
|
-
def report_current_position(gcode)
|
30
|
-
end
|
31
|
-
|
32
|
-
def done(gcode)
|
33
|
-
end
|
34
|
-
|
35
|
-
def report_status_value(gcode)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
data/lib/param.yml
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# ---
|
2
|
-
# X: :x_movement
|
3
|
-
# Y: :y_movement
|
4
|
-
# Z: :z_movement
|
5
|
-
# S: :speed
|
6
|
-
# Q: :quanity
|
7
|
-
# T: :time
|
8
|
-
# C: :comment
|
9
|
-
# P: :parameter
|
10
|
-
# V: :value_number
|
11
|
-
# W: :secondary_value
|
12
|
-
# L: :number
|
13
|
-
# E: :element
|
14
|
-
# M: :pin_mode
|
15
|
-
# M: :read_write_mode
|
16
|
-
# XA: :end_stop_1_x_axis
|
17
|
-
# XB: :end_stop_2_x_axis
|
18
|
-
# YA: :end_stop_1_y_axis
|
19
|
-
# YB: :end_stop_2_y_axis
|
20
|
-
# ZA: :end_stop_1_z_axis
|
21
|
-
# ZB: :end_stop_2_z_axis
|
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
describe FB::HardwareInterfaceArduinoValuesReceived do
|
3
|
-
|
4
|
-
before do
|
5
|
-
@ramps = FB::HardwareInterfaceArduinoValuesReceived.new
|
6
|
-
end
|
7
|
-
|
8
|
-
it "load parameters" do
|
9
|
-
|
10
|
-
p = rand(9999999).to_i
|
11
|
-
v = rand(9999999).to_i
|
12
|
-
|
13
|
-
x = rand(9999999).to_i
|
14
|
-
y = rand(9999999).to_i
|
15
|
-
z = rand(9999999).to_i
|
16
|
-
|
17
|
-
xa = rand(9999999).to_i
|
18
|
-
xb = rand(9999999).to_i
|
19
|
-
ya = rand(9999999).to_i
|
20
|
-
yb = rand(9999999).to_i
|
21
|
-
za = rand(9999999).to_i
|
22
|
-
zb = rand(9999999).to_i
|
23
|
-
|
24
|
-
@ramps.load_parameter("P", p)
|
25
|
-
@ramps.load_parameter("V", v)
|
26
|
-
@ramps.load_parameter("X", x)
|
27
|
-
@ramps.load_parameter("Y", y)
|
28
|
-
@ramps.load_parameter("Z", z)
|
29
|
-
|
30
|
-
@ramps.load_parameter("XA", xa)
|
31
|
-
@ramps.load_parameter("XB", xb)
|
32
|
-
@ramps.load_parameter("YA", ya)
|
33
|
-
@ramps.load_parameter("YB", yb)
|
34
|
-
@ramps.load_parameter("ZA", za)
|
35
|
-
@ramps.load_parameter("ZB", zb)
|
36
|
-
|
37
|
-
expect(@ramps.p).to eq(p)
|
38
|
-
expect(@ramps.v).to eq(v)
|
39
|
-
|
40
|
-
expect(@ramps.x).to eq(x)
|
41
|
-
expect(@ramps.y).to eq(y)
|
42
|
-
expect(@ramps.z).to eq(z)
|
43
|
-
|
44
|
-
expect(@ramps.xa).to eq(xa)
|
45
|
-
expect(@ramps.xb).to eq(xb)
|
46
|
-
expect(@ramps.ya).to eq(ya)
|
47
|
-
expect(@ramps.yb).to eq(yb)
|
48
|
-
expect(@ramps.za).to eq(za)
|
49
|
-
expect(@ramps.zb).to eq(zb)
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
data/testcommands.csv
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
HOME Y,0,0,0
|
2
|
-
HOME X,0,0,0
|
3
|
-
MOVE ABSOLUTE, 0, 30, 0, 0
|
4
|
-
|
5
|
-
MOVE ABSOLUTE, 30, 30, 0, 0
|
6
|
-
DOSE WATER, 0, 0, 0, 5
|
7
|
-
MOVE ABSOLUTE, 60, 30, 0, 0
|
8
|
-
DOSE WATER, 0, 0, 0, 5
|
9
|
-
MOVE ABSOLUTE, 90, 30, 0, 0
|
10
|
-
DOSE WATER, 0, 0, 0, 5
|
11
|
-
MOVE ABSOLUTE,120, 30, 0, 0
|
12
|
-
DOSE WATER, 0, 0, 0, 5
|
13
|
-
|
14
|
-
MOVE ABSOLUTE,120, 60, 0, 0
|
15
|
-
DOSE WATER, 0, 0, 0, 5
|
16
|
-
MOVE ABSOLUTE, 90, 60, 0, 0
|
17
|
-
DOSE WATER, 0, 0, 0, 5
|
18
|
-
MOVE ABSOLUTE, 60, 60, 0, 0
|
19
|
-
DOSE WATER, 0, 0, 0, 5
|
20
|
-
MOVE ABSOLUTE, 30, 60, 0, 0
|
21
|
-
DOSE WATER, 0, 0, 0, 5
|
22
|
-
|
23
|
-
|
24
|
-
HOME Y,0,0,0
|
25
|
-
HOME X,0,0,0
|