farmbot-serial 0.6.2 → 0.7.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: deccbc9e0c3c50ebf83cc8182458dfd403ae96fd
4
- data.tar.gz: a2c81cca29087b45e5ed53ad0fd6521ac3b91ab0
3
+ metadata.gz: caf76751695f80320148ccda60a2b7f5f90d99ce
4
+ data.tar.gz: df0cb1eed0147a30522799aa64f1ddedb599b773
5
5
  SHA512:
6
- metadata.gz: e492413633dbb7409125c1ee53490552c6aa90ebd9cab53e346a8024d02159459bec07d6c1d2483c214d99ef65c65b9a5c2c6f4d24089f72dff4d502ab5fdb8b
7
- data.tar.gz: 8dd6af1fe1463ee1a55c63c6701fb7059824a1d21b2b61dadb6431dbb425bbc66c1a799187ceadad5bd5b8b7e22fe8ad1442f62736cfd0730a29eca85fb7dfab
6
+ metadata.gz: 18dffa6b60f61e21f179f770e61d92b75df8a249c7f35afc324a24341571b0b3f82bfcf369579e459315ae88117a71465ca7a8c305cc48701dc76d59ed4c943b
7
+ data.tar.gz: b77c02b6530fe4aa310149d8ce66591c353165708dbe85ebe194df89ee0e2dc7e8aae70a8c34cc5f39d2b0a93761a4600f37db3aa911f7072930bcf42af102e5
@@ -8,17 +8,21 @@ module FB
8
8
  end
9
9
 
10
10
  def execute(gcode)
11
- self.send(gcode.name, gcode)
12
- rescue NoMethodError
13
- bot.log "#{gcode.name} is a valid GCode, but no input handler method exists"
11
+ name = gcode.name
12
+ if respond_to?(name)
13
+ self.send(name, gcode)
14
+ else
15
+ bot.log "#{gcode.name} is a valid GCode, but no input handler method exists"
16
+ end
14
17
  end
15
18
 
16
19
  def unknown(gcode)
17
20
  bot.log "Don't know how to parse incoming GCode: #{gcode}"
18
21
  end
19
22
 
23
+ # Called when the Ardunio is reporting the status of a parameter.
20
24
  def report_parameter_value(gcode)
21
- bot.status.set_pin(gcode.value_of(:P), gcode.value_of(:V))
25
+ bot.status.set(gcode.value_of(:P), gcode.value_of(:V))
22
26
  end
23
27
 
24
28
  def reporting_end_stops(gcode)
@@ -31,7 +35,7 @@ module FB
31
35
 
32
36
  def report_status_value(gcode)
33
37
  # TODO: Verfiy the accuracy of this code. CC: @timevww
34
- bot.status.set_pin(gcode.value_of(:P), gcode.value_of(:V))
38
+ bot.status.set(gcode.value_of(:P), gcode.value_of(:V))
35
39
  end
36
40
 
37
41
  def received(gcode)
@@ -65,13 +65,65 @@ module FB
65
65
 
66
66
  def pin_write(pin:, value:, mode:)
67
67
  write { "F41 P#{pin} V#{value} M#{mode}" }
68
- bot.status.set_pin(pin, value)
68
+ bot.status.set(pin, value)
69
+ end
70
+
71
+ def set_max_speed(axis, value)
72
+ set_paramater_value(axis, value, 71, 72, 73)
73
+ end
74
+
75
+ def set_acceleration(axis, value)
76
+ set_paramater_value(axis, value, 41, 42, 43)
77
+ end
78
+
79
+ def set_timeout(axis, value)
80
+ set_paramater_value(axis, value, 11, 12, 13)
81
+ end
82
+
83
+ def set_steps_per_mm(axis, value)
84
+ raise "The Farmbot Arduino does not currently store a value for steps "\
85
+ "per mm. Keep track of this information at the application level"
86
+ end
87
+
88
+ def set_end_inversion(axis, value)
89
+ set_paramater_value(axis, bool_to_int(value), 21, 22, 23)
90
+ end
91
+
92
+ def set_motor_inversion(axis, value)
93
+ set_paramater_value(axis, bool_to_int(value), 31, 32, 33)
94
+ end
95
+
96
+ def set_negative_coordinates(axis, value)
97
+ raise "Not yet implemented. TODO: This method."
69
98
  end
70
99
 
71
100
  private
72
101
 
102
+ class InvalidAxisEntry < Exception; end
103
+ class BadBooleanValue < Exception; end
104
+
105
+ # The Arduino uses a different parameter number for each axis. Ex:
106
+ # MOVEMENT_TIMEOUT_X is 11 and MOVEMENT_TIMEOUT_Y is 12. To keep things dry,
107
+ # this method will lookup the correct paramater numer based on the axis
108
+ # provided and the three options available (if_x, if_y, if_z)
109
+ def set_paramater_value(axis, value, if_x, if_y, if_z)
110
+ param_num = { 'x' => if_x, 'y' => if_y, 'z' => if_z }[axis.to_s.downcase]
111
+ raise InvalidAxisEntry, "You entered an invalid axis" unless param_num
112
+ write { "F22 P#{param_num} V#{value.to_s}" }
113
+ end
114
+
73
115
  def write(&blk)
74
116
  bot.write(FB::Gcode.new(&blk))
75
117
  end
118
+
119
+ def bool_to_int(value)
120
+ case value
121
+ when true, 'true', 1, '1' then 1
122
+ when false, 'false', 0, '0' then 0
123
+ else
124
+ raise BadBooleanValue, "Farmbot expected a boolean value in one of "\
125
+ "the following forms: [true, false, 1, 0]"
126
+ end
127
+ end
76
128
  end
77
129
  end
@@ -1,12 +1,11 @@
1
1
  module FB
2
2
  class Status
3
3
  # Map of informational status and default values for status within Arduino.
4
- DEFAULT_INFO = {X: 0, Y: 0, Z: 0, S: 10, BUSY: 1, LAST: 'none', PINS: {}}
5
- Info = Struct.new(*DEFAULT_INFO.keys)
4
+ DEFAULT_INFO = {X: 0, Y: 0, Z: 0, S: 10, BUSY: 1, LAST: 'none'}
6
5
 
7
6
  def initialize
8
7
  @changes = EM::Channel.new
9
- @info = Info.new(*DEFAULT_INFO.values)
8
+ @info = OpenStruct.new(DEFAULT_INFO)
10
9
  end
11
10
 
12
11
  def transaction(&blk)
@@ -18,14 +17,11 @@ module FB
18
17
  end
19
18
 
20
19
  def []=(register, value)
21
- transaction do
22
- register = register.upcase.to_sym
23
- @info[register] = value if @info.members.include?(register)
24
- end
20
+ transaction { @info[register.to_s.upcase] = value }
25
21
  end
26
22
 
27
23
  def [](value)
28
- @info[value.upcase.to_sym]
24
+ @info[value.upcase.to_s]
29
25
  end
30
26
 
31
27
  def to_h
@@ -34,10 +30,7 @@ module FB
34
30
 
35
31
  def gcode_update(gcode)
36
32
  transaction do
37
- gcode.params.each do |p|
38
- setter = "#{p.head}="
39
- @info.send(setter, p.tail) if @info.respond_to?(setter)
40
- end
33
+ gcode.params.each { |p| @info[p.head] = p.tail }
41
34
  end
42
35
  end
43
36
 
@@ -49,13 +42,22 @@ module FB
49
42
  self[:BUSY] == 0
50
43
  end
51
44
 
52
- def pin(num)
53
- @info[:PINS][num] || :unknown
45
+ def get(val)
46
+ @info[val.to_s.upcase] || :unknown
47
+ end
48
+
49
+ def set(key, val)
50
+ transaction do |info|
51
+ info[Gcode::PARAMETER_DICTIONARY.fetch(key, key.to_s)] = val
52
+ end
54
53
  end
