[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}
]
]
]
]