Difference between revisions of "PLCBUS"

From LinuxMCE
Jump to: navigation, search
 
(20 intermediate revisions by 8 users not shown)
Line 1: Line 1:
[[Category: Hardware]]
+
{{versioninfo|810Status=Working|810UpdatedDate=1st May 2010|810UpdatedBy=BongoWongo}}
 
[[Category: Automation]]
 
[[Category: Automation]]
 +
[[Category: Power Line Control]]
 +
[[Category: PLCBUS]]
 
  {| align="right"
 
  {| align="right"
 
   | __TOC__
 
   | __TOC__
Line 6: Line 8:
 
[[Image:Plcbus-logo.jpg|right]]
 
[[Image:Plcbus-logo.jpg|right]]
 
= Status =
 
= Status =
ddamron wrote a GSD for PLCBUS with ruby. Hari will try to get a c++ dce client running.
+
We've implemented a new C++ driver for 0810b2. More information here: http://forum.linuxmce.org/index.php?topic=11170.0
  
 
= About =
 
= About =
Line 29: Line 31:
 
* http://x10-hk.com/store/manual/plcbus/plcbus-1141.pdf
 
* http://x10-hk.com/store/manual/plcbus/plcbus-1141.pdf
  
= GSD/Ruby Code =
+
 
* [[ThreadedRuby]]
+
* http://wiki.linuxmce.org/index.php/PLCBUScmd776
+
* http://wiki.linuxmce.org/index.php/PLCBUScmd373
+
* http://wiki.linuxmce.org/index.php/PLCBUScmd484
+
* http://wiki.linuxmce.org/index.php/PLCBUScmd760
+
* http://wiki.linuxmce.org/index.php/PLCBUScmd776
+
<pre>
+
RCODE:
+
  0:require 'Ruby_Generic_Serial_Device'
+
  1:class Command < Ruby_Generic_Serial_Device::RubyCommandWrapper
+
  2:end
+
  3:class Device_110 < Ruby_Generic_Serial_Device::RubySerialIOWrapper
+
  4:#### 350 ####################################################################
+
  5:def cmd_350(cmd=nil)
+
  6:@returnParamArray.clear
+
  7:### #350
+
  8:
+
  9:while(true)
+
  10:  @buff = conn_.RecvDelimited(0x02.chr,100) #stx
+
  11:  if(@buff.length() == 0)
+
  12:    break
+
  13:  end
+
  14:  @buff2 = conn_.Recv(1,10) #Length of message
+
  15:  @buff +=@buff2
+
  16:  @length = @buff2[0]
+
  17:  @buff += conn_.Recv(@length + 1, 100)
+
  18:  debugin(@buff)
+
  19:  dataIn(@buff)
+
  20:end
+
  21:
+
  22:
+
  23:# this routine needs to be handled better.
+
  24:# possibly with regular expressions.
+
  25:return @returnParamArray
+
  26:end
+
  27:#### 351 ####################################################################
+
  28:def cmd_351(cmd=nil)
+
  29:@returnParamArray.clear
+
  30:errorHandler()
+
  31:return @returnParamArray
+
  32:end
+
  33:#### 355 ####################################################################
+
  34:def cmd_355(cmd=nil)
+
  35:@returnParamArray.clear
+
  36:#########################
+
  37:# Written by Dan Damron #
+
  38:#########################
+
  39:
+
  40:initDevices()
+
  41:return @returnParamArray
+
  42:end
+
  43:#### PRIVATE METHODS ####################################################################
+
  44:#######################################
+
  45:# Threaded RubyCommand
+
  46:# Written by Dan Damron
+
  47:#######################################
+
  48:
+
  49:class Device                                                      #Child Device Holder
+
  50:  attr_accessor  :devdata, :deviceid, :template, :parent, :onoff, :level
+
  51:  def initialize()                                             
+
  52:    @onoff = 'OFF'                                                #State
+
  53:    @level = 0                                                    #Level
+
  54:    @devdata = Hash.new                                          #to hold devdata
+
  55:    @deviceid = @template = @parent = 0
+
  56:  end
+
  57:end
+
  58:
+
  59:class Devices                                                    #holder for Child Devices
+
  60:  def initialize
+
  61:    @devices = Hash.new
+
  62:  end
+
  63:  def append(device)                                              #Device Object
+
  64:    @devices[device.deviceid] = device
+
  65:  end
+
  66:  def find(value)                                                #this method finds the devdata[12] and returns the child ID
+
  67:    @result = 0
+
  68:    log('Looking up:' + value.to_s)
+
  69:    @devices.each_key{|d|
+
  70:      if @devices[d].devdata[12] == value
+
  71:        @result = @devices[d].deviceid
+
  72:      end}
+
  73:    log('In Devices:find() result:' + @result.to_s)
+
  74:    return @result
+
  75:  end
+
  76:  def [](value)                                                  #return the device.
+
  77:    return @devices[value]
+
  78:  end
+
  79:  def log(line)                                                  #logger
+
  80:    @log = File.open("/var/log/pluto/" + $me.deviceid.to_s + "_Generic_Serial_Device.log", "a")
+
  81:    @log.putc '('[0]
+
  82:    @log.putc 'D'[0]
+
  83:    @log.putc 'E'[0]
+
  84:    @log.putc 'V'[0]
+
  85:    @log.putc 'I'[0]
+
  86:    @log.putc 'C'[0]
+
  87:    @log.putc 'E'[0]
+
  88:    @log.putc 'S'[0]
+
  89:    @log.putc ')'[0]
+
  90:    @l = line.to_s
+
  91:    @l.each_byte{|ch|
+
  92:      @log.putc ch
+
  93:      if ch == 60
+
  94:        @log.putc 32
+
  95:      end
+
  96:    }
+
  97:    @log.puts
+
  98:    @log.close
+
  99:    @log = nil
+
100:  end
+
101:end
+
102:
+
103:
+
104:RED = 0x1b.chr + '[31m'
+
105:GREEN = 0x1b.chr + '[32m'
+
106:YELLOW = 0x1b.chr + '[33m'
+
107:BLUE = 0x1b.chr + '[34m'
+
108:PURPLE = 0x1b.chr + '[35m'
+
109:AQUA = 0x1b.chr + '[36m'
+
110:GREY = 0x1b.chr + '[37m'
+
111:REDBACK = 0x1b.chr + '[41m'
+
112:GREENBACK = 0x1b.chr + '[42m'
+
113:YELLOWBACK = 0x1b.chr + '[43m'
+
114:BLUEBACK = 0x1b.chr + '[44m'
+
115:PURPLEBACK = 0x1b.chr + '[45m'
+
116:AQUABACK = 0x1b.chr + '[46m'
+
117:GREYBACK = 0x1b.chr + '[47m'
+
118:BLACKBACK = 0x1b.chr + '[48m'
+
119:DCEtoGSD = 10
+
120:GSDtoDCE = 20
+
121:NotReady = 1
+
122:SendReady = 2
+
123:ReceiveReady = 3
+
124:Complete = 4
+
125:Failed = 5
+
126:
+
127:
+
128:
+
129:
+
130:##############################
+
131:# Methods for $commands[] queue
+
132:##############################
+
133:def dataIn(value)
+
134:  #log('DataIn Entered:')
+
135:  $commands.each{|cmd|
+
136:    if cmd.state == ReceiveReady                                    #only ReceiveReady cmds.
+
137:      if cmd.dataIn(value) == true                                  #this data was accepted if TRUE
+
138:        @newcmd = cmd.commandHolder                                #check for new command
+
139:        if @newcmd != nil
+
140:          log(YELLOW + 'This command is spawning!!!' + GREY)
+
141:          $commands.push @newcmd                                    #if so, push it onto the queue
+
142:        end
+
143:        if cmd.state == SendReady
+
144:          log('DataIn: Ready to Send.')
+
145:          dataOutSingleCmd(cmd)
+
146:        end
+
147:        if cmd.state == Complete
+
148:          if cmd.threaded == false
+
149:            log(YELLOW + 'Threading RESUMED' + GREY)
+
150:            $threadingSuspended = false                                #allow other commands to now transmit.
+
151:          end
+
152:          log(PURPLE + 'DataIn:Command Complete!' + GREY)
+
153:          $commands.delete(cmd)                                    #remove command if complete
+
154:        end
+
155:        if cmd.state == Failed
+
156:          log(RED + 'DataIn:This Command FAILED:' + GREY)
+
157:          log(YELLOW + cmd.inspect + GREY)                          #inspect the failed command
+
158:          log('Command Deleted.')
+
159:          $commands.delete(cmd)                                    #remove command if failed
+
160:        end
+
161:        return
+
162:      end
+
163:    end
+
164:  }
+
165:  #if we hit here, the data has been rejected by all current commands.
+
166:  log('dataIn: New Command:')
+
167:  c = RubyCommand.new
+
168:  c.dataIn(value) # sets up the command.
+
169:  dataOutSingleCmd(c) if c.state == SendReady #check to see if it's ready to send
+
170:  $commands.push c.clone                      #push a copy of it onto the queue.
+
171:  c = nil
+
172: 
+
173:  #dataOut()                                                        #safer to call it in turn.
+
174:  #log('DataIn Exited:')
+
175:end
+
176:def dataOut()                                                      #replaces send()
+
177:  log('dataOut Entered:')
+
178:  #Send out all the commands...
+
179:  $commands.each{|cmd|
+
180:    dataOutSingleCmd(cmd)
+
181:    if cmd.state == Complete
+
182:      log(PURPLE + 'DataOut:Command Complete!' + GREY)
+
183:      $commands.delete(cmd)
+
184:    end
+
185:    if cmd.state == Failed
+
186:      log(RED + 'DataOut:This Command FAILED:' + GREY)
+
187:      log(YELLOW + cmd.inspect + GREY)                          #inspect the failed command
+
188:      log('Command Deleted.')
+
189:      $commands.delete(cmd)                                    #remove command if failed
+
190:    end
+
191:
+
192:  }
+
193:  #log('dataOut Exited:')
+
194:end
+
195:def dataOutSingleCmd(cmd)
+
196:  log('dataOutSingleCmd Entered:')
+
197:  if cmd.state == SendReady                                        #send out only if ready.
+
198:    @out = cmd.dataOut
+
199:    log('got past cmd.dataOut')
+
200:    log('@out is type:' + @out.class.to_s)
+
201:    case @out.class.to_s
+
202:    when 'String'
+
203:      log('Threading Suspended = FALSE') if $threadingSuspended == false
+
204:      log('Threading Suspended = TRUE') if $threadingSuspended == true
+
205:     
+
206:      if $threadingSuspended == false
+
207:      conn_.Reconnect()
+
208:      log('Sending to GSD...')
+
209:      debugout(@out)
+
210:      conn_.Send(@out)
+
211:      debugout(@out)
+
212:      conn_.Send(@out)
+
213:      sleep $delayBetweenTransmits
+
214:      if cmd.threaded == false
+
215:        log(YELLOW + 'THREADING SUSPENDED!!!' + GREY)
+
216:        $threadingSuspended == true
+
217:      end
+
218:      else
+
219:        #cannot send data out while waiting for a NON threaded response.
+
220:      end
+
221:    when 'Command'
+
222:      log('Sending to DCE...')
+
223:      SendCommand(@out)
+
224:    when 'NilClass'                                                #safety first!
+
225:      log('This command not ready to send.')
+
226:    end
+
227:  end
+
228:  #log('dataOutSingleCmd Exited:')
+
229:end
+
230:def log(line)
+
231:  $log = File.open("/var/log/pluto/" + device_.devid_.to_s + "_Generic_Serial_Device.log", "a")
+
232:  $log.putc '('[0]
+
233:  $log.putc '*'[0]
+
234:  $log.putc '*'[0]
+
235:  $log.putc '*'[0]
+
236:  $log.putc ')'[0]
+
237:  @l = line.to_s
+
238:  @l.each_byte{|ch|
+
239:    $log.putc ch
+
240:    if ch == 60
+
241:      $log.putc 32
+
242:    end
+
243:  }
+
244:  $log.puts
+
245:  $log.close
+
246:end
+
247:def debugout(text)
+
248:  work = 'OUT:'
+
249:
+
250:  for c in 1..text.length
+
251:    work += padhex("%X" %text[c-1]) + ' '
+
252:  end
+
253:  log(GREEN + work + "Length:" + text.length.to_s + GREY)
+
254:end
+
255:def debug(label, text)
+
256:  work = label + ":"
+
257:  for c in 1..text.length
+
258:    work += padhex("%X" %text[c-1]) + ' '
+
259:  end
+
260:  log(BLUE + work + "Length:" + text.length.to_s + GREY)
+
261:end
+
262:def debugin(text)
+
263:  work = 'IN:'
+
264:
+
265:  for c in 1..text.length
+
266:    work += padhex("%X" %text[c-1]) + ' '
+
267:  end
+
268:  log(RED + work + "Length:" + text.length.to_s + GREY)
+
269:end
+
270:def padhex(hex)
+
271:  if hex.length==1
+
272:    hex = "0" + hex
+
273:  end
+
274:  return hex
+
275:end
+
276:
+
277:##############################
+
278:#Initialization Routine
+
279:##############################
+
280:def initDevices()                                                  #Loads Child Devices into Devices
+
281:  $threadingSuspended = false
+
282:  $timeout = 1                                                  #Global timeout
+
283:  $retryAttempts = 10                                          #Global Retry Attempts
+
284:  $delayBetweenTransmits = 0.4
+
285:  log(YELLOW + 'Loading Child Devices...' + GREY)
+
286:  $devices = Devices.new
+
287:  device_.childdevices_.keys.each{|c|                          #Populate children
+
288:    d = Device.new()                                            #create a new device
+
289:    d.deviceid = c                                             
+
290:    d.template = device_.childdevices_[c].devtemplid_
+
291:    d.parent = device_.childdevices_[c].parent_
+
292:    d.devdata = device_.childdevices_[c].devdata_
+
293:    $devices.append(d)                                          #add d to $devices
+
294:    log('Device:' + d.deviceid.to_s)}
+
295:  $me = Device.new()                                            #get MY info
+
296:  $me.deviceid = device_.devid_
+
297:  $me.parent = device_.parent_
+
298:  $me.devdata = []
+
299:  $me.devdata = device_.devdata_
+
300:  $me.onoff = "ON"
+
301:  $me.level = 100
+
302:  myusercode = "My Usercode: %X" %$me.devdata[59].to_i          #show in hex form
+
303:  log(myusercode)
+
304:
+
305:  log(YELLOW + 'Done.' + GREY)                                  #devdata[59] = usercode
+
306:  log(YELLOW + 'Setting up Command Queue' + GREY)            #dedata[249] =  3phase (boolean)
+
307:  $commands = Array.new
+
308:  log(YELLOW + 'Done.' + GREY)
+
309:  #TODO:  read all the PLC devices to get initial status.
+
310:  #TODO:  and report status back to lmce.
+
311:end
+
312:def errorHandler                                                    # threaded errorhandler
+
313:  #Error handling is now handled at the RubyCommand Level.
+
314:  if $commands.nitems != 0                                          #log out the commands waiting to be processed, if any.
+
315:    @work = YELLOW + 'Command Queue:' + $commands.nitems.to_s
+
316:    $commands.each{|cm| @work += ', State:'
+
317:      @work += 'NEW' if cm.state == 1
+
318:      @work += 'SendReady' if cm.state == 2
+
319:      @work += 'ReceiveReady' if cm.state == 3
+
320:      @work += 'Complete' if cm.state == 4
+
321:      @work += 'Failed' if cm.state == 5
+
322:      @work += GREY + '  '}
+
323:    log(@work)
+
324:  end
+
325:  $commands.each{|cmd|
+
326:    case cmd.state                                                  #possible to clear out commands here..
+
327:    when Complete
+
328:      $commands.delete(cmd)
+
329:      #    when SendReady
+
330:      #      dataOutSingleCmd(cmd)
+
331:    when ReceiveReady
+
332:      if cmd.timeout == true                                        #call the timeout and get back error.
+
333:        log(RED + 'This Command Timed Out!:' + GREY)
+
334:        log(RED + cmd.inspect + GREY)
+
335:        $commands.delete(cmd)
+
336:      else
+
337:        dataOutSingleCmd(cmd)
+
338:      end
+
339:    end
+
340:  }
+
341:end
+
342:
+
343:##############################
+
344:#Class RubyCommand
+
345:##############################
+
346:class RubyCommand
+
347:  # This class is a container for a protocolObject Instance.
+
348:  # This class is responsible for the DIRECTION of communication of a specific command.
+
349:  #
+
350:  # Error Handling is also handled in the timeout method.
+
351:  #
+
352:  # If this command creates a NEW command, this object will allow only ONE creation.
+
353:  # This class also controls the state information.
+
354:  # Constants:
+
355:  DCEtoGSD = 10
+
356:  GSDtoDCE = 20
+
357:  #Object States:
+
358:  NEW = 1
+
359:  SendReady = 2
+
360:  ReceiveReady = 3
+
361:  Complete = 4
+
362:  Failed = 5
+
363:
+
364:
+
365:  def initialize
+
366:    #log('Initialize Entered:')
+
367:    @protocolObject = PLCBUS.new()
+
368:    @direction = nil
+
369:    @timeoutCounter = 0
+
370:    @timeoutRetries = 0
+
371:    @state = NEW
+
372:    @serialNumber = rand(10000).to_s                #for DCE object
+
373:    @newCommandSent = false
+
374:    #log('Initialize Exited:')
+
375:  end
+
376:  def dataIn(cmd)                                                  #Returns TRUE if accepted, FALSE if not.
+
377:    #log('dataIn Entered:')
+
378:    case @state
+
379:    when NEW
+
380:      log('dataIn: creating NEW command')
+
381:      @savedCommand = cmd
+
382:     
+
383:      case cmd.class.to_s
+
384:      when 'String'                                  # new Command from GSD
+
385:        @direction = GSDtoDCE
+
386:        @protocolObject.gsdCommandIn(cmd)
+
387:        @state = SendReady                          #This command is ready to send.
+
388:      when 'Command'                                  # new Command from DCE
+
389:        @direction = DCEtoGSD
+
390:        @protocolObject.dceCommandIn(cmd)
+
391:        @state = SendReady                          #This command is ready to send.
+
392:      else
+
393:        log('FAILURE IN dataIn - cmd.class not recognized!')
+
394:        log('Direction: nil')
+
395:        log('class is:' + cmd.class.to_s)
+
396:        @state = Failed                            #fail this command. (remove it)
+
397:      end
+
398:      @result = true                                #returns datain Accepted.
+
399:    when ReceiveReady                              #Possible Response
+
400:      log('dataIn: Possible Response')
+
401:      @result = false
+
402:      @class = cmd.class.to_s                      #get this only once.
+
403:      case @direction
+
404:      when DCEtoGSD
+
405:        case @class
+
406:        when 'String'                              # from GSD
+
407:          #log('dataIn: class is STRING')
+
408:          #pass the data to the protocol Object and check for accepted.
+
409:          #log('dataIn: executing gsdResponseIn')
+
410:          if @protocolObject.gsdResponseIn(cmd) == true
+
411:            log('response Accepted.')
+
412:            @result = true
+
413:            if @protocolObject.responseNeeded == true
+
414:              log('Command not yet complete.')
+
415:              @state = ReceiveReady                  # ProtocolObject needs another response.
+
416:            else
+
417:              log('Command Complete.')
+
418:              @state = Complete                      # ProtocolObject is complete.
+
419:            end
+
420:
+
421:          else
+
422:            log('response Rejected!')
+
423:          end
+
424:        when 'Command'                                # from DCE
+
425:          #log('dataIn: class is COMMAND')
+
426:          @result = false                          # cmd is NOT for me.
+
427:        else
+
428:          log('FAILURE IN dataIn - cmd.class not recognised!')
+
429:          log('Direction: DCEtoGSD')
+
430:          log('class is:' + @class.to_s)
+
431:
+
432:          @result = false
+
433:        end
+
434:
+
435:      when GSDtoDCE
+
436:        case @class
+
437:        when 'String'                                # from GSD
+
438:          @result = false                          # not for me.
+
439:        when 'Command'                                # POSSIBLE when sending commands to self.
+
440:          if cmd.params_[999] == @serialNumber
+
441:            @result = true                          #I sent this command!
+
442:            log('Caught Command Sent to Self!')
+
443:          end
+
444:        else
+
445:          log('FAILURE IN dataIn - cmd.class not recognised!')
+
446:          log('Direction: GSDtoDCE')
+
447:          log('class is:' + @class.to_s)
+
448:
+
449:        end
+
450:      end
+
451:      #log('dataIn: returning TRUE (exited)') if @result == true
+
452:      #log('dataIn: returning FALSE (exited)') if @result == false
+
453:      return @result
+
454:    end
+
455:  end
+
456:  def dataOut
+
457:    log('dataOut Entered:')
+
458:    if @state == SendReady
+
459:      case @direction
+
460:      when DCEtoGSD                                  #Send GSD String
+
461:        @work = @protocolObject.gsdout
+
462:        log('dataOut:  Setting @state to Receive Ready')
+
463:        @state = ReceiveReady
+
464:      when GSDtoDCE
+
465:        @work = @protocolObject.dceout
+
466:        if @work.class.to_s == 'Command'              #check for valid Object (returns nil if not ready)
+
467:          if @work.devidto_ == @work.devidfrom_      #check for command to self
+
468:            log('Detected attempting to send to self')
+
469:            @work.devdata_[999] = @serialNumber      #this command is to self.  Serialize it.
+
470:          end
+
471:        end
+
472:        log('dataOut:  Setting @state to Complete')
+
473:        @state = Complete                            #DCE does not send responses. (yet)
+
474:      else
+
475:        log('Attempted DataOut with uninitialized Object')
+
476:        @state = Failed
+
477:        @work = nil
+
478:      end
+
479:      log('dataOut: Returning @work')
+
480:      return @work
+
481:    else
+
482:      log('This command is not ready to send.')
+
483:    end
+
484:    log('DataOut Exited:')
+
485:  end
+
486:  def timeout                                                      #called ONLY when @state == ReceiveReady
+
487:    @result = false                                #returns TRUE if command times out.
+
488:    @timeoutCounter +=1                            #ticker += 1
+
489:    if @timeoutCounter == $timeout                  #global variable defined in init.
+
490:      @timeoutCounter = 0                          #reset ticker
+
491:      @timeoutRetries += 1                          #increment Retries..
+
492:      if @timeoutRetries == $retryAttempts          #global variable defined in init.
+
493:        @state = Failed
+
494:        @result = true
+
495:      else
+
496:        log('Attempt:' + (@timeoutRetries + 1).to_s)
+
497:        if @state == ReceiveReady
+
498:          @state = SendReady
+
499:        end
+
500:      end
+
501:     
+
502:    end
+
503:    log('Tick...')
+
504:    return @result
+
505:  end
+
506:  def state
+
507:    return @state
+
508:  end
+
509:  def direction()
+
510:    return @direction
+
511:  end
+
512:  def responseNeeded()
+
513:    return @protocolObject.responseNeeded
+
514:  end
+
515:  def commandHolder()                                              #This is a holder of self.  Used when inserting another command.
+
516:    #allow only ONE command to be returned.
+
517:    @holder = @protocolObject.commandHolder
+
518:    if @holder != nil
+
519:      if @newCommandSent == false
+
520:        #we can send the command here.
+
521:        @newCommandSent = true 
+
522:        return @holder
+
523:      end
+
524:    end
+
525:    return nil
+
526:  end
+
527:  def threaded
+
528:    return @protocolObject.threaded
+
529:  end
+
530:  #  def packCommand(value)  # this is used by protocolObject to pack a command.
+
531:  #    if value.class.to_s == 'Command'
+
532:  #      #packing a DCE Object..
+
533:  #      self.dcein(value)
+
534:  #      #override the direction...
+
535:  #      @direction = GSDtoDCE
+
536:  #      #flag the command ready to be sent.
+
537:  #      @sendReady = true
+
538:  #    end
+
539:  #    if value.class.to_s == 'String'
+
540:  #      #packing a GSD object
+
541:  #      self.gsdin(value)
+
542:  #      #override the direction...
+
543:  #      @direction = DCEtoGSD
+
544:  #      #flag the command ready to be sent.
+
545:  #      @sendReady = true
+
546:  #    end
+
547:  #  end
+
548:  #  def hasNewCommand()
+
549:  #    return @hasNewCommand
+
550:  #  end
+
551:  def log(line)                                                    #support method.
+
552:    @log = File.open("/var/log/pluto/" + $me.deviceid.to_s + "_Generic_Serial_Device.log", "a")
+
553:    @log.putc '('[0]
+
554:    @log.putc 'C'[0]
+
555:    @log.putc 'o'[0]
+
556:    @log.putc 'm'[0]
+
557:    @log.putc 'm'[0]
+
558:    @log.putc 'a'[0]
+
559:    @log.putc 'n'[0]
+
560:    @log.putc 'd'[0]
+
561:
+
562:    @log.putc ')'[0]
+
563:    @l = line.to_s
+
564:    @l.each_byte{|ch|
+
565:      @log.putc ch
+
566:      if ch == 60
+
567:        @log.putc 32
+
568:      end
+
569:    }
+
570:    @log.puts
+
571:    @log.close
+
572:    @log = nil
+
573:  end
+
574:end
+
575:
+
576:
+
577:
+
578:#####################
+
579:### PLCBUS OBJECT ###
+
580:#####################
+
581:# This is a generic replaceable object
+
582:# This object needs the following methods:
+
583:#
+
584:# Initialize()
+
585:#
+
586:#  What it does:
+
587:#    any Object initialization you may need.
+
588:#   
+
589:#  When is this called:
+
590:#    Upon Object creation.
+
591:#   
+
592:#  What you will get:
+
593:#    nothing.
+
594:#   
+
595:#  What you will return:
+
596:#    nothing.
+
597:#   
+
598:#
+
599:# dceCommandIn(cmd)
+
600:# 
+
601:#  What is does:
+
602:#    sends you a command object to allow you to create gsdOut().
+
603:#   
+
604:#  What you will get:
+
605:#    cmd (Command Object)
+
606:# 
+
607:#  What you need to return:
+
608:#    nothing (ignored)
+
609:#   
+
610:#  When you will get this:
+
611:#    executed when a new DCE command is sent to you.
+
612:#
+
613:#   
+
614:# dceResponseIn(cmd)
+
615:# 
+
616:#  What it does:
+
617:#    Sends you a DCE object to compare with the command.
+
618:#   
+
619:#  What you will get:
+
620:#    cmd (Command Object)
+
621:# 
+
622:#  What you need to return:
+
623:#    TRUE if you accept this response.
+
624:#    FALSE if you do NOT accept this response.
+
625:#   
+
626:#  When you will get this:
+
627:#    executed when a new DCE response is ready.
+
628:#
+
629:#
+
630:# gsdCommandIn(value)
+
631:# 
+
632:#  What it does:
+
633:#    sends you a String to allow you to create a dceOut().
+
634:#   
+
635:#  What you will get:
+
636:#    value (String Object)
+
637:# 
+
638:#  What you need to return:
+
639:#    nothing (ignored)
+
640:#   
+
641:#  When you will get this:
+
642:#    executed when a new GSD command is sent to you.
+
643:#
+
644:#   
+
645:# gsdResponseIn(value)
+
646:#
+
647:#  What it does:
+
648:#    Sends you a GSD Response to compare with the command. 
+
649:#  What you will get:
+
650:#    cmd (Command Object)
+
651:# 
+
652:#  What you need to return:
+
653:#    TRUE if you accept this response.
+
654:#    FALSE if you do NOT accept this response.
+
655:#   
+
656:#  When you will get this:
+
657:#    executed when a new GSD response is ready.
+
658:#
+
659:# dceout()
+
660:# 
+
661:#  What it does:
+
662:#    Creates a Command Object to send to DCE.
+
663:#
+
664:#  What you will get:
+
665:#    nothing.
+
666:#   
+
667:#  What you need to return:
+
668:#    a Command Object representing the previous gsdCommandIn.
+
669:#
+
670:#  When is this called:
+
671:#    After a gsdCommandIn has been sent.
+
672:# gsdout()
+
673:#
+
674:#  What it does:
+
675:#    creates a String Object to send to GSD.
+
676:#   
+
677:#  What you will get:
+
678:#    nothing.
+
679:#   
+
680:#  What you will return:
+
681:#    a String Object representing the previous dceCommandIn.
+
682:#
+
683:#  When is this called:
+
684:#    After a dceCommandIn has been sent.
+
685:#
+
686:#
+
687:# Properties:
+
688:#
+
689:# @responseAccepted
+
690:# 
+
691:#  What it does:
+
692:#    signals that the current response is accepted as valid.
+
693:# 
+
694:#  When you should set this:
+
695:#
+
696:# @responseNeeded
+
697:#
+
698:#  What it does:
+
699:#    signals when you need a response.       
+
700:# 
+
701:# @commandHolder
+
702:#
+
703:#  What it does:
+
704:#    If you need to create a new command, this is the holder for it.
+
705:#
+
706:
+
707:class PLCBUS
+
708:  attr_reader :responseAccepted, :responseNeeded, :commandHolder, :threaded
+
709:  #Conatants:
+
710:  STX=0x02.chr
+
711:  ETX=0x03.chr
+
712:  HomeCodes = {'A'=>0b0000,'B'=>0b0001,'C'=>0b0010,'D'=>0b0011,'E'=>0b0100,'F'=>0b0101,'G'=>0b0110,'H'=>0b0111,'I'=>0b1000,'J'=>0b1001,'K'=>0b1010,'L'=>0b1011,'M'=>0b1100,'N'=>0b1101,'O'=>0b1110,'P'=>0b1111}
+
713:  UnitCodes = {'1'=>0b0000,'2'=>0b0001,'3'=>0b0010,'4'=>0b0011,'5'=>0b0100,'6'=>0b0101,'7'=>0b0110,'8'=>0b0111,'9'=>0b1000,'10'=>0b1001,'11'=>0b1010,'12'=>0b1011,'13'=>0b1100,'14'=>0b1101,'15'=>0b1110,'16'=>0b1111}
+
714:  CommandFunctions = {0x00=>'ALL UNIT OFF',0x01=>'ALL LTS ON',0x02=>'ON',0x03=>'OFF',0x04=>'DIM',0x05=>'BRIGHT',0x06=>'ALL LIGHT OFF',0x07=>'ALL USER LTS ON',0x08=>'ALL USER UNIT OFF',0x09=>'ALL USER LIGHT OFF',0x0A=>'BLINK',0x0B=>'FADE STOP',0x0C=>'PRESETDIM',0x0D=>'STATUS ON',0x0E=>'STATUS OFF',0x0F=>'STATUS REQ',0x10=>'(R)MASTER ADDRS SETUP',0x11=>'(T)MASTER ADDRS SETUP',
+
715:    0x12=>'SCENES ADDRS SETUP',0x13=>'SCENES ADDRS ERASE',0x14=>'ALL SCENES ADDRS ERASE',0x15=>'FOR FUTURE',0x16=>'FOR FUTURE',0x17=>'FOR FUTURE',0x18=>'GET SIGNAL STRENGTH',0x19=>'GET NOISE STRENGTH',0x1A=>'REPORT SIGNAL STRENGTH',0x1B=>'REPORT NOISE STRENGTH',0x1C=>'GET ALL ID PULSE',0x1D=>'GET ONLY ON ID PULSE',0x1E=>'REPORT ALL ID PULSE',0x1F=>'REPORT ONLY ON PULSE'}
+
716:
+
717: 
+
718:  def initialize()
+
719:    # declare gsd variables
+
720:    @home = 0 #these two varianles determine the TO or FROM address
+
721:    @unit = 0 #these two variables determine the TO or FROM address
+
722:    @command = 0
+
723:    @usercode = $me.devdata[59].to_i
+
724:    #@cmdReprq = $me.devdata[260]      #3Phase on Dan's system
+
725:    @cmdReprq = $me.devdata[249]      #3Phase on Hari's system
+
726:    @data1 = 0
+
727:    @data2 = 0
+
728:    @cmdAckPulse = false
+
729:    @cmdLink = false
+
730:    #declare DCE variables
+
731:    @dceto = 0
+
732:    @dcefrom = 0
+
733:    @dcepriority = 0
+
734:    @dcecmdtype = 0
+
735:    @dcecmdid = 0
+
736:    @dceparams = {}
+
737:    @responseNeeded = false
+
738:    @responseAccepted = false
+
739:    @gsdparams = {}
+
740:    #@gsdparams[120] = '1' # hack to force command is useless...
+
741:    @commandHolder = nil
+
742:    #log('Leaving Initialize')
+
743:    @threaded = true
+
744:  end
+
745:  def dceCommandIn(cmd)
+
746:    log('dceCommandIn Entered:')
+
747:    @dcehomeunit = $devices[cmd.devidto_].devdata[12][0..1]
+
748:    @dcehome = HomeCodes[$devices[cmd.devidto_].devdata[12][0].chr].to_s
+
749:    @dceunit = UnitCodes[$devices[cmd.devidto_].devdata[12][1].chr].to_s
+
750:    @dcefrom = cmd.devidfrom_
+
751:    @dceto = cmd.devidto_
+
752:    @dcepriority = cmd.priority_
+
753:    @dcecmdtype = cmd.type_
+
754:    @dcecmdid = cmd.id_
+
755:    @dceparams = cmd.params_
+
756:
+
757:  end
+
758:  def dceResponseIn(cmd)                                        # Returns TRUE if response is accepted.
+
759:    log('dceResponseIn Entered:')
+
760:    log(cmd.inspect)
+
761:    return true                          #ignored in PLCBUS
+
762:  end
+
763:  def gsdCommandIn(value)
+
764:    log('gsdCommandIn Entered:')
+
765:    debug('Value:', value)
+
766:    @gsdusercode = value[2]
+
767:    @gsdhomeunit = ("%X" %value[3])
+
768:    @gsdhome = @gsdhomeunit[0].chr
+
769:    @gsdunit = @gsdhomeunit[1].chr
+
770:    @gsdcommand = value[4]
+
771:    @gsdcmdAckPulse = true if (value[4] & 0x20) == 0x20
+
772:    @gsdcmdReprq = true if (value[4] & 0x40) == 0x40
+
773:    @gsdcmdLink = true if (value[4] & 0x80) == 0x80
+
774:    @gsddata1 = value[5]
+
775:    @gsddata2 = value[6]
+
776:    if value[1] == 6
+
777:      rxtxSwitchRegister(value[7])  #set switches if they exist
+
778:    end
+
779:  end
+
780:  def gsdResponseIn(value)                                      #returns TRUE if response is accepted.
+
781:    #no need to store response.. just compare.
+
782:    #negative logic here
+
783:    @result = true
+
784:    #log('gsdResponseIn Entered:')
+
785:    #debug('Value:', value)
+
786:    if @usercode == value[2]
+
787:      #log('Usercode Check!')
+
788:    else
+
789:      log('Usercode compare failed')
+
790:      @result = false
+
791:    end
+
792:    if dcehomeunit[0] == value[3]
+
793:      #log('Home and Unit CHECK!')
+
794:    else
+
795:      log('Home and Unit compare failed')
+
796:      @result = false
+
797:    end
+
798:    if dcecommand(@dcecmdid)[0] == value[4]
+
799:      #log('PLCBus Command CHECK!')
+
800:    else
+
801:      log('PLCBus Command compare failed')
+
802:      @result = false
+
803:    end
+
804:    if value[1] == 6
+
805:      #log('Setting rxtxRegister')
+
806:      rxtxSwitchRegister(value[7])
+
807:    else
+
808:      log('no rxtxRegister')
+
809:      @result = false
+
810:    end
+
811:    #log('gsdResponseIn returning TRUE') if @result == true
+
812:    #log('gsdResponseIn returning FALSE') if @result == false
+
813:    return @result
+
814:  end
+
815:  def dceout                                                    # Returns the GSD values as a DCE command.
+
816:    @myfrom = gsdhomeunit
+
817:    if @myfrom == 0
+
818:      log('I DONT KNOW THIS DEVICE ID')
+
819:    else
+
820:      @mycommandout = gsdcommand
+
821:      log('IN PLCBUS:DCEOUT')
+
822:      log('        From: ' + @myfrom.to_s)
+
823:      log('          To: -1001')
+
824:      log('    Priority: 1')
+
825:      log('      CmdType: 2')
+
826:      log('        CmdId: ' + @mycommandout.to_s)
+
827:      log('Devdata Below:')
+
828:      @gsdparams.each_pair{|k,v|
+
829:        log('    devdata_[' + k.to_s + '] = ' + v)
+
830:      }
+
831:      @cmdout = Command.new(@myfrom, -1001, 1, 2, @mycommandout)
+
832:      @gsdparams.each_pair{|k,v| @cmdout.params_[k]=v}
+
833:      #      @responseNeeded = false
+
834:      #      @responseAccepted = true
+
835:      return @cmdout
+
836:    end
+
837:  end
+
838:  def gsdout                                                    # Returns the DCE values as a gsd string
+
839:    #log('IN PLCBUS:GSDOUT')
+
840:    log('SETTING THREADING to FALSE in PLCBUS:GSDOUT:')
+
841:    @threaded = false
+
842:    @gsdout = @usercode.chr
+
843:    @gsdout += dcehomeunit + dcecommand(@dcecmdid) + @data1.chr + @data2.chr
+
844:    @gsdout = @gsdout.length.chr + @gsdout
+
845:    @gsdout = STX + @gsdout + ETX
+
846:    #debug('Data Out', @gsdout)
+
847:    return @gsdout
+
848:  end
+
849:  def checkResponse(cmd)  #old?? fired when a response was accepted.
+
850:    log('WARNING: CheckResponse was CALLED')
+
851:    #    #this routine needs to set ONE flag:
+
852:    #    #responseNeeded (true/false) if we need more data
+
853:    #    if cmd.class.to_s == 'String'
+
854:    #      #we are checking a GSD command.
+
855:    #
+
856:    #    end
+
857:    #    if cmd.class == Command
+
858:    #      #we are checking a DCE command.
+
859:    #      if @r_ack_sw == true
+
860:    #        #here is a good place to check the data1 and data2 values
+
861:    #        #to make sure the proper device responded.
+
862:    #        #
+
863:    #        #PLCBUS command complete
+
864:    #        log('Received Ack from PLCBUS device.')
+
865:    #        @responseNeeded = false
+
866:    #        # attempt to set device info here.
+
867:    #        case @dcecmdid
+
868:    #        when 192 # ON
+
869:    #          $devices[@dceto].onoff = "ON"
+
870:    #          if $devices[@dceto].level != 100
+
871:    #            $devices[@dceto].level = 100
+
872:    #            log('HAVE TO SEND A SETLEVEL=100')
+
873:    #          end
+
874:    #        when 193 # OFF
+
875:    #          $devices[@dceto].onoff = "OFF"
+
876:    #          if $devices[@dceto].level != 0
+
877:    #            $devices[@dceto].level = 0
+
878:    #            log('HAVE TO SEND A SETLEVEL = 0')
+
879:    #            log('**************************')
+
880:    #            log('**************************')
+
881:    #            log('**************************')
+
882:    #            log('**************************')
+
883:    #            @commandHolder = RubyCommand.new()
+
884:    #            #pack a new DCE command with the Event..
+
885:    #            @mycmd = Command.new(@dceto, @dceto, 1, 1, 184)
+
886:    #            @mycmd.params_[76] = '0'
+
887:    #            @commandHolder.packCommand(@mycmd)
+
888:    #
+
889:    #          end
+
890:    #        when 184 # SetLevel
+
891:    #          if @dceparams[76].to_i == 0
+
892:    #            #dimming to OFF
+
893:    #            if $devices[@dceto].onoff == 'ON'
+
894:    #              log('HAVE TO SEND AN OFF to DCE')
+
895:    #              log('**************************')
+
896:    #              log('**************************')
+
897:    #              log('**************************')
+
898:    #              log('**************************')
+
899:    #              @commandHolder = RubyCommand.new()
+
900:    #              #pack a new DCE command with the Event..
+
901:    #              @mycmd = Command.new(@dceto, -1001, 1, 2, 40)
+
902:    #              @mycmd.params_[10] = '0'
+
903:    #              @commandHolder.packCommand(@mycmd)
+
904:    #              #
+
905:    #             
+
906:    #              #@commandHolder = Command.new(@dcefrom, -1001, 1, 2, 40)
+
907:    #              #@commandHolder.params_[10] = '0'
+
908:    #              $devices[@dceto].onoff = 'OFF'
+
909:    #             
+
910:    #            end
+
911:    #             
+
912:    #          else
+
913:    #            #dimming to ON
+
914:    #            if $devices[@dceto].onoff == 'OFF'
+
915:    #              log('HAVE TO SEND AN ON to DCE')
+
916:    #              log('**************************')
+
917:    #              log('**************************')
+
918:    #              log('**************************')
+
919:    #              log('**************************')
+
920:    #              @commandHolder = RubyCommand.new()
+
921:    #              @mycmd = Command.new(@dceto, -1001, 1, 2, 40)
+
922:    #              @mycmd.params_[10] = '1'
+
923:    #              @commandHolder.packCommand(@mycmd)
+
924:    #              #@commandHolder = Command.new(@dcefrom, -1001, 1, 2, 40)
+
925:    #              #@commandHolder.params_[10] = '1'
+
926:    #
+
927:    #              $devices[@dceto].onoff = 'ON'
+
928:    #            end
+
929:    #          end
+
930:    #          $devices[@dceto].level = @dceparams[76].to_i
+
931:    #        end
+
932:    #        log('Device:' + @dceto.to_s)
+
933:    #        log('on/off:' + $devices[@dceto].onoff)
+
934:    #        log(' level:' + $devices[@dceto].level.to_s)
+
935:    #      end
+
936:    #      if @r_itself == true
+
937:    #        #heard myself send the response.
+
938:    #        log('I heard myself send the command properly.')
+
939:    #        @responseNeeded = true
+
940:    #      end
+
941:    #
+
942:    #    end
+
943:    @responseAccepted = true
+
944:  end
+
945:  #Support Routines for PLCBUX
+
946:  def dcecommand(value) #DCE value is DCE Command.
+
947:    #user code is in devdata[59] Configuration
+
948:    #devdata[250] 3phase (boolean)
+
949:    @work = 0
+
950:    #log('DCE Command is' + value.to_s)
+
951:    case value
+
952:    when 192 #ON
+
953:
+
954:      @cmdLink = false
+
955:      @cmdReprq = false
+
956:      @cmdAckPulse = true
+
957:      @data1 = 0 #Fade Rate
+
958:      @work = 0x80 if @cmdling == true
+
959:      @work += 0x40 if @cmdReprq == true
+
960:      @work += 0x20 if @cmdAckPulse == true
+
961:      @command =@work + CommandFunctions.index("ON")
+
962:    when 193 #OFF
+
963:      @cmdLink = false
+
964:      @cmdReprq = false
+
965:      @cmdAckPulse = true
+
966:      @data1 = 0 #Fade Rate
+
967:      @work = 0x80 if @cmdling == true
+
968:      @work += 0x40 if @cmdReprq == true
+
969:      @work += 0x20 if @cmdAckPulse == true
+
970:      @command =@work + CommandFunctions.index("OFF")
+
971:    when 184 # SETLEVEL
+
972:      @cmdLink = false
+
973:      @cmdReprq = false
+
974:      @cmdAckPulse = true
+
975:      @data1 = @dceparams[76].to_i #dim level
+
976:      @data2 = 2 #Fade Rate
+
977:      @work = 0x80 if @cmdling == true
+
978:      @work += 0x40 if @cmdReprq == true
+
979:      @work += 0x20 if @cmdAckPulse == true
+
980:      @data2 = 2#Fade Rate
+
981:      @command =@work + CommandFunctions.index("PRESETDIM")
+
982:    end
+
983:    #how convert it into a integer - currently it a HEX string.
+
984:    #log('PLC Command is:' + @command.to_s + 'DECIMAL')
+
985:    return @command.chr
+
986:  end
+
987:  def gsdcommand #returns DCE EVENT!! and compiles params
+
988:
+
989:    #log('IN DCECommand')
+
990:   
+
991:    case CommandFunctions[@gsdcommand]
+
992:    when 'ALL UNIT OFF'
+
993:      @gsdparams[10] = '0'
+
994:      return 48
+
995:    when 'ALL LTS ON'
+
996:      @gsdparams[10] = '1'
+
997:      return 48
+
998:    when 'ON'
+
999:      @gsdparams[10] = '1'
+
1000:      return 48
+
1001:    when 'OFF'
+
1002:      @gsdparams[10] = '0'
+
1003:      return 48
+
1004:    when 'DIM'
+
1005:      @gsdparams[10] = @gsddata1 # set Brightness
+
1006:      return 48
+
1007:
+
1008:    when 'BRIGHT'
+
1009:      @gsdparams[10] = @gsddata1 # set Brightness
+
1010:      return 48
+
1011:
+
1012:    when 'ALL LIGHT OFF'
+
1013:      @gsdparams[10] = '0'
+
1014:      return 48
+
1015:    when 'ALL USER LTS ON'
+
1016:      @gsdparams[10] = '1'
+
1017:      return 48
+
1018:    when 'ALL USER UNIT OFF'
+
1019:      @gsdparams[10] = '0'
+
1020:      return 48
+
1021:    when 'ALL USER LIGHT OFF'
+
1022:      @gsdparams[10] = '0'
+
1023:      return 48
+
1024:    when 'BLINK'
+
1025:    when 'FADE STOP'
+
1026:    when 'PRESETDIM'
+
1027:      @gsdparams[10] = @gsddata1
+
1028:      return 48
+
1029:    when 'STATUS ON'
+
1030:    when 'STATUS OFF'
+
1031:    when 'STATUS REQ'
+
1032:    when '(R)MASTER ADDRS SETUP'
+
1033:    when '(T)MASTER ADDRS SETUP'
+
1034:    when 'SCENES ADDRS SETUP'
+
1035:    when 'SCENES ADDRS ERASE'
+
1036:    when 'ALL SCENES ADDRS ERASE'
+
1037:    when 'FOR FUTURE'
+
1038:    when 'GET SIGNAL STRENGTH'
+
1039:    when 'GET NOISE STRENGTH'
+
1040:    when 'REPORT SIGNAL STRENGTH'
+
1041:    when 'REPORT NOISE STRENGTH'
+
1042:    when 'GET ALL ID PULSE'
+
1043:    when 'GET ONLY ON ID PULSE'
+
1044:    when 'REPORT ALL ID PULSE'
+
1045:    when 'REPORT ONLY ON PULSE'
+
1046:    else
+
1047:      log('UNKNOWN COMMAND RESPONSE in PLCBUS OBJECT')
+
1048:      return 0
+
1049:    end
+
1050:
+
1051:  end
+
1052:  def dcehomeunit() # returns GSD homeunit byte from DCE homeunit
+
1053:    @work = @dcehome + @dceunit
+
1054:    return (@work.hex.chr)
+
1055:  end
+
1056:  def gsdhomeunit() #returns DCE Child ID from gsd homeunit
+
1057:    #@gsdhomeunit holds the data
+
1058:    @work = HomeCodes.index(@gsdhomeunit[0].chr.to_i)
+
1059:    @work += UnitCodes.index(@gsdhomeunit[1].chr.to_i)
+
1060:    return $devices.find(@work)
+
1061:  end
+
1062:  def rxtxSwitchRegister(value)
+
1063:    #log('setting RX_TX_SWITCH')
+
1064:    if (value & 0x40) == 0x40
+
1065:      #log('r_id_sw is set')
+
1066:      @r_id_sw = true
+
1067:    else
+
1068:      #log('r_id_sw is reset')
+
1069:      @r_id_sw = false
+
1070:    end
+
1071:    if (value & 0x20) == 0x20
+
1072:      #log('r_ack_sw is set')
+
1073:      @r_ack_sw = true
+
1074:      @responseNeeded = false
+
1075:    else
+
1076:      #log('ResponseNeeded set to TRUE')
+
1077:      @responseNeeded = true
+
1078:      #log('r_ack_sw is reset')
+
1079:      @r_ack_sw = false
+
1080:    end
+
1081:    if (value & 0x10) == 0x10
+
1082:      #log('r_itself is set')
+
1083:      @r_itself = true
+
1084:      log('I heard myself Transmit this command on the PLCBUS.')
+
1085:    else
+
1086:      #log('r_itself is reset')
+
1087:      @r_itself = false
+
1088:      log('This Command is transmitted from an OUTSIDE SOURCE!')
+
1089:    end
+
1090:    if (value & 0x8) == 0x8
+
1091:      #log('r_risc is set')
+
1092:      @r_risc = true
+
1093:    else
+
1094:      #log('r_risc is reset')
+
1095:      @r_risc = false
+
1096:    end
+
1097:    if (value & 0x4) == 0x4
+
1098:      #log('r_sw is set')
+
1099:      @r_sw = true
+
1100:    else
+
1101:      #log('r_sw is reset')
+
1102:      @r_sw = false
+
1103:    end
+
1104:   
+
1105:  end
+
1106:  #Generic Support Routines
+
1107:  def log(line)
+
1108:    @log = File.open("/var/log/pluto/" + $me.deviceid.to_s + "_Generic_Serial_Device.log", "a")
+
1109:    @log.putc '('[0]
+
1110:    @log.putc 'P'[0]
+
1111:    @log.putc 'L'[0]
+
1112:    @log.putc 'C'[0]
+
1113:    @log.putc ')'[0]
+
1114:    @l = line.to_s
+
1115:    @l.each_byte{|ch|
+
1116:      @log.putc ch
+
1117:      if ch == 60
+
1118:        @log.putc 32
+
1119:      end
+
1120:    }
+
1121:    @log.puts
+
1122:    @log.close
+
1123:    @log = nil
+
1124:  end
+
1125:  def debug(label, text)
+
1126:    work = label + ":"
+
1127:    for c in 1..text.length
+
1128:      work += padhex("%X" %text[c-1]) + ' '
+
1129:    end
+
1130:    log(BLUE + work + "Length:" + text.length.to_s + GREY)
+
1131:  end
+
1132:  def padhex(hex)
+
1133:    if hex.length==1
+
1134:      hex = "0" + hex
+
1135:    end
+
1136:    return hex
+
1137:  end
+
1138:end
+
1139:def cmd_ReceiveCommandForChild(cmd)
+
1140:### #484 Process Receive Command for Child
+
1141:log('DCE Command Received')
+
1142:
+
1143:dataIn(cmd)
+
1144:end
+
1145:#### 760 ####################################################################
+
1146:def cmd_760(id, pk_command, parameters, cmd=nil)
+
1147:@returnParamArray.clear
+
1148:log('DCE Send Command to Child 760 Received')
+
1149:
+
1150:dcein760(cmd)
+
1151:return @returnParamArray
+
1152:end
+
1153:#### 776 ####################################################################
+
1154:def cmd_776(arguments, cmd=nil)
+
1155:@returnParamArray.clear
+
1156:#Simulate a gsdin command...
+
1157:#[31mIN:02 06 22 30 02 64 00 0C 03 Length:9
+
1158:@simulation = 0x02.chr + 0x06.chr + 0x22.chr + 0x30.chr + 0x02.chr
+
1159:@simulation += 0x64.chr + 0x00.chr + 0x0C.chr + 0x03.chr
+
1160:log(AQUA + 'sending Simulated PLCBUS Command' + GREY)
+
1161:debugin(@simulation)
+
1162:dataIn(@simulation)
+
1163:return @returnParamArray
+
1164:end
+
1165:#### START SETTERS ####################################################################
+
1166:def initialize()
+
1167:super
+
1168:@returnParamArray=Array.new
+
1169:end
+
1170:####  END  SETTERS ####################################################################
+
1171:end
+
</pre>
+
  
 
= Links =
 
= Links =
 
* http://www.plcbus.com.cn/
 
* http://www.plcbus.com.cn/
 
* http://www.futurehomes.com.sg/PLCBUSinfo.htm
 
* http://www.futurehomes.com.sg/PLCBUSinfo.htm

Latest revision as of 01:20, 28 September 2015

Version Status Date Updated Updated By
710 Unknown N/A N/A
810 Working 1st May 2010 BongoWongo
1004 Unknown N/A N/A
1204 Unknown N/A N/A
1404 Unknown N/A N/A
Usage Information
Plcbus-logo.jpg

Status

We've implemented a new C++ driver for 0810b2. More information here: http://forum.linuxmce.org/index.php?topic=11170.0

About

PLCBUS Technology provides you the most perfect Home Automation solutions. Control one lamp minimally to the whole house, all the PLCBUS products range is including Lamp control, Appliance control, Remote telephone control, Computer control and Security System control. Based on the features: “High Reliability”, “Two-Way Communications”, “No rewiring necessary”, etc, PLCBUS Technology will be new Home Automation standard in the following 10-15 years.

Demo video:

Features

  • Reliability
  • 2-way communication
  • Powerline, no rewiring
  • ~200bps
  • 230V/50hz

Interfaces

Command specification


Links