New RS-232 plugin via XScript

Xlobby plugin development

New RS-232 plugin via XScript

Postby macboy on Tue Jun 19, 2007 9:24 pm

Since the RS-232 plugin still isn't available, one option is to use XScript(NG) and do a little scripting. This is actually quite easy because .NET 2.0 includes a "SerialPort" class which provides super-easy-to-use access to COM ports.

I am developing a plugin for Sony ES receivers which will use XScriptNG to provide control of the receiver over RS-232. It will provide control over power, volume, surround mode, tuner operation, etc., all with feedback of current state. For example, it will display the tuner station name and frequency, or sound field ("Cinema Studio EX A", etc.), or the current volume level, even if these things are changed using some other method like the remote or the front panel of the receiver. Because it is done in XScriptNG, you can do just about anything, and you can support any control protocol.

I will also write a plugin to control my Barco projector.

Anyone interested in some code samples? It takes only 5 lines of code to open the serial port, send a command, and close the port before exiting.
macboy
 
Posts: 8
Joined: Thu Jun 07, 2007 6:26 pm

Re: New RS-232 plugin via XScript

Postby ironcross on Wed Jun 20, 2007 9:58 pm

I would extremely grateful for some sample code. Thanks
ironcross
 
Posts: 19
Joined: Sun Feb 13, 2005 2:54 pm
Location: Atlanta

Re: New RS-232 plugin via XScript

Postby macboy on Fri Jun 22, 2007 10:58 pm

OK, as promised. Here is some sample code.

This first snippet is the absolute minimum to send a few bytes out of the serial port. In this case, it sends the command to turn on a Sony A/V Receiver (I'll call it the "Amp" since that avoids confusion with transmitter/receiver) which is connected to COM port 2.
Code: Select all
Imports System.IO.Ports

  ' Instantiate the communications port with some basic settings
  Dim port as SerialPort = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One)
  ' Open the port for communications
  port.Open
  ' Write a set of bytes
  port.Write(new Byte(){&H02, &H02, &HA0, &H21, &H3D}, 0, 5)    'syntax: write(byte(), 0, numberOfBytes)
  ' Close the port
  port.Close


The following is an example which also receives data back from the Amp (although it doesn't do much with it). It uses an event handler to receive the data, and it can be called with different parameters to send different commands to the Amp.
Code: Select all
' VB for use with XScriptNG plugin of Xlobby
' This script demonstrates serial communication to and from a Sony A/V Receiver using RS-232 serial.
' It uses the SerialPort class of .NET 2.0 (not available in .NET 1.x)
'
' The serial communications demonstrated in this plugin follows a strict protocol defined by Sony.
' The rules are:
' - Amplifier must send a reply within 500 msec after receiving a command from the Host Controller
' - Host Controller must not transmit another command until the reply has been received for the previous command
' - Host Controller must send each byte of the outgoing message within 10 msec of each other.
' - The Amplifier will never send any message unless there is a request from the Host Controller, even if
'   internal status changes, etc.
'
' Format of response depends on the opcode of the command.
' For opcode between 0x00 and 0x7F, the response is a single byte, either ACK (0xFD) or NACK (0xFE)
' For opcode between 0x80 and 0xFF, the response is a packet following this convention:
'  0x02      BC      OC      D1     [D2] ...   CS
'  start     num     opcode  data   data       Checksum
'   of       of              byte   byte
'  packet    bytes           #1     #2
'            OC->Dx                (optional)
' Checksum is the negative (i.e. 2's comp) value of the lowest byte of the sum of all bytes from BC through Dx


Imports System.IO
Imports System.IO.Ports    ' for SerialPort class
Imports System.Text

Module Script

' Instantiate the COM port with correct setting for the ES receiver
Public port As SerialPort  = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One)

Public writeIdx as Integer = 0
Public readBack(256) as Byte

'Each time the script is run, main is called with the parameter Action
Public Sub Main(Action as String)

  Select Case Action
    Case "PowerOn"
      ' Open the port
      If port.isOpen = FALSE then
        port.Open
      End If
      ' Connect the data received event handler
      AddHandler port.DataReceived, AddressOf PortDataReceived
      ' Send the power-on command
      port.Write(new byte(){&H02, &H02, &HA0, &H21, &H3D}, 0, 5)    'syntax: write(byte(), 0, numberOfBytes)

    Case "PowerOff"
      port.Write(new byte(){&H02, &H02, &HA0, &H20, &H3E}, 0, 5)    'syntax: write(byte(), 0, numberOfBytes)
      ' The receiver is now off so we don't need the serial port any longer
      port.Close
      'port = Nothing

    Case "StatusRequest"
      port.Write(new byte(){&H02, &H03, &HA0, &H82, &H00, &HDB}, 0, 6)

    Case "SendBadPacket"
      'Just to see how the receiver responds.
      port.Write(new byte(){&H02, &H03, &HA0, &HEE, &H00, &HDB}, 0, 6)

    Case "SendBadCommand"
      'Just to see how the receiver responds.
      port.Write(new byte(){&H02, &H02, &HA0, &H23, &H3B}, 0, 5)


  End Select
  'add more commands here
End Sub



' This sub is connected to the dataReceived event of the serialPort. When any data is received, this gets called
' so that we can read the data.
Public Sub PortDataReceived(sender as Object, e as SerialDataReceivedEventArgs)
    ' Read the data. There may be more than 1 byte.
    While port.BytesToRead > 0
      readBack(writeIdx) = port.ReadByte
      writeIdx = writeIdx + 1
      CheckResponseValid
    End while
End Sub



' This sub checks if the readBack array contains a valid response according to the protocol described above
Public Sub CheckResponseValid
  dim readIdx as Integer = 0
  dim checkSum as Integer = 0
  dim packetString as String
  Select Case readBack(0)
    Case &HFD
      'ACK
      writeIdx = 0   ' start over
      'could send acknowledement back to Xlobby here
      msgBox("ACK")
    Case &HFE
      'NACK
      writeIdx = 0
      'could send non-acknowledement back to Xlobby here
      msgBox("NACK")
    Case &H02
      'STX start of packet
      packetString = "02 "
      if writeIdx >= 2 then
        ' the second byte tells us the number of bytes in the packet
        if writeIdx >= (readBack(1)+3) then   
          ' we have received all bytes in the packet, so check the checksum
          checkSum = 0
          for readIdx = 1 to (readBack(1)+1) step 1
            checkSum = checkSum + readBack(readIdx)
            packetString &= Hex(readBack(readIdx)) & " "
          next
          checkSum = ((0 - checkSum) AND &HFF)
          if checkSum = readBack(readIdx) then
            'checksum is correct. do something
       msgBox("Packet received OK " & packetString)
          else
            'checksum is incorrect. do something
       msgBox("Packet Checksum wrong " & Hex(checkSum) & " " & Hex(readBack(readIdx)))
          end if
          writeIdx = 0    ' start over
        end if
      end if
    Case &H00
      'discard stray null byte
      writeIdx = 0
    Case Else
      'anything else is an error
      writeIdx = 0
  End Select
End Sub

End Module

I do not guarantee that this code is bug-free, in fact it probably has a few. But it works.
Have fun.
macboy
 
Posts: 8
Joined: Thu Jun 07, 2007 6:26 pm

Re: New RS-232 plugin via XScript

Postby dalanik on Sat Jun 23, 2007 8:38 am

There also is the option of using girder with generic RS232 plugin and sending messages to/from XLobby to Girder, that's what I do to control LG Plazma TV.

D.
dalanik
 
Posts: 885
Joined: Mon Apr 19, 2004 12:35 pm
Location: Prague, Czech Republic