Logic Machine Forum
pj talk - Printable Version

+- Logic Machine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Gateway (https://forum.logicmachine.net/forumdisplay.php?fid=10)
+--- Thread: pj talk (/showthread.php?tid=286)



pj talk - npinguin - 24.04.2016

Hi

I am trying to create a library for PJ talk communication with a Sony VPL-HW65ES Projector

I am experiencing some difficulties

protocol description is very limited, so far I found the following info
http://forum.coolux.de/viewtopic.php?t=2004&p=6623
http://ec1.images-amazon.com/media/i3d/01/A/man-migrate/MANUAL000015642.pdf


From what I figure out I need to send the following hex values

projector on
h01 h00 hA9 h17 h2F h00 h00 h00 h3F h9A

project off
h01 h00 hA9 h17 h2E h00 h00 h00 h3F h9A

My LUA knowledge is still limited

How can I setup a socket and communicate the above hex values ?
- how to setup the socket ?
- how to send hex values ?

Thanks
Nicky


RE: pj talk - admin - 24.04.2016

Try this example, just change ip variable to your projector IP address:

Code:
require('socket')

ip = '192.168.1.23'
port = 53484
cmd = string.char(0x01, 0x00, 0xA9, 0x17, 0x2F, 0x00, 0x00, 0x00, 0x3F, 0x9A)

sock = socket.tcp()
sock:settimeout(3)

res, err = sock:connect(ip, port)
if res then
  res, err = sock:send(cmd)

  if res then
    alert('send OK')
  else
    alert('send failed: ' .. tostring(err))
  end
else
  alert('connect failed: ' .. tostring(err))
end

sock:close()



RE: pj talk - npinguin - 24.04.2016

Super

thanks for the Lightning fast reply !


RE: pj talk - npinguin - 24.04.2016

I am one step further, but not there yet

- communication works, but command is probably not correct because I get a weird response

my user script
Code:
--------------------------------------
-- Author:         Nicky Wessels
-- Last Modified:     24/04/2016
--
-- Change Log:
-- 24/04/2016        Intial Version
--------------------------------------

-- IP of the projector
PROJECTOR_IP = '192.168.0.20'
PROJECTOR_PORT = '53484'

-- Power ON
-- 'h01 h00 hA9 h17 h2F h00 h00 h00 h3F h9A'
SONYPJ_CMD_ON = string.char(0x01, 0x00, 0xA9, 0x17, 0x2F, 0x00, 0x00, 0x00, 0x3F, 0x9A)

-- Power Off
-- 'h01 h00 hA9 h17 h2E h00 h00 h00 h3F h9A'
SONYPJ_CMD_OFF = string.char(0x01, 0x00, 0xA9, 0x17, 0x2E, 0x00, 0x00, 0x00, 0x3F, 0x9A)

-- change input s-video
-- 'h01 h00 ha9 h00 h01 h00 h00 h01 h01 h9a'
SONYPJ_SET_SVIDEO = string.char(0x01, 0x00, 0xA9, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x9A)


-- funtion to send basic commands to the receiver
function sonypj_send_cmd(cmd, ip, port)
    require 'socket.http'
 response_tbl = { }

 -- fill up optional parameters
 if (ip == nil) then
   ip = PROJECTOR_IP
 end
 if (port == nil) then
   port = PROJECTOR_PORT
 end
 response_tbl['ip']=ip
 response_tbl['port']=port
 response_tbl['cmd']=cmd

 -- Send command to projector
    sock = socket.tcp()
    sock:settimeout(3)
    result, err = sock:connect(ip, port)
 response_tbl['result']=result
    if result then
     result, err = sock:send(cmd)
      response_tbl['result']=result
   response_tbl['error']=error

   -- Check response from projector
        if result then
       alert('send OK')
     else
       alert('send failed: ' .. tostring(err), response_tbl)
     end
    else
     alert('connect failed: ' .. tostring(err), response_tbl)
    end
    sock:close()
 
 return response_tbl
end
my trigger script
Code:
require 'user.sony_pjtalk'

-- object mapped to this event must have its data type set
bStatus = event.getvalue()

-- get the status of the projector
if (bStatus) then
 status_tbl = sonypj_send_cmd(SONYPJ_CMD_ON)
else
    status_tbl = sonypj_send_cmd(SONYPJ_CMD_OFF)
end
 
log('status',status_tbl)

the response that I get for all commands

Code:
* arg: 2
 * table:
  [error]
   * function: builtin#19
  [ip]
   * string: 192.168.0.20
  [result]
   * number: 10
  [cmd]
   * string: 



RE: pj talk - Erwin van der Zwart - 24.04.2016

Hi,


Try this to see the HEX values from cmd after string.char(0x01, 0x00, 0xA9, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x9A):

Code:
response_tbl['cmd']=lmcore.strtohex(cmd)


Are your commands processed? Sometimes you need to end a command like this:

Code:
res, err = sock:send(cmd .. '\r')


If you expect an answer from the socket after sending a command you need to switch to receive mode like this:


Code:
s, status, partial = sock:receive(1024) -- 1024 is expected response length and be sure to set socket timeout like this sock:settimeout(2) before sending a command


Good luck!

BR,

Erwin


RE: pj talk - npinguin - 25.04.2016

Thanks Eric

Will try,

I have been searching on this topic and it seems nobody got this protocol working over ip...

Hmmm


RE: pj talk - npinguin - 30.11.2017

I got it working, but I am unable to convert a string into a hex array to compute the code

These codes work

Code:
-- Power ON
-- HEX: 02 0A 53 4F 4E 59 00 01 30 02 00 01
SONYSDCP_CMD_ON = string.char(0x02, 0x0A, 0x53, 0x4F, 0x4E, 0x59, 0x00, 0x01, 0x30, 0x02, 0x00, 0x01)

-- Power Off
-- HEX: 02 0A 53 4F 4E 59 00 01 30 02 00 00
SONYSDCP_CMD_OFF =string.char(0x02, 0x0A, 0x53, 0x4F, 0x4E, 0x59, 0x00, 0x01, 0x30, 0x02, 0x00, 0x00)

I use the following strings after computation

Code:
-- Power ON
-- HEX: 02 0A 53 4F 4E 59 00 01 30 02 00 01
SONYSDCP_CMD_ON = "020A534F4E59000130020001"

-- Power Off
-- HEX: 02 0A 53 4F 4E 59 00 01 30 02 00 00
SONYSDCP_CMD_OFF = "020A534F4E59000130020000"

The following helpers do not convert correctly, but I am unable to determine why 

Code:
-- convert hex char array to string
function string.fromhex(str)
   return (str:gsub('..', function (cc)
       return string.char(tonumber(cc, 16))
   end))
end

-- convert string to hex char array
function string.tohex(str)
   return (str:gsub('.', function (c)
       return string.format('%02X', string.byte(c))
   end))
end



RE: pj talk - admin - 30.11.2017

You can convert hex to binary string like this (second argument is needed, otherwise NULL bytes will be removed). You can also use loghex function which logs binary strings in readable hex format.
Code:
SONYSDCP_CMD_ON = lmcore.hextostr('020A534F4E59000130020001', true)
loghex(SONYSDCP_CMD_ON)



RE: pj talk - npinguin - 30.11.2017

Thanks  Smile

I found an alternative in the mean time

Hereby the full script for anyone looking for a PJ Talk solution

Code:
--------------------------------------
-- Author:         Nicky Wessels
-- Last Modified:     30/11/2017
--
-- Change Log:
-- 24/04/2016        Intial Version
-- 30/11/2017        Update Based on SDCP-Com - By Vokkim on JSDelivr
-- 30/11/2017        Javascript code https://github.com/vokkim/sony-sdcp-com
-- 30/11/2017        Protocol https://www.digis.ru/upload/iblock/f5a/VPL-VW320,%20VW520_ProtocolManual.pdf
--------------------------------------

-------------------------
-- CONFIG
-------------------------

-- IP of the projector
BASEMENT_PROJECTOR_IP = '192.168.0.21'
BASEMENT_PROJECTOR_PORT = '53484'

-------------------------
-- CONSTANTS
-------------------------

-- CONSTANTS
VERSION = '02'
CATEGORY = '0A'
-- Default to 'SONY'
COMMUNITY = '534F4E59'
                            
actions = {
 GET= '01',
 SET= '00'
}

commands = {
 SET_POWER= '0130',
 CALIBRATION_PRESET= '0002',
 ASPECT_RATIO= '0020',
 INPUT= '0001',
 GET_STATUS_ERROR= '0101',
 GET_STATUS_POWER= '0102',
 GET_STATUS_LAMP_TIMER= '0113'
}

input = {
 HDMI1 = '0002',
 HDMI2 = '0003',
}

aspectRatio = {
 NORMAL= '0001',
 V_STRETCH= '000B',
 ZOOM_1_85= '000C',
 ZOOM_2_35= '000D',
 STRETCH= '000E',
 SQUEEZE= '000F'
}

powerStatus = {
 STANDBY= '0000',
 START_UP= '0001',
 START_UP_LAMP= '0002',
 POWER_ON= '0003',
 COOLING= '0004',
 COOLING2= '0005'
}

-- set projector input
function setInput(input, ip, port, debug)
 if (debug) then
   log (string.format("setInput:%s projector:%s:%s", input, ip, port))
 end
 frame = createMessageAsHex(actions.SET, commands.INPUT, input, debug)
 result = sony_sdcp_send_frame(frame, ip, port, debug)
 return result
end

-- get projector input status
function getInputStatus(ip, port, debug)
 if (debug) then
   log (string.format("getInputStatus projector:%s:%s", ip, port))
 end
 frame = createMessageAsHex(actions.GET, commands.INPUT, nil, debug)
 result = sony_sdcp_send_frame(frame, ip, port, debug)
 inputStatus = nil
 if (result and result.reply and result.reply.data) then
   inputStatus = result.reply.data
 end
 return inputStatus
end

-- power projector on
function setPower(powerOn, ip, port, debug)
 if (debug) then
   log (string.format("powerOn:%s projector:%s:%s", tostring(powerOn), ip, port))
 end
 if (powerOn) then
   frame = createMessageAsHex(actions.SET, commands.SET_POWER, powerStatus.START_UP, debug)
 else
     frame = createMessageAsHex(actions.SET, commands.SET_POWER, powerStatus.STANDBY, debug)
 end
 result = sony_sdcp_send_frame(frame, ip, port, debug)
 return result
end

-- get projector power status
function getPowerStatus(ip, port, debug)
 if (debug) then
   log (string.format("getPowerStatus projector:%s:%s", ip, port))
 end
 frame = createMessageAsHex(actions.GET, commands.GET_STATUS_POWER, nil, debug)
 result = sony_sdcp_send_frame(frame, ip, port, debug)
 powerstatus = false
 if (result and result.reply and result.reply.data) then
   powerstatus = result.reply.data
 end
 return powerstatus
end

-- get projector power status as a boolean
function getPowerStatusAsBool(ip, port, debug)
 if (debug) then
   log (string.format("getPowerStatusAsBool projector:%s:%s", ip, port))
 end
 result = false
 powerstatus = getPowerStatus(ip, port, debug)
 if (powerstatus) then
   result = powerstatus == powerStatus.POWER_ON or powerstatus == powerStatus.START_UP or powerstatus == powerStatus.START_UP_LAMP
 end
 return result
end

-- convert hex char array to string
function string.fromhex(str)
 result =''
    for c in str:gmatch"." do
   result = result .. string.format("%02x", string.byte(c))
 end
 return string.upper(result)
end

-- convert string to hex char array
function string.tohex(str)
 result =''
    for cc in str:gmatch".." do
   result = result .. string.char(tonumber(cc, 16))
 end
 return string.upper(result)
end

-- create a sdcp message
function createMessageAsHex(action, command, data, debug)
 if (command and type(command) ~= "string") then
   alert(string.format("Accepts command only as String (HEX) for now, was %s", type(command)))
    end    
 if (string.len(command) ~= 4) then
        alert(string.format("Command must be 4 bytes long"))
 end
 if (data and type(data) ~= "string") then
     alert(string.format("Accepts data only as String (HEX) for now, was %s", type(data)))
 end
 if (not data) then
   data = ""
 end
   
 dataLength = string.format('%02x', string.len(data)/2)
 if (debug) then
--    log ("dataLength:" .. dataLength)
 end

 frame = VERSION .. CATEGORY.. COMMUNITY.. action.. command.. dataLength.. data
 if (debug) then
--    log ("frame:" .. frame)
 end
    return string.tohex(frame)
end

-- parse a sdcp message
function parseResponse(value, debug)
 if (not value) then
   alert(string.format("Empty value passed"))
   assert(not value, string.format("Empty value passed"))
 end
 frame = string.fromhex(value)
 if (string.len(frame) < 20) then
   alert(string.format("Unknown response %s, length %d",frame,string.len(frame)))
   assert(string.len(frame) < 20, string.format("Unknown response %s",frame))
 end
    version = string.sub(frame, 1, 2)
    category = string.sub(frame, 3, 4)
    community = string.sub(frame, 5, 12)
    success = string.sub(frame, 13, 14)
    command = string.sub(frame, 15, 18)
    dataLength = string.sub(frame, 19, 20)
 if (tonumber(dataLength, 16) > 0) then
        data = string.sub(frame,21, 21 + tonumber(dataLength, 16) * 2)
 end
    result = {
   version=version,
        category=category,
        community=community,
        command=command,
        dataLength=dataLength,
   data=data,
        success=success ~= '00',
   raw = frame
 }
 return result
end

-- funtion to send basic commands to the projector
function sony_sdcp_send_frame(frame, ip, port, debug)
    require 'socket.http'
 response_tbl = { }

 -- fill up optional parameters
 if (ip == nil) then
   ip = BASEMENT_PROJECTOR_IP
 end
 if (port == nil) then
   port = BASEMENT_PROJECTOR_PORT
 end
 response_tbl['ip']=ip
 response_tbl['port']=port
 response_tbl['frame']=frame
 if (debug) then
   log("ip:" .. ip)
   log("port:" .. port)
   log("transmit frame char:" .. string.fromhex(frame))
   log("transmit frame hex:" .. frame)
   log("transmit frame length:" .. string.len(frame))
 end
 
 -- Send command to projector
    sock = socket.tcp()
    sock:settimeout(3)
    result, err = sock:connect(ip, port)
 response_tbl['result']=result
 response_tbl['error']=err
    if result then
     result, err = sock:send(frame .. "\r")
   
      response_tbl['result']=result
   response_tbl['error']=error

   -- Check response from projector
        if result then
          if (debug) then
       log ('transmit succesfully send')
     end
     -- read the response
     resframe = ''
     while true do
         resp, err, part = sock:receive(1)
       if resp ~= nil then
           resframe = resframe .. resp
       else
         break
       end
     end
     resstring = string.fromhex(resframe)
     resdecoded = parseResponse(resframe)
     response_tbl['reply']=resdecoded
     if (debug and resframe) then
       log("response frame char:" .. resstring)
       log("response frame hex:" .. resframe)
       log("response frame length:" .. string.len(resframe))
       log("response frame decoded", resdecoded)        
     end
     
     else
       alert('send failed: ' .. tostring(err), response_tbl)
     end
    else
     alert('connect failed: ' .. tostring(err), response_tbl)
    end
    sock:close()
 
 return response_tbl
end


add trigger scripts to call the functions in the user lib

Code:
-- activate projector
setPower(bStatus, BASEMENT_PROJECTOR_IP, BASEMENT_PROJECTOR_PORT)
-- check if it is active or starting up
-- warning takes a few seconds before projector boots up
bPowerStatus = getPowerStatusAsBool(BASEMENT_PROJECTOR_IP, BASEMENT_PROJECTOR_PORT)
-- set the input
setInput(input.HDMI1, BASEMENT_PROJECTOR_IP, BASEMENT_PROJECTOR_PORT, true)
-- check the input state
sInputStatus = getInputStatus(BASEMENT_PROJECTOR_IP, BASEMENT_PROJECTOR_PORT)