55
54
 
56
- def set_pin(num, val)
57
- val = [true, 1, '1'].include?(val) ? :on : :off
58
- transaction { |info| info.PINS[num] = val }
55
+ def pin(num)
56
+ case get(num)
57
+ when false, 0, :off then :off
58
+ when true, 1, :on then :on
59
+ else; :unknown
60
+ end
59
61
  end
60
62
  end
61
63
  end
data/lib/gcode.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  require 'yaml'
2
2
  module FB
3
3
  class Gcode
4
- GCODE_DICTIONARY = YAML.load_file(File.join(File.dirname(__FILE__), 'gcode.yml'))
4
+ GCODE_DICTIONARY = YAML.load_file(File.join(File.dirname(__FILE__),
5
+ 'gcode.yml'))
6
+ PARAMETER_DICTIONARY = YAML.load_file(File.join(File.dirname(__FILE__),
7
+ 'parameters.yml'))
5
8
 
6
9
  attr_accessor :cmd, :params, :block
7
10
 
data/lib/gcode.yml CHANGED
@@ -1,3 +1,5 @@
1
+ # This is a dictionary of all the GCodes. They are used by the Arduino to
2
+ # differentiate commands.
1
3
  ---
2
4
  :G0: :move_to_location_at_given_speed_for_axis
3
5
  :G1: :move_to_location_on_a_straight_line
@@ -0,0 +1,25 @@
1
+ # Internally, the arduino uses a number code for each status. Those statuses are
2
+ # defined here.
3
+ ---
4
+ 0: :PARAM_VERSION
5
+ 11: :MOVEMENT_TIMEOUT_X
6
+ 12: :MOVEMENT_TIMEOUT_Y
7
+ 13: :MOVEMENT_TIMEOUT_Z
8
+ 21: :MOVEMENT_INVERT_ENDPOINTS_X
9
+ 22: :MOVEMENT_INVERT_ENDPOINTS_Y
10
+ 23: :MOVEMENT_INVERT_ENDPOINTS_Z
11
+ 31: :MOVEMENT_INVERT_MOTOR_X
12
+ 32: :MOVEMENT_INVERT_MOTOR_Y
13
+ 33: :MOVEMENT_INVERT_MOTOR_Z
14
+ 41: :MOVEMENT_STEPS_ACC_DEC_X
15
+ 42: :MOVEMENT_STEPS_ACC_DEC_Y
16
+ 43: :MOVEMENT_STEPS_ACC_DEC_Z
17
+ 51: :MOVEMENT_HOME_UP_X
18
+ 52: :MOVEMENT_HOME_UP_Y
19
+ 53: :MOVEMENT_HOME_UP_Z
20
+ 61: :MOVEMENT_MIN_SPD_X
21
+ 62: :MOVEMENT_MIN_SPD_Y
22
+ 63: :MOVEMENT_MIN_SPD_Z
23
+ 71: :MOVEMENT_MAX_SPD_X
24
+ 72: :MOVEMENT_MAX_SPD_Y
25
+ 73: :MOVEMENT_MAX_SPD_Z
data/serial-console.rb ADDED
@@ -0,0 +1,45 @@
1
+ require_relative 'lib/farmbot-serial'
2
+ require 'pry'
3
+
4
+ connection = FB::DefaultSerialPort.new('/dev/ttyUSB0')
5
+
6
+ puts """
7
+ THIS IS A SERIAL TERMINAL.
8
+
9
+ """
10
+
11
+ print "> "
12
+
13
+ class KeyboardHandler < EM::Connection
14
+ include EM::Protocols::LineText2
15
+
16
+ attr_reader :connection
17
+
18
+ def initialize(connection)
19
+ @connection = connection
20
+ end
21
+
22
+ def receive_line(data)
23
+ connection.puts(data.chomp + "\r\n")
24
+ puts("Computer: #{data}")
25
+ end
26
+
27
+ def unbind
28
+ EM.stop
29
+ end
30
+ end
31
+
32
+ class SerialHandler < EventMachine::Connection
33
+ def receive_data(data)
34
+ puts("Arduino: #{data}")
35
+ end
36
+
37
+ def unbind
38
+ EM.stop
39
+ end
40
+ end
41
+
42
+ EM.run do
43
+ EM.open_keyboard(KeyboardHandler, connection)
44
+ EM.attach(connection,)
45
+ end
@@ -5,16 +5,18 @@ describe FB::IncomingHandler do
5
5
  let(:bot) { FakeArduino.new }
