ThreadedRubyProtocolObject
Here is my ThreadedRuby code. I'm trying to add notes and a bit of an explanation as to what each piece of code does. If you just want to get going, create a class Object for your protocol as per in section 5.
Device Object
This class is simply a holder for a Child Device with onoff and level added:
class Device attr_accessor :devdata, :deviceid, :template, :parent, :onoff, :level def initialize() @onoff = 'OFF' #State @level = 0 #Level @devdata = Hash.new #to hold devdata @deviceid = @template = @parent = 0 end end
$devices hash
This hash contains all the Device Objects (child objects with state info)
This is initialized in initDevices()
Command Object
$Commands Array
This is an Array of the Command Objects. This serves as the queue for the threading.
Once a command has been completed, it is removed from this array.
PLCBUS OBJECT
This is a generic replaceable object This object needs the following methods:
Methods
Initialize()
- What it does:
- any Object initialization you may need.
- When is this called:
- Upon Object creation.
- What you will get:
- nothing.
- What you will return:
- nothing.
dceCommandIn(cmd)
- What is does:
- sends you a command object to allow you to create gsdOut().
- What you will get:
- cmd (Command Object)
- What you need to return:
- nothing (ignored)
- When you will get this:
- executed when a new DCE command is sent to you.
dceResponseIn(cmd)
- What it does:
- Sends you a DCE object to compare with the command.
- What you will get:
- cmd (Command Object)
- What you need to return:
- TRUE if you accept this response.
- FALSE if you do NOT accept this response.
- When you will get this:
- executed when a new DCE response is ready.
gsdCommandIn(value)
- What it does:
sends you a String to allow you to create a dceOut().
- What you will get:
value (String Object)
- What you need to return:
nothing (ignored)
- When you will get this:
executed when a new GSD command is sent to you.
gsdResponseIn(value)
- What it does:
Sends you a GSD Response to compare with the command.
- What you will get:
cmd (Command Object)
- What you need to return:
- TRUE if you accept this response.
- FALSE if you do NOT accept this response.
- When you will get this:
executed when a new GSD response is ready.
dceout()
- What it does:
Creates a Command Object to send to DCE.
- What you will get:
nothing.
- What you need to return:
a Command Object representing the previous gsdCommandIn.
- When is this called:
After a gsdCommandIn has been sent.
gsdout()
- What it does:
creates a String Object to send to GSD.
- What you will get:
nothing.
- What you will return:
a String Object representing the previous dceCommandIn.
- When is this called:
After a dceCommandIn has been sent.
Properties:
@responseAccepted
- What it does:
- signals that the current response is accepted as valid.
- When you should set this:
- Set this to TRUE if you accept the response as a valid response for this command.
- Set this to FALSE if you do NOT accept this response
@responseNeeded
What it does: signals when you need a response.
@commandHolder
- What it does:
- If you need to create a new command, this is the holder for it.
ProtocolObject Class Template
class PLCBUS attr_reader :responseAccepted, :responseNeeded, :commandHolder, :threaded #Constants: Set up any constants here... STX=0x02.chr ETX=0x03.chr def initialize() @responseAccepted = false @responseNeeded = false @commandHolder = nil @threaded = true #set up any variable initialization here. end def dceCommandIn(cmd) #This is fired when a new DCE command is created. #cmd is a Command object ie Command.new #eg: @dcehomeunit = $devices[cmd.devidto_].devdata[12][0..1] @dcehome = HomeCodes[$devices[cmd.devidto_].devdata[12][0].chr].to_s @dceunit = UnitCodes[$devices[cmd.devidto_].devdata[12][1].chr].to_s @dcefrom = cmd.devidfrom_ @dceto = cmd.devidto_ @dcepriority = cmd.priority_ @dcecmdtype = cmd.type_ @dcecmdid = cmd.id_ @dceparams = cmd.params_ end def dceResponseIn(cmd) # Returns TRUE if response is accepted. #This is a RESPONSE from DCE. Normally, we do not get DCE responses #as the DCE commands we send do not need a Reply. #but if you need it, here is where you get it. return true #or false end def gsdCommandIn(value) @gsdusercode = value[2] @gsdhomeunit = ("%X" %value[3]) @gsdhome = @gsdhomeunit[0].chr @gsdunit = @gsdhomeunit[1].chr @gsdcommand = value[4] @gsdcmdAckPulse = true if (value[4] & 0x20) == 0x20 @gsdcmdReprq = true if (value[4] & 0x40) == 0x40 @gsdcmdLink = true if (value[4] & 0x80) == 0x80 @gsddata1 = value[5] @gsddata2 = value[6] if value[1] == 6 rxtxSwitchRegister(value[7]) #set switches if they exist end end def gsdResponseIn(value) #returns TRUE if response is accepted. #no need to store response.. just compare. @result = true #value is a string from GSD. #validate if you accept this response here.... return @result end def dceout # Returns the GSD values as a DCE command. @myfrom = gsdhomeunit if @myfrom == 0 log('I DONT KNOW THIS DEVICE ID') else @mycommandout = gsdcommand @cmdout = Command.new(@myfrom, -1001, 1, 2, @mycommandout) @gsdparams.each_pair{|k,v| @cmdout.params_[k]=v} return @cmdout end end def gsdout # Returns the DCE values as a gsd string @threaded = false #PLCBUS does not support threading #compile the output string from the values set in dceCommandIn(cmd) @gsdout = @usercode.chr @gsdout += dcehomeunit + dcecommand(@dcecmdid) + @data1.chr + @data2.chr @gsdout = @gsdout.length.chr + @gsdout @gsdout = STX + @gsdout + ETX return @gsdout end def checkResponse(cmd) #old?? fired when a response was accepted. @responseAccepted = true end ### Below you can add any kind of support routines you may need for your protocol. #I've deleted most of the code for brevity of a template. #Support Routines for PLCBUS def dcecommand(value) #DCE value is DCE Command. #user code is in devdata[59] Configuration #devdata[250] 3phase (boolean) case value when 192 #ON when 193 #OFF when 184 # SETLEVEL end return @command.chr end def gsdcommand #returns DCE EVENT!! and compiles params case CommandFunctions[@gsdcommand] when 'ALL UNIT OFF' @gsdparams[10] = '0' return 48 when 'ALL LTS ON' @gsdparams[10] = '1' return 48 when 'ON' @gsdparams[10] = '1' return 48 when 'OFF' @gsdparams[10] = '0' return 48 when 'DIM' @gsdparams[10] = @gsddata1 # set Brightness return 48 when 'BRIGHT' @gsdparams[10] = @gsddata1 # set Brightness return 48 when 'ALL LIGHT OFF' @gsdparams[10] = '0' return 48 when 'ALL USER LTS ON' @gsdparams[10] = '1' return 48 when 'ALL USER UNIT OFF' @gsdparams[10] = '0' return 48 when 'ALL USER LIGHT OFF' @gsdparams[10] = '0' return 48 when 'PRESETDIM' @gsdparams[10] = @gsddata1 return 48 else return 0 end return 0 end def rxtxSwitchRegister(value) #log('setting RX_TX_SWITCH') if (value & 0x40) == 0x40 #log('r_id_sw is set') @r_id_sw = true else #log('r_id_sw is reset') @r_id_sw = false end if (value & 0x20) == 0x20 #log('r_ack_sw is set') @r_ack_sw = true @responseNeeded = false else #log('ResponseNeeded set to TRUE') @responseNeeded = true #log('r_ack_sw is reset') @r_ack_sw = false end if (value & 0x10) == 0x10 #log('r_itself is set') @r_itself = true log('I heard myself Transmit this command on the PLCBUS.') else #log('r_itself is reset') @r_itself = false log('This Command is transmitted from an OUTSIDE SOURCE!') end if (value & 0x8) == 0x8 #log('r_risc is set') @r_risc = true else #log('r_risc is reset') @r_risc = false end if (value & 0x4) == 0x4 #log('r_sw is set') @r_sw = true else #log('r_sw is reset') @r_sw = false end end #Generic Support Routines def log(line) @log = File.open("/var/log/pluto/" + $me.deviceid.to_s + "_Generic_Serial_Device.log", "a") @log.putc '('[0] @log.putc 'P'[0] @log.putc 'L'[0] @log.putc 'C'[0] @log.putc ')'[0] @l = line.to_s @l.each_byte{|ch| @log.putc ch if ch == 60 @log.putc 32 end } @log.puts @log.close @log = nil end def debug(label, text) work = label + ":" for c in 1..text.length work += padhex("%X" %text[c-1]) + ' ' end log(BLUE + work + "Length:" + text.length.to_s + GREY) end def padhex(hex) if hex.length==1 hex = "0" + hex end return hex end end