From edfe9e9a59ce3c44dbddfdef14d71ba6798d406e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Mon, 22 Feb 2021 17:09:02 +1100 Subject: [PATCH 01/15] feat(new_driver):inital port of wolfvision camera driver from Ruby to Crystal --- drivers/wolfvision/eve14_spec.cr | 83 +++++++++++++++ drivers/wolfvision/eye14.cr | 168 +++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 drivers/wolfvision/eve14_spec.cr create mode 100644 drivers/wolfvision/eye14.cr diff --git a/drivers/wolfvision/eve14_spec.cr b/drivers/wolfvision/eve14_spec.cr new file mode 100644 index 0000000000..98371a2a99 --- /dev/null +++ b/drivers/wolfvision/eve14_spec.cr @@ -0,0 +1,83 @@ +DriverSpecs.mock_driver "Wolfvision::Eye14" do + exec(:power?) + .should_send("\x00\x30\x00") # power query + .responds("\x00\x30\x01\x01") # respond with on + .expect(status[:power]).to be(true) + + wait(150) + + exec(:power, false) + .should_send("\x01\x30\x01\x00") # turn off device + .responds("\x01\x30\x00") # respond with success + .expect(status[:power]).to be(false) + + wait(150) + + exec(:power, true) + .should_send("\x01\x30\x01\x01") # turn off device + .responds("\x01\x30\x00") # respond with success + .expect(status[:power]).to be(true) + + wait(150) + + exec(:power?) + .should_send("\x00\x30\x00") # power query + .responds("\x00\x30\x01\x01") # respond with on + .expect(status[:power]).to be(true) + + wait(150) + + exec(:zoom?) + .should_send("\x00\x20\x00") + .responds("\x00\x20\x02\x00\x09") + .expect(status[:zoom]).to be(9) + + wait(150) + + exec(:zoom, 6) + .should_send("\x01\x20\x02\x00\x06") + .transmit("\x01\x20\x00") + .expect(status[:zoom]).to be(6) + + wait(150) + + exec(:zoom?) + .should_send("\x00\x20\x00") + .responds("\x00\x20\x02\x00\x06") + .expect(status[:zoom]).to be(6) + + wait(150) + + exec(:iris?) + .should_send("\x00\x22\x00") + .responds("\x00\x22\x02\x00\x20") + .expect(status[:iris]).to be(32) + + wait(150) + + exec(:iris, 8) + .should_send("\x01\x22\x02\x00\x08") + .transmit("\x01\x22\x00") + .expect(status[:iris]).to be(8) + + wait(150) + + exec(:iris?) + .should_send("\x00\x22\x00") + .responds("\x00\x22\x02\x00\x08") + .expect(status[:iris]).to be(8) + + wait(150) + + exec(:autofocus?) + .should_send("\x00\x31\x00") + .responds("\x00\x31\x01\x00") + .expect(status[:autofocus]).to be(false) + + wait(150) + + exec(:autofocus) + .should_send("\x01\x31\x01\x01") + .transmit("\x01\x31\x00") # respond with success + .expect(status[:autofocus]).to be(true) +end diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr new file mode 100644 index 0000000000..a67376b62f --- /dev/null +++ b/drivers/wolfvision/eye14.cr @@ -0,0 +1,168 @@ +module Wolfvision; end + +# Documentation: https://www.wolfvision.com/wolf/protocol_command_wolfvision/protocol/commands_eye-14.pdf +# Ruby version: https://github.com/acaprojects/ruby-engine-drivers/tree/beta/modules/wolfvision + +class Wolfvision::Eye14 < PlaceOS::Driver + # TODO: Implement PlaceOS::Driver::Interface::Zoomable + + # include ::Orchestrator::Constants + include PlaceOS::Driver::Utilities::Transcoder + + tcp_port 50915 # Need to go through an RS232 gatway + descriptive_name "WolfVision EYE-14" + generic_name :Camera + + # Communication settings + tokenize indicator: /\x00|\x01|/, callback: :check_length + delay between_sends: 150 + + def on_load + self[:zoom_max] = 3923 + self[:iris_max] = 4094 + self[:zoom_min] = self[:iris_min] = 0 + on_update + end + + def on_update + end + + def on_unload + end + + def connected + schedule.every("60s") do + logger.debug "-- Polling Sony Camera" + power? do + if self[:power] == On + zoom? + iris? + autofocus? + end + end + end + end + + def disconnected + # Disconnected will be called before connect if initial connect fails + schedule.clear + end + + def power(state) + target = is_affirmative?(state) + self[:power_target] = target + + # Execute command + logger.debug { "Target = #{target} and self[:power] = #{self[:power]}" } + if target == On && self[:power] != On + send_cmd("\x30\x01\x01", name: :power_cmd) + elsif target == Off && self[:power] != Off + send_cmd("\x30\x01\x00", name: :power_cmd) + end + end + + # uses only optical zoom + def zoom(position) + val = in_range(position, self[:zoom_max], self[:zoom_min]) + self[:zoom_target] = val + val = sprintf("%04X", val) + logger.debug { "position in decimal is #{position} and hex is #{val}" } + send_cmd("\x20\x02#{hex_to_byte(val)}", name: :zoom_cmd) + end + + def zoom? + send_inq("\x20\x00", priority: 0, name: :zoom_inq) + end + + # set autofocus to on + def autofocus + send_cmd("\x31\x01\x01", name: :autofocus_cmd) + end + + def autofocus? + send_inq("\x31\x00", priority: 0, name: :autofocus_inq) + end + + def iris(position) + val = in_range(position, self[:iris_max], self[:iris_min]) + self[:iris_target] = val + val = sprintf("%04X", val) + logger.debug { "position in decimal is #{position} and hex is #{val}" } + send_cmd("\x22\x02#{hex_to_byte(val)}", name: :iris_cmd) + end + + def iris? + send_inq("\x22\x00", priority: 0, name: :iris_inq) + end + + def power? + send_inq("\x30\x00", priority: 0, name: :power_inq) + end + + def send_cmd(cmd, options = Hash.new) + req = "\x01#{cmd}" + logger.debug { "tell -- 0x#{byte_to_hex(req)} -- #{options[:name]}" } + send(req, options) + end + + def send_inq(inq, options = Hash.new) + req = "\x00#{inq}" + logger.debug { "ask -- 0x#{byte_to_hex(req)} -- #{options[:name]}" } + send(req, options) + end + + def received(data, deferrable, command) + logger.debug { "Received 0x#{byte_to_hex(data)}\n" } + + bytes = str_to_array(data) + + if command && !command[:name].nil? + case command[:name] + when :power_cmd + self[:power] = self[:power_target] if byte_to_hex(data) == "3000" + when :zoom_cmd + self[:zoom] = self[:zoom_target] if byte_to_hex(data) == "2000" + when :iris_cmd + self[:iris] = self[:iris_target] if byte_to_hex(data) == "2200" + when :autofocus_cmd + self[:autofocus] = true if byte_to_hex(data) == "3100" + when :power_inq + # -1 index for array refers to the last element in Ruby + self[:power] = bytes[-1] == 1 + when :zoom_inq + # for some reason the after changing the zoom position + # the first zoom inquiry sends "2000" regardless of the actaul zoom value + # consecutive zoom inquiries will then return the correct zoom value + + return :ignore if byte_to_hex(data) == "2000" + hex = byte_to_hex(data[-2..-1]) + self[:zoom] = hex.to_i(16) + when :autofocus_inq + self[:autofocus] = bytes[-1] == 1 + when :iris_inq + # same thing as zoom inq happens here + return :ignore if byte_to_hex(data) == "2200" + hex = byte_to_hex(data[-2..-1]) + self[:iris] = hex.to_i(16) + else + return :ignore + end + return :success + end + end + + def check_length(byte_str : String) + # response = str_to_array(byte_str) + response = byte_str.to_a + + return false if response.length <= 1 # header is 2 bytes + + len = response[1] + 2 # (data length + header) + + if response.length >= len + return len + else + return false + end + end +end From dc24d474e22dbf86c14efacc3462157c9338b0b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Tue, 23 Feb 2021 14:43:07 +1100 Subject: [PATCH 02/15] refactor(eye14):stuck on having to send in a block --- drivers/wolfvision/eye14.cr | 67 ++++++++++++++++++-------- drivers/wolfvision/eye14_spec.cr | 83 ++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 21 deletions(-) create mode 100644 drivers/wolfvision/eye14_spec.cr diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index a67376b62f..a7480786ec 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -1,8 +1,15 @@ +require "tokenizer" + module Wolfvision; end # Documentation: https://www.wolfvision.com/wolf/protocol_command_wolfvision/protocol/commands_eye-14.pdf # Ruby version: https://github.com/acaprojects/ruby-engine-drivers/tree/beta/modules/wolfvision +enum Power + On + Off +end + class Wolfvision::Eye14 < PlaceOS::Driver # TODO: Implement PlaceOS::Driver::Interface::Zoomable @@ -14,10 +21,16 @@ class Wolfvision::Eye14 < PlaceOS::Driver generic_name :Camera # Communication settings - tokenize indicator: /\x00|\x01|/, callback: :check_length - delay between_sends: 150 + # private getter tokenizer : Tokenizer = Tokenizer.new(Bytes[0x00, 0x01]) + + # tokenize indicator: /\x00|\x01|/, callback: :check_length + # delay between_sends: 150 def on_load + queue.delay = 150.milliseconds + # transport.tokenizer = Tokenizer.new("\r\n") + transport.tokenizer = Tokenizer.new(/\x00|\x01|/) + self[:zoom_max] = 3923 self[:iris_max] = 4094 self[:zoom_min] = self[:iris_min] = 0 @@ -31,14 +44,13 @@ class Wolfvision::Eye14 < PlaceOS::Driver end def connected - schedule.every("60s") do - logger.debug "-- Polling Sony Camera" - power? do - if self[:power] == On - zoom? - iris? - autofocus? - end + schedule.every(60.seconds) do + logger.debug { "-- Polling Sony Camera" } + + if power? && self[:power] == Power::On + zoom? + iris? + autofocus? end end end @@ -48,21 +60,21 @@ class Wolfvision::Eye14 < PlaceOS::Driver schedule.clear end - def power(state) + def power(state : Power = Power::Off) target = is_affirmative?(state) self[:power_target] = target # Execute command logger.debug { "Target = #{target} and self[:power] = #{self[:power]}" } - if target == On && self[:power] != On + if target == Power::On && self[:power] != Power::On send_cmd("\x30\x01\x01", name: :power_cmd) - elsif target == Off && self[:power] != Off + elsif target == Power::Off && self[:power] != Power::Off send_cmd("\x30\x01\x00", name: :power_cmd) end end # uses only optical zoom - def zoom(position) + def zoom(position : String = "") val = in_range(position, self[:zoom_max], self[:zoom_min]) self[:zoom_target] = val val = sprintf("%04X", val) @@ -83,7 +95,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver send_inq("\x31\x00", priority: 0, name: :autofocus_inq) end - def iris(position) + def iris(position : String = "") val = in_range(position, self[:iris_max], self[:iris_min]) self[:iris_target] = val val = sprintf("%04X", val) @@ -97,21 +109,22 @@ class Wolfvision::Eye14 < PlaceOS::Driver def power? send_inq("\x30\x00", priority: 0, name: :power_inq) + !!self[:power]?.try(&.as_bool) end - def send_cmd(cmd, options = Hash.new) + def send_cmd(cmd : String = "", **options) req = "\x01#{cmd}" logger.debug { "tell -- 0x#{byte_to_hex(req)} -- #{options[:name]}" } - send(req, options) + transport.send(req, options) end - def send_inq(inq, options = Hash.new) + def send_inq(inq : String = "", **options) req = "\x00#{inq}" logger.debug { "ask -- 0x#{byte_to_hex(req)} -- #{options[:name]}" } - send(req, options) + transport.send(req, options) end - def received(data, deferrable, command) + def received(data : String = "", command : String = "") logger.debug { "Received 0x#{byte_to_hex(data)}\n" } bytes = str_to_array(data) @@ -151,7 +164,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver end end - def check_length(byte_str : String) + def check_length(byte_str : String = "") # response = str_to_array(byte_str) response = byte_str.to_a @@ -165,4 +178,16 @@ class Wolfvision::Eye14 < PlaceOS::Driver return false end end + + def byte_to_hex(data : String = "") + # data.split(//) + data.hexbytes + # output = "" + # data.each_byte { |c| + # s = c.as(String).to_s(16) + # s.prepend('0') if s.length % 2 > 0 + # output << s + # } + # return output + end end diff --git a/drivers/wolfvision/eye14_spec.cr b/drivers/wolfvision/eye14_spec.cr new file mode 100644 index 0000000000..98371a2a99 --- /dev/null +++ b/drivers/wolfvision/eye14_spec.cr @@ -0,0 +1,83 @@ +DriverSpecs.mock_driver "Wolfvision::Eye14" do + exec(:power?) + .should_send("\x00\x30\x00") # power query + .responds("\x00\x30\x01\x01") # respond with on + .expect(status[:power]).to be(true) + + wait(150) + + exec(:power, false) + .should_send("\x01\x30\x01\x00") # turn off device + .responds("\x01\x30\x00") # respond with success + .expect(status[:power]).to be(false) + + wait(150) + + exec(:power, true) + .should_send("\x01\x30\x01\x01") # turn off device + .responds("\x01\x30\x00") # respond with success + .expect(status[:power]).to be(true) + + wait(150) + + exec(:power?) + .should_send("\x00\x30\x00") # power query + .responds("\x00\x30\x01\x01") # respond with on + .expect(status[:power]).to be(true) + + wait(150) + + exec(:zoom?) + .should_send("\x00\x20\x00") + .responds("\x00\x20\x02\x00\x09") + .expect(status[:zoom]).to be(9) + + wait(150) + + exec(:zoom, 6) + .should_send("\x01\x20\x02\x00\x06") + .transmit("\x01\x20\x00") + .expect(status[:zoom]).to be(6) + + wait(150) + + exec(:zoom?) + .should_send("\x00\x20\x00") + .responds("\x00\x20\x02\x00\x06") + .expect(status[:zoom]).to be(6) + + wait(150) + + exec(:iris?) + .should_send("\x00\x22\x00") + .responds("\x00\x22\x02\x00\x20") + .expect(status[:iris]).to be(32) + + wait(150) + + exec(:iris, 8) + .should_send("\x01\x22\x02\x00\x08") + .transmit("\x01\x22\x00") + .expect(status[:iris]).to be(8) + + wait(150) + + exec(:iris?) + .should_send("\x00\x22\x00") + .responds("\x00\x22\x02\x00\x08") + .expect(status[:iris]).to be(8) + + wait(150) + + exec(:autofocus?) + .should_send("\x00\x31\x00") + .responds("\x00\x31\x01\x00") + .expect(status[:autofocus]).to be(false) + + wait(150) + + exec(:autofocus) + .should_send("\x01\x31\x01\x01") + .transmit("\x01\x31\x00") # respond with success + .expect(status[:autofocus]).to be(true) +end From 3e50364000bf2e71a52c8cd48a03e2bdbca92b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Wed, 24 Feb 2021 16:49:32 +1100 Subject: [PATCH 03/15] refactor(eye14):stuck on working received --- drivers/wolfvision/eye14.cr | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index a7480786ec..4d674d6900 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -16,6 +16,12 @@ class Wolfvision::Eye14 < PlaceOS::Driver # include ::Orchestrator::Constants include PlaceOS::Driver::Utilities::Transcoder + # include Interface::Powerable + # include Interface::Muteable + + @channel : Channel(String) = Channel(String).new + # stable_power : Bool = true + tcp_port 50915 # Need to go through an RS232 gatway descriptive_name "WolfVision EYE-14" generic_name :Camera @@ -115,16 +121,18 @@ class Wolfvision::Eye14 < PlaceOS::Driver def send_cmd(cmd : String = "", **options) req = "\x01#{cmd}" logger.debug { "tell -- 0x#{byte_to_hex(req)} -- #{options[:name]}" } - transport.send(req, options) + # @channel.send(req, options) + @channel.send(req) end def send_inq(inq : String = "", **options) req = "\x00#{inq}" logger.debug { "ask -- 0x#{byte_to_hex(req)} -- #{options[:name]}" } - transport.send(req, options) + # @channel.send(req, options) + @channel.send(req) end - def received(data : String = "", command : String = "") + def received(data : Slice = Slice.empty, command : PlaceOS::Driver::Task = "null") logger.debug { "Received 0x#{byte_to_hex(data)}\n" } bytes = str_to_array(data) From 76ec4595ac813b4f40a24b9d5c1913dbfe9e16b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Thu, 25 Feb 2021 11:10:57 +1100 Subject: [PATCH 04/15] feat(eye14):implement camera and powerable interfaces --- drivers/wolfvision/eye14.cr | 53 ++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index 4d674d6900..cc88e243be 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -1,45 +1,38 @@ -require "tokenizer" +require "digest/md5" +require "placeos-driver/interface/muteable" +require "placeos-driver/interface/powerable" +require "placeos-driver/interface/switchable" +require "placeos-driver/interface/camera" + +# require "tokenizer" module Wolfvision; end # Documentation: https://www.wolfvision.com/wolf/protocol_command_wolfvision/protocol/commands_eye-14.pdf # Ruby version: https://github.com/acaprojects/ruby-engine-drivers/tree/beta/modules/wolfvision -enum Power - On - Off -end - class Wolfvision::Eye14 < PlaceOS::Driver - # TODO: Implement PlaceOS::Driver::Interface::Zoomable - - # include ::Orchestrator::Constants - include PlaceOS::Driver::Utilities::Transcoder - - # include Interface::Powerable - # include Interface::Muteable + include PlaceOS::Driver::Interface::Camera + include Interface::Powerable + include Interface::Muteable + # include PlaceOS::Driver::Interface::InputSelection(Power) @channel : Channel(String) = Channel(String).new - # stable_power : Bool = true + @stable_power : Bool = true tcp_port 50915 # Need to go through an RS232 gatway descriptive_name "WolfVision EYE-14" generic_name :Camera - # Communication settings - # private getter tokenizer : Tokenizer = Tokenizer.new(Bytes[0x00, 0x01]) - - # tokenize indicator: /\x00|\x01|/, callback: :check_length # delay between_sends: 150 def on_load - queue.delay = 150.milliseconds - # transport.tokenizer = Tokenizer.new("\r\n") + # transport.tokenizer = Tokenizer.new("\r") transport.tokenizer = Tokenizer.new(/\x00|\x01|/) - self[:zoom_max] = 3923 - self[:iris_max] = 4094 - self[:zoom_min] = self[:iris_min] = 0 + @zoom_range = 0..3923 + @iris_range = 0..4094 + on_update end @@ -53,7 +46,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver schedule.every(60.seconds) do logger.debug { "-- Polling Sony Camera" } - if power? && self[:power] == Power::On + if power? && self[:power] == PowerState::On zoom? iris? autofocus? @@ -63,25 +56,25 @@ class Wolfvision::Eye14 < PlaceOS::Driver def disconnected # Disconnected will be called before connect if initial connect fails - schedule.clear + @channel.close unless @channel.closed? end - def power(state : Power = Power::Off) + def power(state : Power = PowerState::Off) target = is_affirmative?(state) self[:power_target] = target # Execute command logger.debug { "Target = #{target} and self[:power] = #{self[:power]}" } - if target == Power::On && self[:power] != Power::On + if target == PowerState::On && self[:power] != PowerState::On send_cmd("\x30\x01\x01", name: :power_cmd) - elsif target == Power::Off && self[:power] != Power::Off + elsif target == PowerState::Off && self[:power] != PowerState::Off send_cmd("\x30\x01\x00", name: :power_cmd) end end # uses only optical zoom def zoom(position : String = "") - val = in_range(position, self[:zoom_max], self[:zoom_min]) + val = in_range(position, @zoom_range.max, @zoom_range.min) self[:zoom_target] = val val = sprintf("%04X", val) logger.debug { "position in decimal is #{position} and hex is #{val}" } @@ -102,7 +95,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver end def iris(position : String = "") - val = in_range(position, self[:iris_max], self[:iris_min]) + val = in_range(position, @iris_range.max, @iris_range.min) self[:iris_target] = val val = sprintf("%04X", val) logger.debug { "position in decimal is #{position} and hex is #{val}" } From 537b861a58daefd44ce9709a6bd473e984af27f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Thu, 25 Feb 2021 11:48:50 +1100 Subject: [PATCH 05/15] feat(eye14):implement do_send COMMANDS and power on/off --- drivers/wolfvision/eye14.cr | 52 ++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index cc88e243be..2d6dfce1bf 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -24,6 +24,17 @@ class Wolfvision::Eye14 < PlaceOS::Driver descriptive_name "WolfVision EYE-14" generic_name :Camera + COMMANDS = { + power_on: "\x01\x30\x01\x01", + power_off: "\x01\x30\x01\x00", + power_query: "\x00\x30\x00", + autofocus: "\x01\x31\x01\x01", + autofocus_query: "\x00\x31\x00", + iris: "\x01\x22\x02", + iris_query: "\x00\x22\x00", + } + RESPONSES = COMMANDS.to_h.invert + # delay between_sends: 150 def on_load @@ -59,16 +70,17 @@ class Wolfvision::Eye14 < PlaceOS::Driver @channel.close unless @channel.closed? end - def power(state : Power = PowerState::Off) - target = is_affirmative?(state) - self[:power_target] = target + def power(state : Bool) + self[:stable_power] = @stable_power = false + self[:power_target] = state + + if state + logger.debug { "requested to power on" } + do_send(:power_on, retries: 10, name: :power_on, delay: 8.seconds) + else + logger.debug { "requested to power off" } + do_send(:power_off, retries: 10, name: :power_off, delay: 8.seconds) # .get - # Execute command - logger.debug { "Target = #{target} and self[:power] = #{self[:power]}" } - if target == PowerState::On && self[:power] != PowerState::On - send_cmd("\x30\x01\x01", name: :power_cmd) - elsif target == PowerState::Off && self[:power] != PowerState::Off - send_cmd("\x30\x01\x00", name: :power_cmd) end end @@ -191,4 +203,26 @@ class Wolfvision::Eye14 < PlaceOS::Driver # } # return output end + + protected def do_send(command, param = nil, **options) + # prepare the command + cmd = COMMANDS[command] + + logger.debug { "queuing #{command}: #{cmd}" } + + # queue the request + queue(**({ + name: command, + }.merge(options))) do + # prepare channel and connect to the projector (which will then send the random key) + @channel = Channel(String).new + transport.connect + # wait for the random key to arrive + random_key = @channel.receive + # send the request + # NOTE:: the built in `send` function has implicit queuing, but we are + # in a task callback here so should be calling transport send directly + transport.send(cmd) + end + end end From ea7c4d13ecf4abf5c028ff816ea76078d2fc2234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Thu, 25 Feb 2021 12:05:03 +1100 Subject: [PATCH 06/15] feat(eye14):implement zoom --- drivers/wolfvision/eye14.cr | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index 2d6dfce1bf..d36f0f3384 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -30,6 +30,8 @@ class Wolfvision::Eye14 < PlaceOS::Driver power_query: "\x00\x30\x00", autofocus: "\x01\x31\x01\x01", autofocus_query: "\x00\x31\x00", + zoom: "\x01\x20\x02", + zoom_query: "\x00\x20\x00", iris: "\x01\x22\x02", iris_query: "\x00\x22\x00", } @@ -85,16 +87,16 @@ class Wolfvision::Eye14 < PlaceOS::Driver end # uses only optical zoom - def zoom(position : String = "") - val = in_range(position, @zoom_range.max, @zoom_range.min) - self[:zoom_target] = val - val = sprintf("%04X", val) + def zoom(position : String | Int32 = 0) + val = position if @zoom_range.includes?(position) + @zoom = val + val = "%04X" % val logger.debug { "position in decimal is #{position} and hex is #{val}" } - send_cmd("\x20\x02#{hex_to_byte(val)}", name: :zoom_cmd) + do_send(:zoom, val, name: :zoom) end def zoom? - send_inq("\x20\x00", priority: 0, name: :zoom_inq) + do_send(:zoom_query, val, name: :zoom_query, priority: 0) end # set autofocus to on @@ -206,7 +208,11 @@ class Wolfvision::Eye14 < PlaceOS::Driver protected def do_send(command, param = nil, **options) # prepare the command - cmd = COMMANDS[command] + cmd = if param.nil? + "#{COMMANDS[command]}" + else + "#{COMMANDS[command]}#{param}" + end logger.debug { "queuing #{command}: #{cmd}" } From d471d02bf04c9b53d583fcbded44bfed815f922d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Thu, 25 Feb 2021 14:21:12 +1100 Subject: [PATCH 07/15] feat(eye14):implement recieve , iris , autofocus --- drivers/wolfvision/eye14.cr | 170 ++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 93 deletions(-) diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index d36f0f3384..069d5d96be 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -15,6 +15,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver include PlaceOS::Driver::Interface::Camera include Interface::Powerable include Interface::Muteable + include PlaceOS::Driver::Utilities::Transcoder # include PlaceOS::Driver::Interface::InputSelection(Power) @channel : Channel(String) = Channel(String).new @@ -59,7 +60,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver schedule.every(60.seconds) do logger.debug { "-- Polling Sony Camera" } - if power? && self[:power] == PowerState::On + if power? && self[:power] == true zoom? iris? autofocus? @@ -72,6 +73,10 @@ class Wolfvision::Eye14 < PlaceOS::Driver @channel.close unless @channel.closed? end + #### + # Power controls + # On / Off + # def power(state : Bool) self[:stable_power] = @stable_power = false self[:power_target] = state @@ -86,124 +91,103 @@ class Wolfvision::Eye14 < PlaceOS::Driver end end + #### + # Power query + def power? + do_send(:power_query, priority: 0, name: :power_query) + end + + #### + # Zoom settings # uses only optical zoom + # def zoom(position : String | Int32 = 0) val = position if @zoom_range.includes?(position) - @zoom = val + self[:zoom_target] = val val = "%04X" % val logger.debug { "position in decimal is #{position} and hex is #{val}" } do_send(:zoom, val, name: :zoom) end def zoom? - do_send(:zoom_query, val, name: :zoom_query, priority: 0) + do_send(:zoom_query, priority: 0, name: :zoom_query) end + #### + # Autofocus # set autofocus to on + # curiously there is no off + # def autofocus - send_cmd("\x31\x01\x01", name: :autofocus_cmd) + do_send(:autofocus, name: :autofocus) end def autofocus? - send_inq("\x31\x00", priority: 0, name: :autofocus_inq) + do_send(:autofocus_query, priority: 0, name: :autofocus_query) end - def iris(position : String = "") - val = in_range(position, @iris_range.max, @iris_range.min) + #### + # Iris aperture controls + # + def iris(position : String | Int32 = 0) + val = position if @zoom_range.includes?(position) self[:iris_target] = val - val = sprintf("%04X", val) + val = "%04X" % val logger.debug { "position in decimal is #{position} and hex is #{val}" } - send_cmd("\x22\x02#{hex_to_byte(val)}", name: :iris_cmd) + do_send(:iris, val, name: :iris) end def iris? - send_inq("\x22\x00", priority: 0, name: :iris_inq) - end - - def power? - send_inq("\x30\x00", priority: 0, name: :power_inq) - !!self[:power]?.try(&.as_bool) - end - - def send_cmd(cmd : String = "", **options) - req = "\x01#{cmd}" - logger.debug { "tell -- 0x#{byte_to_hex(req)} -- #{options[:name]}" } - # @channel.send(req, options) - @channel.send(req) - end - - def send_inq(inq : String = "", **options) - req = "\x00#{inq}" - logger.debug { "ask -- 0x#{byte_to_hex(req)} -- #{options[:name]}" } - # @channel.send(req, options) - @channel.send(req) - end - - def received(data : Slice = Slice.empty, command : PlaceOS::Driver::Task = "null") - logger.debug { "Received 0x#{byte_to_hex(data)}\n" } - - bytes = str_to_array(data) - - if command && !command[:name].nil? - case command[:name] - when :power_cmd - self[:power] = self[:power_target] if byte_to_hex(data) == "3000" - when :zoom_cmd - self[:zoom] = self[:zoom_target] if byte_to_hex(data) == "2000" - when :iris_cmd - self[:iris] = self[:iris_target] if byte_to_hex(data) == "2200" - when :autofocus_cmd - self[:autofocus] = true if byte_to_hex(data) == "3100" - when :power_inq - # -1 index for array refers to the last element in Ruby - self[:power] = bytes[-1] == 1 - when :zoom_inq - # for some reason the after changing the zoom position - # the first zoom inquiry sends "2000" regardless of the actaul zoom value - # consecutive zoom inquiries will then return the correct zoom value - - return :ignore if byte_to_hex(data) == "2000" - hex = byte_to_hex(data[-2..-1]) - self[:zoom] = hex.to_i(16) - when :autofocus_inq - self[:autofocus] = bytes[-1] == 1 - when :iris_inq - # same thing as zoom inq happens here - return :ignore if byte_to_hex(data) == "2200" - hex = byte_to_hex(data[-2..-1]) - self[:iris] = hex.to_i(16) - else - return :ignore - end - return :success - end - end - - def check_length(byte_str : String = "") - # response = str_to_array(byte_str) - response = byte_str.to_a - - return false if response.length <= 1 # header is 2 bytes - - len = response[1] + 2 # (data length + header) - - if response.length >= len - return len + do_send(:iris_query, priority: 0, name: :iris_query) + end + + #### + # Called when signal from device is received + # toghther with + # `data` - containing the payload + # `task` - continaing callee task + # + def received(data, task) + data = String.new(data).strip + logger.debug { "Wolfvision eye14 sent sent: #{data}" } + + # we no longer need the connection to be open , the projector expects + # us to close it and a new connection is required per-command + transport.disconnect + + # We can't interpret this message without a task reference + # This also makes sure it is no longer nil + return unless task + + # Process the response + data = data[2..-1] + hex = byte_to_hex(data[-2..-1]) + val = hex.to_i(16) + + case task.name + when :power_on + self[:power] = true if byte_to_hex(data) == "3000" + when :power_off + self[:power] = false if byte_to_hex(data) == "3000" + when :power_query + self[:power] = val.not_nil!.to_i == 1 + when :zoom + self[:zoom] = self[:zoom_target] if byte_to_hex(data) == "2000" + when :zoom_query + self[:zoom] = val.not_nil!.to_i == 1 + when :iris + self[:iris] = self[:iris_target] if byte_to_hex(data) == "2200" + when :iris_query + self[:iris] = val.not_nil!.to_i == 1 + when :autofocus + self[:autofocus] = true if byte_to_hex(data) == "3100" + when :autofocus_query + self[:autofocus] = val.not_nil!.to_i == 1 else - return false + raise Exception.new("could not process task #{task.name} from eye14. \r\nData: #{data}") end - end - def byte_to_hex(data : String = "") - # data.split(//) - data.hexbytes - # output = "" - # data.each_byte { |c| - # s = c.as(String).to_s(16) - # s.prepend('0') if s.length % 2 > 0 - # output << s - # } - # return output + task.success end protected def do_send(command, param = nil, **options) From db28f59899bb5e79b292f491c0365a2aa9825a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Thu, 25 Feb 2021 14:52:13 +1100 Subject: [PATCH 08/15] feat(eye14):interface implementations, stuck on byte_to_hex --- drivers/wolfvision/eye14.cr | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index 069d5d96be..65daeeccd3 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -6,16 +6,18 @@ require "placeos-driver/interface/camera" # require "tokenizer" -module Wolfvision; end +module Wolfvision; + +end # Documentation: https://www.wolfvision.com/wolf/protocol_command_wolfvision/protocol/commands_eye-14.pdf # Ruby version: https://github.com/acaprojects/ruby-engine-drivers/tree/beta/modules/wolfvision class Wolfvision::Eye14 < PlaceOS::Driver + + include PlaceOS::Driver::Interface::Powerable + include PlaceOS::Driver::Utilities::Transcoder include PlaceOS::Driver::Interface::Camera - include Interface::Powerable - include Interface::Muteable - include PlaceOS::Driver::Utilities::Transcoder # include PlaceOS::Driver::Interface::InputSelection(Power) @channel : Channel(String) = Channel(String).new @@ -56,6 +58,20 @@ class Wolfvision::Eye14 < PlaceOS::Driver def on_unload end + #### + # Implement for interfaces else crystal cries + # + def move(position : MoveablePosition, index : Int32 | String = 0) + end + def stop(index : Int32 | String = 0, emergency : Bool = false) + end + def joystick(pan_speed : Int32, tilt_speed : Int32, index : Int32 | String = 0) + end + def recall(position : String, index : Int32 | String = 0) + end + def save_position(name : String, index : Int32 | String = 0) + end + def connected schedule.every(60.seconds) do logger.debug { "-- Polling Sony Camera" } @@ -101,6 +117,11 @@ class Wolfvision::Eye14 < PlaceOS::Driver # Zoom settings # uses only optical zoom # + # implement zoomable interface method + def zoom_to(position : Int32, auto_focus : Bool = true, index : Int32 | String = 0) + zoom(position) + end + # Old interface def zoom(position : String | Int32 = 0) val = position if @zoom_range.includes?(position) self[:zoom_target] = val From ed5e951a95e0855f37099d0bd406a77f88953711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Thu, 25 Feb 2021 15:00:01 +1100 Subject: [PATCH 09/15] delete(again):somehow this file is back --- drivers/wolfvision/eve14_spec.cr | 83 -------------------------------- 1 file changed, 83 deletions(-) delete mode 100644 drivers/wolfvision/eve14_spec.cr diff --git a/drivers/wolfvision/eve14_spec.cr b/drivers/wolfvision/eve14_spec.cr deleted file mode 100644 index 98371a2a99..0000000000 --- a/drivers/wolfvision/eve14_spec.cr +++ /dev/null @@ -1,83 +0,0 @@ -DriverSpecs.mock_driver "Wolfvision::Eye14" do - exec(:power?) - .should_send("\x00\x30\x00") # power query - .responds("\x00\x30\x01\x01") # respond with on - .expect(status[:power]).to be(true) - - wait(150) - - exec(:power, false) - .should_send("\x01\x30\x01\x00") # turn off device - .responds("\x01\x30\x00") # respond with success - .expect(status[:power]).to be(false) - - wait(150) - - exec(:power, true) - .should_send("\x01\x30\x01\x01") # turn off device - .responds("\x01\x30\x00") # respond with success - .expect(status[:power]).to be(true) - - wait(150) - - exec(:power?) - .should_send("\x00\x30\x00") # power query - .responds("\x00\x30\x01\x01") # respond with on - .expect(status[:power]).to be(true) - - wait(150) - - exec(:zoom?) - .should_send("\x00\x20\x00") - .responds("\x00\x20\x02\x00\x09") - .expect(status[:zoom]).to be(9) - - wait(150) - - exec(:zoom, 6) - .should_send("\x01\x20\x02\x00\x06") - .transmit("\x01\x20\x00") - .expect(status[:zoom]).to be(6) - - wait(150) - - exec(:zoom?) - .should_send("\x00\x20\x00") - .responds("\x00\x20\x02\x00\x06") - .expect(status[:zoom]).to be(6) - - wait(150) - - exec(:iris?) - .should_send("\x00\x22\x00") - .responds("\x00\x22\x02\x00\x20") - .expect(status[:iris]).to be(32) - - wait(150) - - exec(:iris, 8) - .should_send("\x01\x22\x02\x00\x08") - .transmit("\x01\x22\x00") - .expect(status[:iris]).to be(8) - - wait(150) - - exec(:iris?) - .should_send("\x00\x22\x00") - .responds("\x00\x22\x02\x00\x08") - .expect(status[:iris]).to be(8) - - wait(150) - - exec(:autofocus?) - .should_send("\x00\x31\x00") - .responds("\x00\x31\x01\x00") - .expect(status[:autofocus]).to be(false) - - wait(150) - - exec(:autofocus) - .should_send("\x01\x31\x01\x01") - .transmit("\x01\x31\x00") # respond with success - .expect(status[:autofocus]).to be(true) -end From 16c2ddaf61549b0b3c6404eab3c7444a4aadf469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Thu, 25 Feb 2021 15:07:05 +1100 Subject: [PATCH 10/15] chore(format):crystal tool format --- drivers/wolfvision/eye14.cr | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index 65daeeccd3..34c709718d 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -6,17 +6,14 @@ require "placeos-driver/interface/camera" # require "tokenizer" -module Wolfvision; - -end +module Wolfvision; end # Documentation: https://www.wolfvision.com/wolf/protocol_command_wolfvision/protocol/commands_eye-14.pdf # Ruby version: https://github.com/acaprojects/ruby-engine-drivers/tree/beta/modules/wolfvision class Wolfvision::Eye14 < PlaceOS::Driver - include PlaceOS::Driver::Interface::Powerable - include PlaceOS::Driver::Utilities::Transcoder + include PlaceOS::Driver::Utilities::Transcoder include PlaceOS::Driver::Interface::Camera # include PlaceOS::Driver::Interface::InputSelection(Power) @@ -63,12 +60,16 @@ class Wolfvision::Eye14 < PlaceOS::Driver # def move(position : MoveablePosition, index : Int32 | String = 0) end + def stop(index : Int32 | String = 0, emergency : Bool = false) end + def joystick(pan_speed : Int32, tilt_speed : Int32, index : Int32 | String = 0) end + def recall(position : String, index : Int32 | String = 0) end + def save_position(name : String, index : Int32 | String = 0) end @@ -121,6 +122,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver def zoom_to(position : Int32, auto_focus : Bool = true, index : Int32 | String = 0) zoom(position) end + # Old interface def zoom(position : String | Int32 = 0) val = position if @zoom_range.includes?(position) From 8d2b828ae78cccde0723144855cbec55a4f86772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Fri, 26 Feb 2021 13:34:32 +1100 Subject: [PATCH 11/15] fix(eye14):passing build/run but can only exec from spec, not send data --- drivers/wolfvision/eye14.cr | 58 +++++++---------- drivers/wolfvision/eye14_spec.cr | 106 +++++++++++++++++-------------- 2 files changed, 81 insertions(+), 83 deletions(-) diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index 34c709718d..78af50cdc3 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -14,12 +14,15 @@ module Wolfvision; end class Wolfvision::Eye14 < PlaceOS::Driver include PlaceOS::Driver::Interface::Powerable include PlaceOS::Driver::Utilities::Transcoder - include PlaceOS::Driver::Interface::Camera + # include PlaceOS::Driver::Interface::Camera # include PlaceOS::Driver::Interface::InputSelection(Power) @channel : Channel(String) = Channel(String).new @stable_power : Bool = true + @zoom_range = 0..3923 + @iris_range = 0..4094 + tcp_port 50915 # Need to go through an RS232 gatway descriptive_name "WolfVision EYE-14" generic_name :Camera @@ -41,10 +44,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver def on_load # transport.tokenizer = Tokenizer.new("\r") - transport.tokenizer = Tokenizer.new(/\x00|\x01|/) - - @zoom_range = 0..3923 - @iris_range = 0..4094 + transport.tokenizer = Tokenizer.new(Bytes[0x00, 0x01]) on_update end @@ -55,27 +55,10 @@ class Wolfvision::Eye14 < PlaceOS::Driver def on_unload end - #### - # Implement for interfaces else crystal cries - # - def move(position : MoveablePosition, index : Int32 | String = 0) - end - - def stop(index : Int32 | String = 0, emergency : Bool = false) - end - - def joystick(pan_speed : Int32, tilt_speed : Int32, index : Int32 | String = 0) - end - - def recall(position : String, index : Int32 | String = 0) - end - - def save_position(name : String, index : Int32 | String = 0) - end - def connected + schedule.clear schedule.every(60.seconds) do - logger.debug { "-- Polling Sony Camera" } + logger.debug { "-- Polling Wolfvision Eye14 Camera" } if power? && self[:power] == true zoom? @@ -118,14 +101,8 @@ class Wolfvision::Eye14 < PlaceOS::Driver # Zoom settings # uses only optical zoom # - # implement zoomable interface method - def zoom_to(position : Int32, auto_focus : Bool = true, index : Int32 | String = 0) - zoom(position) - end - - # Old interface def zoom(position : String | Int32 = 0) - val = position if @zoom_range.includes?(position) + val = position if @zoom_range.includes?(position.to_i32) self[:zoom_target] = val val = "%04X" % val logger.debug { "position in decimal is #{position} and hex is #{val}" } @@ -153,7 +130,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver # Iris aperture controls # def iris(position : String | Int32 = 0) - val = position if @zoom_range.includes?(position) + val = position if @zoom_range.includes?(position.to_i32) self[:iris_target] = val val = "%04X" % val logger.debug { "position in decimal is #{position} and hex is #{val}" } @@ -183,8 +160,8 @@ class Wolfvision::Eye14 < PlaceOS::Driver return unless task # Process the response - data = data[2..-1] - hex = byte_to_hex(data[-2..-1]) + + hex = byte_to_hex(data) val = hex.to_i(16) case task.name @@ -238,4 +215,17 @@ class Wolfvision::Eye14 < PlaceOS::Driver transport.send(cmd) end end + + def byte_to_hex(data : String) + logger.info { data } + output = "" + data.each_byte do |byte| + if !byte.nil? + # s = byte#.to_s(16) + # s.to_s.prepend('0') #if s.length % 2 > 0 + output = output + byte.to_s(16) + end + end + output + end end diff --git a/drivers/wolfvision/eye14_spec.cr b/drivers/wolfvision/eye14_spec.cr index 98371a2a99..e0712d0838 100644 --- a/drivers/wolfvision/eye14_spec.cr +++ b/drivers/wolfvision/eye14_spec.cr @@ -1,83 +1,91 @@ DriverSpecs.mock_driver "Wolfvision::Eye14" do + # exec(:power?) - .should_send("\x00\x30\x00") # power query - .responds("\x00\x30\x01\x01") # respond with on - .expect(status[:power]).to be(true) - wait(150) + # transmit "\x00\x30\x00\r" + # transmit("\x00\x30\x00") + # should_send("\x00\x30\x00") + # .should_send("\x00\x30\x00") # power query + # responds("\x00\x30\x01\x01") # respond with on + # power_status.should be_true + # .expect(status[:power]).to be(true) + # logger.info { power_status } + sleep 150.milliseconds + # status[:power].should be_true exec(:power, false) - .should_send("\x01\x30\x01\x00") # turn off device - .responds("\x01\x30\x00") # respond with success - .expect(status[:power]).to be(false) + # .should_send("\x01\x30\x01\x00") # turn off device + # .responds("\x01\x30\x00") # respond with success + # .expect(status[:power]).to be(false) - wait(150) + sleep 150.milliseconds exec(:power, true) - .should_send("\x01\x30\x01\x01") # turn off device - .responds("\x01\x30\x00") # respond with success - .expect(status[:power]).to be(true) - - wait(150) + # .should_send("\x01\x30\x01\x01") # turn off device + # .responds("\x01\x30\x00") # respond with success + # .expect(status[:power]).to be(true) + sleep 150.milliseconds exec(:power?) - .should_send("\x00\x30\x00") # power query - .responds("\x00\x30\x01\x01") # respond with on - .expect(status[:power]).to be(true) + # .should_send("\x00\x30\x00") # power query + # .responds("\x00\x30\x01\x01") # respond with on + # .expect(status[:power]).to be(true) - wait(150) + sleep 150.milliseconds exec(:zoom?) - .should_send("\x00\x20\x00") - .responds("\x00\x20\x02\x00\x09") - .expect(status[:zoom]).to be(9) - - wait(150) + # .should_send("\x00\x20\x00") + # .responds("\x00\x20\x02\x00\x09") + # .expect(status[:zoom]).to be(9) + sleep 150.milliseconds exec(:zoom, 6) - .should_send("\x01\x20\x02\x00\x06") - .transmit("\x01\x20\x00") - .expect(status[:zoom]).to be(6) + # .should_send("\x01\x20\x02\x00\x06") + # .transmit("\x01\x20\x00") + # .expect(status[:zoom]).to be(6) - wait(150) + sleep 150.milliseconds exec(:zoom?) - .should_send("\x00\x20\x00") - .responds("\x00\x20\x02\x00\x06") - .expect(status[:zoom]).to be(6) + # .should_send("\x00\x20\x00") + # .responds("\x00\x20\x02\x00\x06") + # .expect(status[:zoom]).to be(6) - wait(150) + sleep 150.milliseconds exec(:iris?) - .should_send("\x00\x22\x00") - .responds("\x00\x22\x02\x00\x20") - .expect(status[:iris]).to be(32) + # .should_send("\x00\x22\x00") + # .responds("\x00\x22\x02\x00\x20") + # .expect(status[:iris]).to be(32) - wait(150) + sleep 150.milliseconds exec(:iris, 8) - .should_send("\x01\x22\x02\x00\x08") - .transmit("\x01\x22\x00") - .expect(status[:iris]).to be(8) + # should_send("\x01\x22\x02\x00\x08") + # transmit("\x01\x22\x00") + # expect(status[:iris]).to be(8) + # + + sleep 150.milliseconds - wait(150) + # status[:iris].should eq(8) exec(:iris?) - .should_send("\x00\x22\x00") - .responds("\x00\x22\x02\x00\x08") - .expect(status[:iris]).to be(8) + # .should_send("\x00\x22\x00") + # .responds("\x00\x22\x02\x00\x08") + # .expect(status[:iris]).to be(8) - wait(150) + sleep 150.milliseconds exec(:autofocus?) - .should_send("\x00\x31\x00") - .responds("\x00\x31\x01\x00") - .expect(status[:autofocus]).to be(false) + # .should_send("\x00\x31\x00") + # .responds("\x00\x31\x01\x00") + # .expect(status[:autofocus]).to be(false) - wait(150) + sleep 150.milliseconds exec(:autofocus) - .should_send("\x01\x31\x01\x01") - .transmit("\x01\x31\x00") # respond with success - .expect(status[:autofocus]).to be(true) + # .should_send("\x01\x31\x01\x01") + # .transmit("\x01\x31\x00") # respond with success + # .expect(status[:autofocus]).to be(true) end From 9cc52d2f4e71b2deb51e47e2e2799fd9f6007630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Fri, 26 Feb 2021 17:29:50 +1100 Subject: [PATCH 12/15] feat(eye14):specs working bar some, boo --- drivers/wolfvision/eye14_spec.cr | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/wolfvision/eye14_spec.cr b/drivers/wolfvision/eye14_spec.cr index e0712d0838..b6c8fdcbff 100644 --- a/drivers/wolfvision/eye14_spec.cr +++ b/drivers/wolfvision/eye14_spec.cr @@ -6,36 +6,35 @@ DriverSpecs.mock_driver "Wolfvision::Eye14" do # transmit("\x00\x30\x00") # should_send("\x00\x30\x00") # .should_send("\x00\x30\x00") # power query - # responds("\x00\x30\x01\x01") # respond with on + responds("\x00\x30\x01\x01") # respond with on # power_status.should be_true # .expect(status[:power]).to be(true) # logger.info { power_status } sleep 150.milliseconds # status[:power].should be_true - exec(:power, false) - # .should_send("\x01\x30\x01\x00") # turn off device - # .responds("\x01\x30\x00") # respond with success - # .expect(status[:power]).to be(false) - - sleep 150.milliseconds - exec(:power, true) # .should_send("\x01\x30\x01\x01") # turn off device - # .responds("\x01\x30\x00") # respond with success + responds("\x01\x30\x00") # respond with success # .expect(status[:power]).to be(true) sleep 150.milliseconds + exec(:power, false) + # .should_send("\x01\x30\x01\x00") # turn off device + # responds("\x01\x30\x00") # respond with success + # .expect(status[:power]).to be(false) + + sleep 150.milliseconds exec(:power?) # .should_send("\x00\x30\x00") # power query - # .responds("\x00\x30\x01\x01") # respond with on + responds("\x00\x30\x01\x01") # respond with on # .expect(status[:power]).to be(true) sleep 150.milliseconds exec(:zoom?) # .should_send("\x00\x20\x00") - # .responds("\x00\x20\x02\x00\x09") + responds("\x00\x20\x02\x00\x09") # .expect(status[:zoom]).to be(9) sleep 150.milliseconds @@ -48,14 +47,14 @@ DriverSpecs.mock_driver "Wolfvision::Eye14" do exec(:zoom?) # .should_send("\x00\x20\x00") - # .responds("\x00\x20\x02\x00\x06") + responds("\x00\x20\x02\x00\x06") # .expect(status[:zoom]).to be(6) sleep 150.milliseconds exec(:iris?) # .should_send("\x00\x22\x00") - # .responds("\x00\x22\x02\x00\x20") + responds("\x00\x22\x02\x00\x20") # .expect(status[:iris]).to be(32) sleep 150.milliseconds @@ -71,15 +70,15 @@ DriverSpecs.mock_driver "Wolfvision::Eye14" do # status[:iris].should eq(8) exec(:iris?) - # .should_send("\x00\x22\x00") - # .responds("\x00\x22\x02\x00\x08") + # should_send("\x00\x22\x00") + responds("\x00\x22\x02\x00\x08") # .expect(status[:iris]).to be(8) sleep 150.milliseconds exec(:autofocus?) # .should_send("\x00\x31\x00") - # .responds("\x00\x31\x01\x00") + responds("\x00\x31\x01\x00") # .expect(status[:autofocus]).to be(false) sleep 150.milliseconds From f55e6829ac3ea5b98daba387cc8c2f9468604ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Tue, 2 Mar 2021 13:01:59 +1100 Subject: [PATCH 13/15] feat(eye14):all specs passing --- drivers/wolfvision/eye14.cr | 128 +++++++++++------------ drivers/wolfvision/eye14_spec.cr | 167 +++++++++++++++++-------------- 2 files changed, 148 insertions(+), 147 deletions(-) diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index 78af50cdc3..edd9cb9580 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -28,23 +28,24 @@ class Wolfvision::Eye14 < PlaceOS::Driver generic_name :Camera COMMANDS = { - power_on: "\x01\x30\x01\x01", - power_off: "\x01\x30\x01\x00", - power_query: "\x00\x30\x00", - autofocus: "\x01\x31\x01\x01", - autofocus_query: "\x00\x31\x00", - zoom: "\x01\x20\x02", - zoom_query: "\x00\x20\x00", - iris: "\x01\x22\x02", - iris_query: "\x00\x22\x00", + power_on: "\\x01\\x30\\x01\\x01", + power_off: "\\x01\\x30\\x01\\x00", + power_query: "\\x00\\x30\\x00", + autofocus: "\\x01\\x31\\x01\\x01", + autofocus_query: "\\x00\\x31\\x00", + zoom: "\\x01\\x20\\x02", + zoom_query: "\\x00\\x20\\x00", + iris: "\\x01\\x22\\x02", + iris_query: "\\x00\\x22\\x00", } - RESPONSES = COMMANDS.to_h.invert - # delay between_sends: 150 + RESPONSES = COMMANDS.to_h.invert def on_load - # transport.tokenizer = Tokenizer.new("\r") - transport.tokenizer = Tokenizer.new(Bytes[0x00, 0x01]) + transport.tokenizer = Tokenizer.new("\r") + # transport.connect + # transport.tokenizer = Tokenizer.new(Bytes[0x00, 0x01]) + # transport.tokenizer = Tokenizer.new("\x00\x01") on_update end @@ -58,7 +59,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver def connected schedule.clear schedule.every(60.seconds) do - logger.debug { "-- Polling Wolfvision Eye14 Camera" } + logger.info { "-- Polling Wolfvision Eye14 Camera" } if power? && self[:power] == true zoom? @@ -69,6 +70,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver end def disconnected + # transport.disconnect # Disconnected will be called before connect if initial connect fails @channel.close unless @channel.closed? end @@ -78,16 +80,13 @@ class Wolfvision::Eye14 < PlaceOS::Driver # On / Off # def power(state : Bool) + logger.info { "requested to power - #{state}" } self[:stable_power] = @stable_power = false self[:power_target] = state - if state - logger.debug { "requested to power on" } - do_send(:power_on, retries: 10, name: :power_on, delay: 8.seconds) + do_send(:power_on, retries: 10, name: :power_on, delay: 2.seconds) else - logger.debug { "requested to power off" } - do_send(:power_off, retries: 10, name: :power_off, delay: 8.seconds) # .get - + do_send(:power_off, retries: 10, name: :power_off, delay: 2.seconds).get end end @@ -104,8 +103,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver def zoom(position : String | Int32 = 0) val = position if @zoom_range.includes?(position.to_i32) self[:zoom_target] = val - val = "%04X" % val - logger.debug { "position in decimal is #{position} and hex is #{val}" } + val = "%02X" % val do_send(:zoom, val, name: :zoom) end @@ -132,8 +130,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver def iris(position : String | Int32 = 0) val = position if @zoom_range.includes?(position.to_i32) self[:iris_target] = val - val = "%04X" % val - logger.debug { "position in decimal is #{position} and hex is #{val}" } + val = "%02X" % val do_send(:iris, val, name: :iris) end @@ -148,12 +145,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver # `task` - continaing callee task # def received(data, task) - data = String.new(data).strip - logger.debug { "Wolfvision eye14 sent sent: #{data}" } - - # we no longer need the connection to be open , the projector expects - # us to close it and a new connection is required per-command - transport.disconnect + logger.info { "Wolfvision eye14 sent: #{data} and Task name is #{task.try &.name}" } # We can't interpret this message without a task reference # This also makes sure it is no longer nil @@ -161,44 +153,53 @@ class Wolfvision::Eye14 < PlaceOS::Driver # Process the response - hex = byte_to_hex(data) - val = hex.to_i(16) + hex_int = data.hexstring.chars[0..9] + + # array holding the hex string pairs + hex_arr = [] of String + hex_int.each_with_index do |v, k| + hex_arr << "#{hex_int[k - 1]}#{hex_int[k]}" if k % 2 == 1 + end case task.name - when :power_on - self[:power] = true if byte_to_hex(data) == "3000" - when :power_off - self[:power] = false if byte_to_hex(data) == "3000" - when :power_query - self[:power] = val.not_nil!.to_i == 1 - when :zoom - self[:zoom] = self[:zoom_target] if byte_to_hex(data) == "2000" - when :zoom_query - self[:zoom] = val.not_nil!.to_i == 1 - when :iris - self[:iris] = self[:iris_target] if byte_to_hex(data) == "2200" - when :iris_query - self[:iris] = val.not_nil!.to_i == 1 - when :autofocus - self[:autofocus] = true if byte_to_hex(data) == "3100" - when :autofocus_query - self[:autofocus] = val.not_nil!.to_i == 1 + when "power_on" + self[:power] = true if hex_arr[1] == "30" + self[:stable_power] = @stable_power = true + when "power_off" + self[:power] = false if hex_arr[1] == "30" + self[:stable_power] = @stable_power = true + when "power_query" + self[:power] = (hex_arr[3].to_i == 1) ? true : false + when "zoom" + self[:zoom] = self[:zoom_target] if hex_arr[1] == "20" + when "zoom_query" + self[:zoom] = hex_arr[4].to_i(16) if hex_arr[1] == "20" + when "iris" + self[:iris] = self[:iris_target] if hex_arr[1] == "22" + when "iris_query" + self[:iris] = hex_arr[4].to_i(16) if hex_arr[1] == "22" + when "autofocus" + self[:autofocus] = true if hex_arr[1] == "31" + when "autofocus_query" + self[:autofocus] = (hex_arr[2].to_i == 1) ? true : false else - raise Exception.new("could not process task #{task.name} from eye14. \r\nData: #{data}") + raise Exception.new(" Could not process task #{task.name} from eye14. \r\nData: #{data}") end - task.success + # transport.disconnect + return task.try &.success end protected def do_send(command, param = nil, **options) # prepare the command + cmd = if param.nil? "#{COMMANDS[command]}" else - "#{COMMANDS[command]}#{param}" + "#{COMMANDS[command]}\\x#{param}" end - logger.debug { "queuing #{command}: #{cmd}" } + logger.info { " Queing: #{cmd}" } # queue the request queue(**({ @@ -206,26 +207,9 @@ class Wolfvision::Eye14 < PlaceOS::Driver }.merge(options))) do # prepare channel and connect to the projector (which will then send the random key) @channel = Channel(String).new - transport.connect - # wait for the random key to arrive - random_key = @channel.receive # send the request - # NOTE:: the built in `send` function has implicit queuing, but we are - # in a task callback here so should be calling transport send directly + logger.info { " Sending: #{cmd}" } transport.send(cmd) end end - - def byte_to_hex(data : String) - logger.info { data } - output = "" - data.each_byte do |byte| - if !byte.nil? - # s = byte#.to_s(16) - # s.to_s.prepend('0') #if s.length % 2 > 0 - output = output + byte.to_s(16) - end - end - output - end end diff --git a/drivers/wolfvision/eye14_spec.cr b/drivers/wolfvision/eye14_spec.cr index b6c8fdcbff..bfb64cbd5a 100644 --- a/drivers/wolfvision/eye14_spec.cr +++ b/drivers/wolfvision/eye14_spec.cr @@ -1,90 +1,107 @@ DriverSpecs.mock_driver "Wolfvision::Eye14" do + #### + # POWER # exec(:power?) - - # transmit "\x00\x30\x00\r" - # transmit("\x00\x30\x00") - # should_send("\x00\x30\x00") - # .should_send("\x00\x30\x00") # power query - responds("\x00\x30\x01\x01") # respond with on - # power_status.should be_true - # .expect(status[:power]).to be(true) - # logger.info { power_status } - sleep 150.milliseconds - # status[:power].should be_true - + sleep 1.second + should_send("\\x00\\x30\\x00") # power query + responds("\x00\x30\x01\x00\r") # respond with off + sleep 1.second + status[:power].should eq(false) + # exec(:power, true) - # .should_send("\x01\x30\x01\x01") # turn off device - responds("\x01\x30\x00") # respond with success - # .expect(status[:power]).to be(true) - sleep 150.milliseconds - - exec(:power, false) - # .should_send("\x01\x30\x01\x00") # turn off device - # responds("\x01\x30\x00") # respond with success - # .expect(status[:power]).to be(false) - - sleep 150.milliseconds + sleep 1.second + should_send("\\x01\\x30\\x01\\x01") # turn on device + responds("\x01\x30\x01\x01\r") # respond with success + sleep 1.second + status[:power].should eq(true) + # exec(:power?) - # .should_send("\x00\x30\x00") # power query - responds("\x00\x30\x01\x01") # respond with on - # .expect(status[:power]).to be(true) - - sleep 150.milliseconds - + sleep 2.seconds + should_send("\\x00\\x30\\x00") # power query + sleep 2.seconds + responds("\x00\x30\x01\x00\r") # respond with on + sleep 2.seconds + status[:power].should eq(false) + # + exec(:power, false) + sleep 2.seconds + should_send("\\x01\\x30\\x01\\x00") # turn off device + sleep 2.seconds + responds("\x01\x30\x01\x00\r") # respond with success + sleep 2.seconds + status[:power].should eq(false) + + #### + # ZOOM + # exec(:zoom?) - # .should_send("\x00\x20\x00") - responds("\x00\x20\x02\x00\x09") - # .expect(status[:zoom]).to be(9) - sleep 150.milliseconds - + sleep 2.seconds + should_send("\\x00\\x20\\x00") + sleep 2.seconds + responds("\x00\x20\x02\x00\x09\r") # originally zoom is 9 + sleep 2.seconds + status[:zoom].should eq(9) + # exec(:zoom, 6) - # .should_send("\x01\x20\x02\x00\x06") - # .transmit("\x01\x20\x00") - # .expect(status[:zoom]).to be(6) - - sleep 150.milliseconds - + sleep 2.seconds + should_send("\\x01\\x20\\x02\\x06") # set zoom to 6 + sleep 2.seconds + responds("\x00\x20\x02\x00\x06\r") + sleep 2.seconds + status[:zoom].should eq(6) + # exec(:zoom?) - # .should_send("\x00\x20\x00") - responds("\x00\x20\x02\x00\x06") - # .expect(status[:zoom]).to be(6) - - sleep 150.milliseconds - + sleep 2.seconds + should_send("\\x00\\x20\\x00") + sleep 2.seconds + responds("\x00\x20\x02\x00\x06\r") + sleep 2.seconds + status[:zoom].should eq(6) + + #### + # IRIS + # exec(:iris?) - # .should_send("\x00\x22\x00") - responds("\x00\x22\x02\x00\x20") - # .expect(status[:iris]).to be(32) - - sleep 150.milliseconds - + sleep 2.seconds + should_send("\\x00\\x22\\x00") + sleep 2.seconds + responds("\x00\x22\x02\x00\x20\r") # originally zoom is 20 hex 32 int + sleep 2.seconds + status[:iris].should eq(32) + # exec(:iris, 8) - # should_send("\x01\x22\x02\x00\x08") - # transmit("\x01\x22\x00") - # expect(status[:iris]).to be(8) + sleep 2.seconds + should_send("\\x01\\x22\\x02\\x08") # set zoom to 6 + sleep 2.seconds + responds("\x00\x22\x02\x00\x08\r") + sleep 2.seconds + status[:iris].should eq(8) # - - sleep 150.milliseconds - - # status[:iris].should eq(8) - exec(:iris?) - # should_send("\x00\x22\x00") - responds("\x00\x22\x02\x00\x08") - # .expect(status[:iris]).to be(8) - - sleep 150.milliseconds - + sleep 2.seconds + should_send("\\x00\\x22\\x00") + sleep 2.seconds + responds("\x00\x22\x02\x00\x08\r") + sleep 2.seconds + status[:iris].should eq(8) + + #### + # AUTOFOCUS + # exec(:autofocus?) - # .should_send("\x00\x31\x00") - responds("\x00\x31\x01\x00") - # .expect(status[:autofocus]).to be(false) - - sleep 150.milliseconds - + sleep 2.seconds + should_send("\\x00\\x31\\x00") + sleep 2.seconds + responds("\x00\x31\x00\r") + sleep 2.seconds + status[:autofocus].should eq(false) + # exec(:autofocus) - # .should_send("\x01\x31\x01\x01") - # .transmit("\x01\x31\x00") # respond with success - # .expect(status[:autofocus]).to be(true) + sleep 2.seconds + should_send("\\x01\\x31\\x01\\x01") + sleep 2.seconds + responds("\x01\x31\x01\x01\r") + sleep 2.seconds + status[:autofocus].should eq(true) end From 317a1899158be50f7b6d538e8394f631fa5f7753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Tue, 2 Mar 2021 13:18:51 +1100 Subject: [PATCH 14/15] fix(workflow):handle more than 50 annotations --- .github/workflows/crystal.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crystal.yml b/.github/workflows/crystal.yml index 597fcda80a..c40fc3da48 100644 --- a/.github/workflows/crystal.yml +++ b/.github/workflows/crystal.yml @@ -16,6 +16,6 @@ jobs: - name: Format run: crystal tool format - name: Lint - uses: crystal-ameba/github-action@v0.2.6 + uses: crystal-ameba/github-action@v0.2.8 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From c84868e0961f2cbd09511a21d4f9a09cda22429f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Po=C5=82o=C5=84ski?= Date: Wed, 14 Apr 2021 10:36:20 +1000 Subject: [PATCH 15/15] fix(eye14):use binary string IO commands instead of string --- drivers/wolfvision/eye14.cr | 33 ++++++++---------- drivers/wolfvision/eye14_spec.cr | 59 ++++++++++---------------------- 2 files changed, 34 insertions(+), 58 deletions(-) diff --git a/drivers/wolfvision/eye14.cr b/drivers/wolfvision/eye14.cr index edd9cb9580..47108527bd 100644 --- a/drivers/wolfvision/eye14.cr +++ b/drivers/wolfvision/eye14.cr @@ -28,25 +28,21 @@ class Wolfvision::Eye14 < PlaceOS::Driver generic_name :Camera COMMANDS = { - power_on: "\\x01\\x30\\x01\\x01", - power_off: "\\x01\\x30\\x01\\x00", - power_query: "\\x00\\x30\\x00", - autofocus: "\\x01\\x31\\x01\\x01", - autofocus_query: "\\x00\\x31\\x00", - zoom: "\\x01\\x20\\x02", - zoom_query: "\\x00\\x20\\x00", - iris: "\\x01\\x22\\x02", - iris_query: "\\x00\\x22\\x00", + power_on: "\x01\x30\x01\x01", + power_off: "\x01\x30\x01\x00", + power_query: "\x00\x30\x00", + autofocus: "\x01\x31\x01\x01", + autofocus_query: "\x00\x31\x00", + zoom: "\x01\x20\x02", + zoom_query: "\x00\x20\x00", + iris: "\x01\x22\x02", + iris_query: "\x00\x22\x00", } RESPONSES = COMMANDS.to_h.invert def on_load transport.tokenizer = Tokenizer.new("\r") - # transport.connect - # transport.tokenizer = Tokenizer.new(Bytes[0x00, 0x01]) - # transport.tokenizer = Tokenizer.new("\x00\x01") - on_update end @@ -103,7 +99,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver def zoom(position : String | Int32 = 0) val = position if @zoom_range.includes?(position.to_i32) self[:zoom_target] = val - val = "%02X" % val + val = val.to_i.chr if !val.nil? do_send(:zoom, val, name: :zoom) end @@ -117,7 +113,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver # curiously there is no off # def autofocus - do_send(:autofocus, name: :autofocus) + do_send(:autofocus, priority: 0, name: :autofocus) end def autofocus? @@ -130,7 +126,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver def iris(position : String | Int32 = 0) val = position if @zoom_range.includes?(position.to_i32) self[:iris_target] = val - val = "%02X" % val + val = val.to_i.chr if !val.nil? do_send(:iris, val, name: :iris) end @@ -145,7 +141,7 @@ class Wolfvision::Eye14 < PlaceOS::Driver # `task` - continaing callee task # def received(data, task) - logger.info { "Wolfvision eye14 sent: #{data} and Task name is #{task.try &.name}" } + logger.info { "Wolfvision eye14 sent reply: #{data} and Task name is #{task.try &.name}" } # We can't interpret this message without a task reference # This also makes sure it is no longer nil @@ -192,11 +188,12 @@ class Wolfvision::Eye14 < PlaceOS::Driver protected def do_send(command, param = nil, **options) # prepare the command + # puts param cmd = if param.nil? "#{COMMANDS[command]}" else - "#{COMMANDS[command]}\\x#{param}" + "#{COMMANDS[command]}#{param}" end logger.info { " Queing: #{cmd}" } diff --git a/drivers/wolfvision/eye14_spec.cr b/drivers/wolfvision/eye14_spec.cr index bfb64cbd5a..a8dba3ec3a 100644 --- a/drivers/wolfvision/eye14_spec.cr +++ b/drivers/wolfvision/eye14_spec.cr @@ -3,33 +3,27 @@ DriverSpecs.mock_driver "Wolfvision::Eye14" do # POWER # exec(:power?) - sleep 1.second - should_send("\\x00\\x30\\x00") # power query + sleep 2.seconds + should_send("\x00\x30\x00") # power query responds("\x00\x30\x01\x00\r") # respond with off - sleep 1.second status[:power].should eq(false) # exec(:power, true) - sleep 1.second - should_send("\\x01\\x30\\x01\\x01") # turn on device - responds("\x01\x30\x01\x01\r") # respond with success - sleep 1.second + sleep 2.seconds + should_send("\x01\x30\x01\x01") # turn on device + responds("\x01\x30\x01\x01\r") # respond with success status[:power].should eq(true) # exec(:power?) sleep 2.seconds - should_send("\\x00\\x30\\x00") # power query - sleep 2.seconds - responds("\x00\x30\x01\x00\r") # respond with on - sleep 2.seconds - status[:power].should eq(false) + should_send("\x00\x30\x00") # power query + responds("\x00\x30\x01\x01\r") # respond with on + status[:power].should eq(true) # exec(:power, false) sleep 2.seconds - should_send("\\x01\\x30\\x01\\x00") # turn off device - sleep 2.seconds - responds("\x01\x30\x01\x00\r") # respond with success - sleep 2.seconds + should_send("\x01\x30\x01\x00") # turn off device + responds("\x01\x30\x01\x00\r") # respond with success status[:power].should eq(false) #### @@ -37,26 +31,20 @@ DriverSpecs.mock_driver "Wolfvision::Eye14" do # exec(:zoom?) sleep 2.seconds - should_send("\\x00\\x20\\x00") - sleep 2.seconds + should_send("\x00\x20\x00") responds("\x00\x20\x02\x00\x09\r") # originally zoom is 9 - sleep 2.seconds status[:zoom].should eq(9) # exec(:zoom, 6) sleep 2.seconds - should_send("\\x01\\x20\\x02\\x06") # set zoom to 6 - sleep 2.seconds + should_send("\x01\x20\x02\x06") # set zoom to 6 responds("\x00\x20\x02\x00\x06\r") - sleep 2.seconds status[:zoom].should eq(6) # exec(:zoom?) sleep 2.seconds - should_send("\\x00\\x20\\x00") - sleep 2.seconds + should_send("\x00\x20\x00") responds("\x00\x20\x02\x00\x06\r") - sleep 2.seconds status[:zoom].should eq(6) #### @@ -64,26 +52,20 @@ DriverSpecs.mock_driver "Wolfvision::Eye14" do # exec(:iris?) sleep 2.seconds - should_send("\\x00\\x22\\x00") - sleep 2.seconds + should_send("\x00\x22\x00") responds("\x00\x22\x02\x00\x20\r") # originally zoom is 20 hex 32 int - sleep 2.seconds status[:iris].should eq(32) # exec(:iris, 8) sleep 2.seconds - should_send("\\x01\\x22\\x02\\x08") # set zoom to 6 - sleep 2.seconds + should_send("\x01\x22\x02\x08") # set iris to 8 responds("\x00\x22\x02\x00\x08\r") - sleep 2.seconds status[:iris].should eq(8) # exec(:iris?) sleep 2.seconds - should_send("\\x00\\x22\\x00") - sleep 2.seconds + should_send("\x00\x22\x00") responds("\x00\x22\x02\x00\x08\r") - sleep 2.seconds status[:iris].should eq(8) #### @@ -91,17 +73,14 @@ DriverSpecs.mock_driver "Wolfvision::Eye14" do # exec(:autofocus?) sleep 2.seconds - should_send("\\x00\\x31\\x00") - sleep 2.seconds + should_send("\x00\x31\x00") responds("\x00\x31\x00\r") - sleep 2.seconds status[:autofocus].should eq(false) # exec(:autofocus) sleep 2.seconds - should_send("\\x01\\x31\\x01\\x01") - sleep 2.seconds + should_send("\x01\x31\x01\x01") responds("\x01\x31\x01\x01\r") - sleep 2.seconds status[:autofocus].should eq(true) + # end