Skip to content

Commit

Permalink
Add support for 5-nibble pan/tilt position commands (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
vwout committed Jul 11, 2024
1 parent 702f80d commit 3be8d5a
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 28 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Besides recalling a pre-made preset, this plugin supports a few more control ope

This plugin requires the camera to support Visca over IP via UDP.
It follows the specification as designed by Sony and also supports the PTZOptics variant of Visca.
This plugin is confirmed to work with at Avonic, BZB Gear, Everet, GlowStream, JVC, PTZOptics and Zowietek cameras.
This plugin is confirmed to work with at Avonic, Canon, BZB Gear, Everet, GlowStream, JVC, PTZOptics and Zowietek cameras.
Others may work as well.

Also visit https://obsproject.com/forum/resources/control-visca-over-ip-based-cameras.1173/ for more information.
Expand Down
92 changes: 65 additions & 27 deletions libvisca.lua
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ Visca.compatibility = {
-- When the first preset is 1, leave it nil (or set to 0).
-- When the first preset is 0, set the offset to 1.
-- The preset recalled at the camera is 'preset - <preset_nr_offset>'
pantilt_pan_bytes = 4 -- The number of bytes used for the pan argument in absolute pan/tilt commands
}


Expand Down Expand Up @@ -431,16 +432,32 @@ function Visca.PayloadReply:get_inquiry_data_for(inquiry_payload)
end
elseif category == Visca.categories.pan_tilter then
if inquiry_command == Visca.inquiry_commands.pantilt_position then
data = {
pan = bit.lshift(bit.band(self.arguments[1] or 0, 0x0F), 12) +
bit.lshift(bit.band(self.arguments[2] or 0, 0x0F), 8) +
bit.lshift(bit.band(self.arguments[3] or 0, 0x0F), 4) +
bit.band(self.arguments[4] or 0, 0x0F),
tilt = bit.lshift(bit.band(self.arguments[5] or 0, 0x0F), 12) +
bit.lshift(bit.band(self.arguments[6] or 0, 0x0F), 8) +
bit.lshift(bit.band(self.arguments[7] or 0, 0x0F), 4) +
bit.band(self.arguments[8] or 0, 0x0F)
}
if self.argument_cnt == 8 then
data = {
pantilt_pan_bytes = 4,
pan = bit.lshift(bit.band(self.arguments[1] or 0, 0x0F), 12) +
bit.lshift(bit.band(self.arguments[2] or 0, 0x0F), 8) +
bit.lshift(bit.band(self.arguments[3] or 0, 0x0F), 4) +
bit.band(self.arguments[4] or 0, 0x0F),
tilt = bit.lshift(bit.band(self.arguments[5] or 0, 0x0F), 12) +
bit.lshift(bit.band(self.arguments[6] or 0, 0x0F), 8) +
bit.lshift(bit.band(self.arguments[7] or 0, 0x0F), 4) +
bit.band(self.arguments[8] or 0, 0x0F)
}
elseif self.argument_cnt == 9 then
data = {
pantilt_pan_bytes = 5,
pan = bit.lshift(bit.band(self.arguments[1] or 0, 0x0F), 16) +
bit.lshift(bit.band(self.arguments[2] or 0, 0x0F), 12) +
bit.lshift(bit.band(self.arguments[3] or 0, 0x0F), 8) +
bit.lshift(bit.band(self.arguments[4] or 0, 0x0F), 4) +
bit.band(self.arguments[5] or 0, 0x0F),
tilt = bit.lshift(bit.band(self.arguments[6] or 0, 0x0F), 12) +
bit.lshift(bit.band(self.arguments[7] or 0, 0x0F), 8) +
bit.lshift(bit.band(self.arguments[8] or 0, 0x0F), 4) +
bit.band(self.arguments[9] or 0, 0x0F)
}
end
end
end

Expand Down Expand Up @@ -1347,23 +1364,44 @@ function Visca.Connection:Cam_PanTilt_Absolute(speed, pan, tilt)

local msg = Visca.Message.new()
msg.payload_type = Visca.payload_types.visca_command
msg.payload = {
Visca.packet_consts.req_addr_base + bit.band(Visca.default_camera_nr or 1, 0x0F),
Visca.packet_consts.command,
Visca.categories.pan_tilter,
Visca.commands.pantilt_absolute,
speed, -- Pan speed
speed, -- Tilt speed
bit.band(bit.rshift(pan, 12), 0x0F),
bit.band(bit.rshift(pan, 8), 0x0F),
bit.band(bit.rshift(pan, 4), 0x0F),
bit.band(pan, 0x0F),
bit.band(bit.rshift(tilt, 12), 0x0F),
bit.band(bit.rshift(tilt, 8), 0x0F),
bit.band(bit.rshift(tilt, 4), 0x0F),
bit.band(tilt, 0x0F),
Visca.packet_consts.terminator
}
if not self.compatibility.pantilt_pan_bytes or self.compatibility.pantilt_pan_bytes == 4 then
msg.payload = {
Visca.packet_consts.req_addr_base + bit.band(Visca.default_camera_nr or 1, 0x0F),
Visca.packet_consts.command,
Visca.categories.pan_tilter,
Visca.commands.pantilt_absolute,
speed, -- Pan speed
speed, -- Tilt speed
bit.band(bit.rshift(pan, 12), 0x0F),
bit.band(bit.rshift(pan, 8), 0x0F),
bit.band(bit.rshift(pan, 4), 0x0F),
bit.band(pan, 0x0F),
bit.band(bit.rshift(tilt, 12), 0x0F),
bit.band(bit.rshift(tilt, 8), 0x0F),
bit.band(bit.rshift(tilt, 4), 0x0F),
bit.band(tilt, 0x0F),
Visca.packet_consts.terminator
}
elseif self.compatibility.pantilt_pan_bytes == 5 then
msg.payload = {
Visca.packet_consts.req_addr_base + bit.band(Visca.default_camera_nr or 1, 0x0F),
Visca.packet_consts.command,
Visca.categories.pan_tilter,
Visca.commands.pantilt_absolute,
speed, -- Pan/Tilt speed
00, -- Fixed
bit.band(bit.rshift(pan, 16), 0x0F),
bit.band(bit.rshift(pan, 12), 0x0F),
bit.band(bit.rshift(pan, 8), 0x0F),
bit.band(bit.rshift(pan, 4), 0x0F),
bit.band(pan, 0x0F),
bit.band(bit.rshift(tilt, 12), 0x0F),
bit.band(bit.rshift(tilt, 8), 0x0F),
bit.band(bit.rshift(tilt, 4), 0x0F),
bit.band(tilt, 0x0F),
Visca.packet_consts.terminator
}
end

return self:send(msg)
end
Expand Down
4 changes: 4 additions & 0 deletions obs-visca-control.lua
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,10 @@ local function open_visca_connection(camera_id)
table.insert(ptz_vals, "Zoom: n/a (-)")
end

if reply_data.pantilt_pan_bytes then
connection:set_compatibility({pantilt_pan_bytes = reply_data.pantilt_pan_bytes})
end

for scene_name, source_name, source_settings, _ in
get_plugin_settings_from_scene(plugin_scene_type.Preview, camera_id) do
if source_settings then
Expand Down
29 changes: 29 additions & 0 deletions test/libvisca_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,17 @@ function test_pantilt()
lunit.assert_equal(23, t_size)
lunit.assert_equal(Visca.limits.PAN_MIN_SPEED, string.byte(t_data, 13))
lunit.assert_equal(Visca.limits.PAN_MIN_SPEED, string.byte(t_data, 14))
lunit.assert_equal(0x0F, string.byte(t_data, 15))
lunit.assert_equal(0x0C, string.byte(t_data, 16))

clear_transmission_queue(connection)
connection:set_compatibility({pantilt_pan_bytes = 5})
t_size, t_data = connection:Cam_PanTilt_Absolute(0, 0xABCDE, 0x1234)
lunit.assert_equal(24, t_size)
lunit.assert_equal(Visca.limits.PAN_MIN_SPEED, string.byte(t_data, 13))
lunit.assert_equal(0, string.byte(t_data, 14))
lunit.assert_equal(0x0A, string.byte(t_data, 15))
lunit.assert_equal(0x04, string.byte(t_data, 23))
end

function test_zoom()
Expand Down Expand Up @@ -335,6 +346,24 @@ function test_reply_parsing_inquiry_brightnes()
lunit.assert_equal(0x69, msg_inq_brightness_data.brightness)
end

function test_reply_parsing_inquiry_pt_position()
local msg_inq_pt4_position = Visca.Message.new():from_data("\x90\x50\x0A\x0B\x0C\x0D\x01\x02\x03\x04\xFF"):dump("msg_inq_pt4_position")
lunit.assert_not_nil(msg_inq_pt4_position.message.reply)
local msg_inq_pt4_position_data = msg_inq_pt4_position.message.reply:get_inquiry_data_for({0,0,Visca.categories.pan_tilter,Visca.inquiry_commands.pantilt_position})
lunit.assert_not_nil(msg_inq_pt4_position_data)
lunit.assert_equal(4, msg_inq_pt4_position_data.pantilt_pan_bytes)
lunit.assert_equal(0xABCD, msg_inq_pt4_position_data.pan)
lunit.assert_equal(0x1234, msg_inq_pt4_position_data.tilt)

local msg_inq_pt5_position = Visca.Message.new():from_data("\x90\x50\x01\x02\x03\x04\x05\x0A\x0B\x0C\x0D\xFF"):dump("msg_inq_pt5_position")
lunit.assert_not_nil(msg_inq_pt5_position.message.reply)
local msg_inq_pt5_position_data = msg_inq_pt5_position.message.reply:get_inquiry_data_for({0,0,Visca.categories.pan_tilter,Visca.inquiry_commands.pantilt_position})
lunit.assert_not_nil(msg_inq_pt5_position_data)
lunit.assert_equal(5, msg_inq_pt5_position_data.pantilt_pan_bytes)
lunit.assert_equal(0x12345, msg_inq_pt5_position_data.pan)
lunit.assert_equal(0xABCD, msg_inq_pt5_position_data.tilt)
end

function test_inquiry()
lunit.assert_true(connection:set_mode(Visca.modes.generic))

Expand Down

0 comments on commit 3be8d5a

Please sign in to comment.