6
6
  let(:handler) { FB::IncomingHandler.new(bot) }
7
7
 
8
+ it 'gets calibration data' do
9
+ gcode = FB::Gcode.new { "R21 P71 V7654" }
10
+ handler.execute(gcode)
11
+ expect(bot.status.to_h[:MOVEMENT_MAX_SPD_X]).to eq(7654)
12
+ end
13
+
8
14
  it 'handles unknowns' do
9
15
  handler.execute(FakeGcode.new('hello', 'abc'))
10
16
  expectation = "hello is a valid GCode, but no input handler method exists"
11
17
  expect(bot.logger.message).to eq(expectation)
12
18
  end
13
19
 
14
- # def report_parameter_value(gcode)
15
- # bot.status.set_pin(gcode.value_of(:P), gcode.value_of(:V))
16
- # end
17
-
18
20
  it 'reports the value of a parameter' do
19
21
  handler.report_parameter_value(FB::Gcode.new { "A1 P1 V0" })
20
22
  expect(bot.status.pin(1)).to eq(:off)
@@ -73,4 +73,79 @@ describe FB::OutgoingHandler do
73
73
  handler.pin_write(pin: 0, value: 1, mode: 3)
74
74
  expect(bot.next_cmd.to_s).to eq("F41 P0 V1 M3")
75
75
  end
76
+
77
+ it 'sets max speed' do
78
+ handler.set_max_speed(:x, 1000)
79
+ expect(bot.next_cmd.to_s).to eq("F22 P71 V1000")
80
+ handler.set_max_speed(:Y, 100)
81
+ expect(bot.next_cmd.to_s).to eq("F22 P72 V100")
82
+ handler.set_max_speed('z', 1)
83
+ expect(bot.next_cmd.to_s).to eq("F22 P73 V1")
84
+ end
85
+
86
+ it 'sets acceleration' do
87
+ handler.set_acceleration(:x, 123)
88
+ expect(bot.next_cmd.to_s).to eq("F22 P41 V123")
89
+ handler.set_acceleration(:y, 123)
90
+ expect(bot.next_cmd.to_s).to eq("F22 P42 V123")
91
+ handler.set_acceleration(:z, 123)
92
+ expect(bot.next_cmd.to_s).to eq("F22 P43 V123")
93
+ end
94
+
95
+ it 'sets a timeout' do
96
+ handler.set_timeout(:x, 223)
97
+ expect(bot.next_cmd.to_s).to eq("F22 P11 V223")
98
+ handler.set_timeout(:y, 223)
99
+ expect(bot.next_cmd.to_s).to eq("F22 P12 V223")
100
+ handler.set_timeout(:z, 223)
101
+ expect(bot.next_cmd.to_s).to eq("F22 P13 V223")
102
+ end
103
+
104
+ it 'sets end stop inversion' do
105
+ handler.set_end_inversion(:x, true)
106
+ expect(bot.next_cmd.to_s).to eq("F22 P21 V1")
107
+ handler.set_end_inversion(:y, '0')
108
+ expect(bot.next_cmd.to_s).to eq("F22 P22 V0")
109
+ handler.set_end_inversion(:z, 1)
110
+ expect(bot.next_cmd.to_s).to eq("F22 P23 V1")
111
+ end
112
+
113
+ it 'sets motor inversion' do
114
+ handler.set_motor_inversion(:x, false)
115
+ expect(bot.next_cmd.to_s).to eq("F22 P31 V0")
116
+ handler.set_motor_inversion(:y, '1')
117
+ expect(bot.next_cmd.to_s).to eq("F22 P32 V1")
118
+ handler.set_motor_inversion(:z, 0)
119
+ expect(bot.next_cmd.to_s).to eq("F22 P33 V0")
120
+ end
121
+
122
+ it 'does NOT set negative coordinates' do
123
+ expect do
124
+ handler.set_negative_coordinates(:x, 99)
125
+ end.to raise_exception
126
+ end
127
+
128
+ it 'does NOT set steps per mm (thats not the Arduinos job)' do
129
+ expect do
130
+ handler.set_steps_per_mm(:x, 99)
131
+ end.to raise_exception
132
+ end
133
+
134
+ it 'sets end inversion' do
135
+ expect do
136
+ handler.set_steps_per_mm(:x, 99)
137
+ end.to raise_exception
138
+ end
139
+
140
+ it 'raises exceptions when given invalid axis names' do
141
+ expect do
142
+ handler.set_max_speed('q', 1)
143
+ end.to raise_exception(FB::OutgoingHandler::InvalidAxisEntry)
144
+ end
145
+
146
+ it 'handles bad inputs when inverting motors / steps' do
147
+ expect do
148
+ handler.set_motor_inversion(:x, 4)
149
+ end.to raise_exception(FB::OutgoingHandler::BadBooleanValue)
150
+ end
76
151
  end
