Skip to content

Instantly share code, notes, and snippets.

@cmsj
Last active December 23, 2017 23:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cmsj/89548c9ad9c9ef38d021fd2a1e697cd7 to your computer and use it in GitHub Desktop.
Save cmsj/89548c9ad9c9ef38d021fd2a1e697cd7 to your computer and use it in GitHub Desktop.
hs.console.clearConsole()
local hubMessage = {
["INITIATE_COMMS"] = 0x01,
["PARAMETER_CHANGE"] = 0x02,
["PARAMETER_RESET"] = 0x03,
["PARAMETER_VALUE_REQUEST"] = 0x04,
["MENU_CHANGE"] = 0x05,
["MENU_RESET"] = 0x06,
["MENU_STRING_REQUEST"] = 0x07,
["ACTION_ON"] = 0x08,
["MODE_CHANGE"] = 0x09,
["TRANSPORT"] = 0x0A,
["ACTION_OFF"] = 0x0B,
["UNMANAGED_PANEL_CAPABILITIES"] = 0x30,
["UNMANAGED_BUTTON_DOWN"] = 0x31,
["UNMANAGED_BUTTON_UP"] = 0x32,
["UNMANAGED_ENCODER_CHANGE"] = 0x33,
["UNMANAGED_DISPLAY_REFRESH"] = 0x34,
["PANEL_CONNECTION_STATE"] = 0x35,
}
local appMessage = {
["APPLICATION_DEFINITION"] = 0x81,
["PARAMETER_VALUE"] = 0x82,
["MENU_STRING"] = 0x83,
["ALL_CHANGE"] = 0x84,
["MODE_VALUE"] = 0x85,
["DISPLAY_TEXT"] = 0x86,
["UNMANAGED_PANEL_CAPABILITIES_REQUEST"] = 0xA0,
["UNMANAGED_DISPLAY_WRITE"] = 0xA1,
["RENAME_CONTROL"] = 0xA2,
["HIGHLIGHT_CONTROL"] = 0xA3,
["INDICATE_CONTROL"] = 0xA4,
["REQUEST_PANEL_CONNECTION_STATES"] = 0xA5,
}
local panelType = {
["CP200-BK"] = 0x03,
["CP200-K"] = 0x04,
["CP200-TS"] = 0x05,
["CP200-S"] = 0x09,
["Wave"] = 0x0A,
["Element-Tk"] = 0x0C,
["Element-Mf"] = 0x0D,
["Element-Kb"] = 0x0E,
["Element-Bt"] = 0x0F,
["Ripple"] = 0x11,
}
local logger = require("hs.logger")
logger.defaultLogLevel = 'debug'
local log = logger.new("tangent")
local socket = require("hs.socket")
local utf8 = require("hs.utf8")
messageBuffer = {}
messageLength = 0
messageCount = 0
readBytesRemaining = 0
function getPanelType(id)
for i,v in pairs(panelType) do
if id == v then
return i
end
end
end
function byteStringToNumber(str, offset, num_bytes)
assert(num_bytes >= 1 and num_bytes <= 4)
local x = 0
for i = 1, num_bytes do
x = x * 0x0100
x = x + math.fmod(string.byte(str, i + offset - 1) or 0, 0x0100)
end
return x
end
function numberToByteString(n)
local t = {}
local char = string.char
t[1] = char(n >> 24 & 0xFF)
t[2] = char(n >> 16 & 0xFF)
t[3] = char(n >> 08 & 0xFF)
t[4] = char(n >> 00 & 0xFF)
return table.concat(t)
end
function buildMessage(msgType, msgParts)
local byteString = numberToByteString(msgType)
for _,partValue in pairs(msgParts) do
byteString = byteString .. numberToByteString(#partValue)
byteString = byteString .. partValue
end
log.df("buildMessage constructed: "..utf8.hexDump(byteString))
return byteString
end
function processHubCommand(data)
local id = byteStringToNumber(data, 1, 4)
if id == hubMessage["INITIATE_COMMS"] then
-- 0x01, <protocolRev>, <numPanels>, (<panelType>, <panelID>)...
log.df("InitiateComms (0x01) Triggered:")
local protocolRev = byteStringToNumber(data, 5, 4)
local numberOfPanels = byteStringToNumber(data, 9, 4)
log.df(" protocolRev: %s", protocolRev)
log.df(" numberOfPanels: %s", numberOfPanels)
local startNumber = 13
for i=1, numberOfPanels do
local currentPanelType = byteStringToNumber(data, startNumber, 4)
startNumber = startNumber + 4
local currentPanelID = byteStringToNumber(data, startNumber, 4)
startNumber = startNumber + 4
log.df(" panelType: %s panelID: %s", getPanelType(currentPanelType), currentPanelID)
end
-- Respond with ApplicationDefinition (0x81):
log.df("Responding with ApplicationDefinition (0x81)")
local byteString = buildMessage(appMessage["APPLICATION_DEFINITION"], {"CommandPost", "/Users/cmsj", ""})
tangentSocket:send(byteStringToNumber(#byteString)..byteString)
else
log.df("Unknown Reply: %s", hs.inspect(data))
end
end
log.df("CONNECTING TO TANGENT HUB...")
tangentSocket = socket.new()
:setCallback(function(data, tag)
local hexDump = utf8.hexDump(data)
log.df("Received data: "..hexDump)
if readBytesRemaining == 0 then
-- Each message starts with an integer value indicating the number of bytes to follow
-- We don't have any bytes left to read of a previous message, so this must be the first 4 bytes
readBytesRemaining = byteStringToNumber(data, 1, 4)
log.df("New command received from hub, of length: "..readBytesRemaining)
hs.timer.doAfter(0.5, function() tangentSocket:read(readBytesRemaining) end)
else
-- We've read the rest of a command
readBytesRemaining = 0
processHubCommand(data)
-- Get set up for the next command
hs.timer.doAfter(0.5, function() tangentSocket:read(4) end)
end
end)
:connect("127.0.0.1", 64246, function()
log.df("CONNECTION TO TANGENT HUB ESTABLISHED.")
end)
tangentSocket:read(4) -- Read the first 4 bytes, which will trigger the callback.
@latenitefilms
Copy link

latenitefilms commented Dec 23, 2017

FYI: Line 126 should be:

tangentSocket:send(numberToByteString(#byteString)..byteString)

Apart from that works BRILLIANTLY! THANK YOU!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment