Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] X.10 serial port control from Rebol

From: parki::whatevernot::com at: 6-Sep-2003 18:11

My first 'real' Rebol script - this is a certainly unfinished script which controls my X.10 lights in my house - with simple commands I can turn on and off lights on the X.10 circuit in my house. I have looked at this in C (working with a developer to port to Mac OS X) as well as Perl and Java, and can certainly say that the Rebol approach, which built in serial:// protocol, makes life a snap. This also contains some playing around with the notions of Singleton idiom and data hiding. It's likely overkill. I am posting it here as people might be interested, and I welcome any feedback on style and whatevernot. Cheers, parki... --- x8 snip REBOL [ Title: "CM11A X.10 serial controller" Author: "Brian Parkinson" Email: [parki--whatevernot--com] Date: 6-Sep-2003 File: %cm11a.r Version: 0.1.0 Purpose: "Support simple access to an X.10 controller to turn lights on and off." History: [ 0.1.0 [6-Sep-2003 "First cut."] ] Comment: { Example usage: x: cm11a ; Initialize the interface to the CM11A controller x/ex 3 'on ; Turn on light 3 in default house code #"A" x/houseCode #"B" ; Set the house code to #"B" x/ex 4 'off ; Turn off light 4 in house code #"B" x/deinit ; Deinitialize the controller when all are done with it Should be mentioned that at of this version (0.1.0) I have only really tested that lights on and off work - more features can be added. This is based around a singleton idiom that is somewhat nifty - data hiding is implemented. To make this work on a different machine, you will almost certainly have to change the set to system/ports/serial in the cm11aInit function. } ] ; The use construct allows us to hide a number of variable and functions and in so ; doing provide some nice data hiding ; use [ privateCtor instance_ cm11aInit cm11aSend serialPort_ HOUSE_CODES DEVICE_CODES FUNCTION_CODES ] [ ; The singleton instance which ensures that we only create one object ; instance_: false ; Define our constants based on the CM11A protocol ; HOUSE_CODES: [ 96 224 32 160 16 144 80 208 112 240 48 176 0 128 64 192 ] DEVICE_CODES: [ 6 14 2 10 1 9 5 13 7 15 3 11 0 8 4 12 ] FUNCTION_CODES: [ all-units-off all-lights-on on off dim bright all-lights-off extended hail-request hail-acknowledge preset-dim1 preset-dim2 extended-data status-on status-off status-request ] ; The function which returns the global singleton instance of the CM11A controller ; cm11a: func [] [ either instance_ [ instance_ ] [ instance_: privateCtor ] ] ; Private func inits serial port connection to the CM11A controller - called from ; the private constructor so we only init the connection when the cm11a object ; is constructed, and not at script load time ; cm11aInit: func [] [ ; /dev/cu.USA19QI14P1.1 is the serial device for X.10 on my machine ; See /dev on the machine for the name of this port ; system/ports/serial: [ cu.USA19QI14P1.1 ] ; The serial port contained by the singleton object ; Open the connection to the serial port serialPort_: open/binary/direct/no-wait serial://port1/4800/8/none/1 ; Turn off handshaking (required by CM11A controller) serialPort_/rts-cts: false update serialPort_ ] ; Private function to send a value to the CM11A controller ; Need to add in exception handling if fall through loop ; cm11aSend: func [ value /local reply ] [ insert serialPort_ value repeat count 100 [ wait 0.1 reply: copy serialPort_ if not reply = #{} [ return 0 ] ] -1 ] ; Private constructor which only gets called once upon first access ; privateCtor: func [] [ make object! [ ; The house code that this object will control - defaults to A but ; can be set with the houseCode function ; houseCode_: #"A" ; Initialize the CM11A controller ; cm11aInit ; When you are done with the serial port, you should call deinit to close ; the connection ; deinit: func [] [ close serialPort_ ] ; Set the current house code used by the controller ; houseCode: func [ houseCode [ char! ] "The house code character: A,...,P" ] [ houseCode_: houseCode ] ; The main entry point - ensure that the controller has been init'ed ; Example use: "ex 3 'on" ; ex: function [ deviceCode [ number! ] "Device code number: 1,..,16" funcWord [word!] "The function to run: 'on, 'off, etc" ] [ houseVal deviceVal functionVal addrHex funcHex ] [ houseVal: pick HOUSE_CODES (to-integer houseCode_) - (to-integer #"@") deviceVal: pick DEVICE_CODES deviceCode functionVal: (index? find FUNCTION_CODES funcWord) - 1 addrHex: debase/base (to-string copy/part at to-hex (1024 + houseVal + deviceVal) 5 4) 16 funcHex: debase/base (to-string copy/part at to-hex (1536 + houseVal + functionVal) 5 4) 16 ; Make the calls to the serial port ; cm11aSend addrHex cm11aSend #{00} cm11aSend funcHex cm11aSend #{00} ] ] ] ]