@@ -46,7 +46,7 @@ describe FB::Status do
46
46
  end
47
47
 
48
48
  it 'reads known and unknow pin values' do
49
- status.set_pin(1, 1)
49
+ status.set(1, 1)
50
50
  expect(status.pin(1)).to eq(:on)
51
51
  expect(status.pin(2)).to eq(:unknown)
52
52
  end
@@ -44,10 +44,5 @@ describe FB::Gcode do
44
44
  expect(FB::Gcode.new{ " " }.cmd.head).to eq(null_token.head)
45
45
  expect(FB::Gcode.new{ " " }.cmd.tail).to eq(null_token.tail)
46
46
  end
47
-
48
- it 'sets dyanmic parameters' do
49
- random_gcode = FB::Gcode.new{ "Q#{Time.now.to_f.to_s[-2, 2]}" }
50
- expect(random_gcode.cmd.tail).to_not eq(random_gcode.cmd.tail)
51
- end
52
47
  end
53
48
 
data/spec/spec_helper.rb CHANGED
@@ -12,22 +12,6 @@ require_relative 'fakes/fake_logger'
12
12
  require_relative 'fakes/fake_arduino'
13
13
  require_relative 'fakes/fake_gcode'
14
14
 
15
- require 'ruby-prof'
16
-
17
- RSpec.configure do |config|
18
- config.before(:suite) do
19
- # Profile the code
20
- RubyProf.start
21
- end
22
-
23
- config.after(:suite) do
24
- result = RubyProf.stop
25
- # Print a flat profile to text
26
- printer = RubyProf::FlatPrinter.new(result)
27
- printer.print(STDOUT)
28
- end
29
- end
30
-
31
15
  # This is used for testing things that require an event loop. Once run, you can
32
16
  # observe / make assertions on side effects.
33
17
  def within_event_loop(ticks_remaining = 1)
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.6.2
4
+ version: 0.7.0
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-06-07 00:00:00.000000000 Z
12
+ date: 2015-08-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -144,6 +144,8 @@ files:
144
144
  - lib/farmbot-serial.rb
145
145
  - lib/gcode.rb
146
146
  - lib/gcode.yml
147
+ - lib/parameters.yml
148
+ - serial-console.rb
147
149
  - spec/fakes/fake_arduino.rb
148
150
  - spec/fakes/fake_gcode.rb
149
151
  - spec/fakes/fake_logger.rb