DECUServe VMS
Conference 3064.12
Note 3064.12 X10 / X-10 / BSR / Home Automation 12 of 15
EISNER::COVERT "John.Covert@Compaq.com" 411 lines 17-JAN-2000 18:23
-< CM11.BLI Version 2 >-
--------------------------------------------------------------------------------
module cm11 (main = start, addressing_mode(external=general))=
begin
require 'sys$library:starlet';
macro
dsc_0 (buffer) = $BBLOCK[8] INITIAL (LONG(128), LONG(BUFFER)) %;
external routine
lib$put_output;
forward routine
read_mailbox:novalue,
mailbox_ast:novalue,
next_command:novalue,
send_command:novalue,
timer_ast:novalue;
GLOBAL
checksum: byte,
justsent: initial(0),
awaitconfirm: initial(0),
needtosend: initial(0),
inputcoming: initial(0),
chan: initial(0),
mbxchan: initial(0),
mbxiosb: VECTOR[4,word],
cmdbuffer: VECTOR[2,byte],
cmdcount: initial(0),
cmdptr,
mbxbuffer: VECTOR[128,byte],
timeout: quad initial(0);
routine start =
begin
LOCAL
status,
iosb: VECTOR[4,word],
buffer: VECTOR[128,byte],
bufdesc: dsc_0(buffer),
ch: byte,
noterms: quad initial(0);
!
! Create a mailbox to receive commands we need to send out on the CM11
!
! Remember to issue the following command before starting this
! And also to have SYSNAM privilege so it will work
! $ DEFINE/TABLE=LNM$PROCESS_DIRECTORY LNM$TEMPORARY_MAILBOX LNM$SYSTEM
!
status = $crembx(
chan = mbxchan,
lognam = %ascid'CM11_MAILBOX'
);
if not .status then SIGNAL_STOP(.status);
!
! Start the timeout routine
timer_ast();
!
!
! Start the mailbox reading
!
read_mailbox();
status = $assign(devnam=%ascid'TERM_DEV',chan=chan);
if not .status then SIGNAL_STOP(.status);
!
! Read forever
!
while 1 do
begin
status = $qiow (
chan = .chan,
func = io$_readvblk,
iosb = iosb,
p1 = buffer,
p2 = 1);
if not .status then SIGNAL_STOP(.status);
if not .iosb[0] then signal_stop (.iosb[0]);
$setast(enbflg=0);
ch = .buffer[0];
!
! If we just sent something, this is supposed to be the checksum
!
if .justsent
then
begin
if .ch eqlu .checksum
then
begin
justsent = 0;
awaitconfirm = 1;
buffer[0] = 0; ! This command to the CM11 says OK!
status = $qiow (
chan = .chan,
func = io$_writevblk,
iosb = iosb,
p1 = buffer,
p2 = 1);
if not .status then SIGNAL_STOP(.status);
if not .iosb[0] then signal_stop (.iosb[0]);
end;
!
! Else we should send again, but do that a bit later
!
end;
!
! If the character indicates we have X10 data, go get it
!
if .ch eqlu %x'5A' and .ch nequ .checksum
then
begin
inputcoming = 1;
if .justsent or .awaitconfirm
then
begin
needtosend = 1; ! Sent command lost; we have to resend
timeout = 0; ! Don't do it in the timer
justsent = 0;
end;
buffer[0] = %x'C3'; ! This command to the CM11 gets the data
status = $qiow (
chan = .chan,
func = io$_writevblk,
iosb = iosb,
p1 = buffer,
p2 = 1);
if not .status then SIGNAL_STOP(.status);
if not .iosb[0] then signal_stop (.iosb[0]);
end;
!
! Format the output (we'll probably output it unless we had a count)
!
bufdesc[dsc$w_length]=128;
status = $fao (
%ascid'!%D !XB',
bufdesc[dsc$w_length],
bufdesc,
0,.ch);
if not .status then SIGNAL_STOP(.status);
!
! Continue with main loop waiting for response
!
if .inputcoming and .ch lequ 9 and .ch nequ 0 ! Expected response: count
then
begin
!
! Read the number of characters we were told to get
!
status = $qiow (
chan = .chan,
func = io$_readvblk,
iosb = iosb,
p1 = buffer[1],
p2 = .ch,
p4 = noterms);
if not .status then SIGNAL_STOP(.status);
if not .iosb[0] then signal_stop (.iosb[0]);
bufdesc[dsc$w_length]=128;
status = $fao (
%ascid'!%D !#(XB)',
bufdesc[dsc$w_length],
bufdesc,0,
.ch+1,
.ch,
.buffer[1],
.buffer[2],
.buffer[3],
.buffer[4],
.buffer[5],
.buffer[6],
.buffer[7],
.buffer[8],
.buffer[9],
);
if not .status then SIGNAL_STOP(.status);
inputcoming = 0;
end;
!
! Do some output (the received character or the received buffer)
!
status = lib$put_output(bufdesc);
if not .status then SIGNAL_STOP(.status);
!
! If the character indicates a powerfailure, reset the CM11 controller
!
if .ch eqlu %x'A5' and .ch nequ .checksum
then
begin
buffer[0] = %x'9B'; ! This tells the CM11 to shut up
buffer[1] = 0;
buffer[2] = 0;
buffer[3] = 0;
buffer[4] = 0;
buffer[5] = 0;
buffer[6] = 0;
! log it
status = $qiow (
chan = .chan,
func = io$_writevblk,
iosb = iosb,
p1 = buffer,
p2 = 7);
if not .status then SIGNAL_STOP(.status);
if not .iosb[0] then signal_stop (.iosb[0]);
bufdesc[dsc$w_length]=128;
status = $fao (
%ascid'!%D 00 Power restored',
bufdesc[dsc$w_length],
bufdesc,0);
status = lib$put_output(bufdesc);
if not .status then SIGNAL_STOP(.status);
end;
!
! Zap our memory of the checksum; if the checksum was %x'5A' we need to
! treat a repeat of the same character as the incoming data indicator
! instead. If it was %x'A5' we need to treat a repeat as the power
! failure indicator. If it _was_ the checksum, we're already done with it.
!
checksum = 0;
!
! If it's none of the above, and we just sent, then probably bad checksum
! Or, if input is no longer coming and we need to send, then it's probably
! then end of a receive, and now we can send.
!
if not .inputcoming and (.justsent or .needtosend)
then
send_command(); ! Send it again
!
! If the character indicates the previous command we sent has completed,
! then get ready for more commands.
!
if .ch eqlu %x'55' and .awaitconfirm
then
begin
timeout = 0;
awaitconfirm = 0;
next_command(); ! Get ready for the next command
end;
$setast(enbflg=1);
end; ! of endless loop
ss$_normal
end;
routine read_mailbox : novalue =
begin
local status;
status = $qio (
chan = .mbxchan,
func = io$_readvblk,
iosb = mbxiosb,
astadr = mailbox_ast,
p1 = mbxbuffer,
p2 = 128
);
if not .status then SIGNAL_STOP(.status);
end;
routine mailbox_ast : novalue =
begin
local
status;
if not .mbxiosb[0]
then
begin
if .mbxiosb[0] EQLU SS$_ENDOFFILE
then
begin
read_mailbox();
return;
end;
signal_stop (.mbxiosb[0]);
end
else
begin
if .mbxiosb[1]
then
begin
lib$put_output(%ascid'************************00 Odd bytect');
read_mailbox();
end
else
begin
cmdcount = .mbxiosb[1]/2;
cmdptr = mbxbuffer;
next_command();
end;
end;
end;
routine next_command: novalue =
begin
local
c0: byte,
c1: byte,
c2: byte,
status,
buffer: VECTOR[128,byte],
bufdesc: dsc_0(buffer);
if .cmdcount leq 0
then
begin
read_mailbox(); ! Get more commands
return;
end;
c0 = ..cmdptr;
cmdbuffer[0] = .c0;
cmdptr = .cmdptr+1;
c1 = ..cmdptr;
cmdbuffer[1] = .c1;
cmdptr = .cmdptr+1;
cmdcount = .cmdcount - 1;
if .inputcoming
then
needtosend = 1 ! Get it later
else
send_command();
!
! Now format local output
if .c0 eqlu 4 ! an address
then
begin
bufdesc[dsc$w_length]=128;
status = $fao (
%ascid'!%D*!#(XB)',
bufdesc[dsc$w_length],
bufdesc,0,
3,
2,
0,
.c1
);
if not .status then SIGNAL_STOP(.status);
end
else ! a function
begin
bufdesc[dsc$w_length]=128;
status = $fao (
%ascid'!%D*!#(XB)',
bufdesc[dsc$w_length],
bufdesc,0,
(if .c1<0,4,0> eqlu 4 or .c1<0,4,0> eqlu 5
then (c2 = .c0<3,5,0>;
status=3)
else status=2; .status+1), .status,
1,
.c1,
.c2
);
if not .status then SIGNAL_STOP(.status);
end;
lib$put_output(bufdesc);
end;
routine timer_ast: novalue =
begin
local
tvar: quad initial (-5000000), ! 1/2 second
current_time: quad,
status;
!
! Restart the AST for two seconds from now
!
$setimr(daytim = tvar, astadr = timer_ast);
if .timeout NEQU 0
then
begin
$gettim(timadr = current_time);
if .current_time GTRU .timeout
then
send_command(); ! Send it again
end;
end;
routine send_command: novalue =
begin
local
current_time: quad,
status;
justsent = 1;
checksum = .cmdbuffer[0] + .cmdbuffer[1];
! Send data; results will be processed in mainline code
status = $qiow (
chan = .chan,
func = io$_writevblk,
iosb = mbxiosb,
p1 = cmdbuffer,
p2 = 2);
if not .status then SIGNAL_STOP(.status);
if not .mbxiosb[0] then signal_stop (.mbxiosb[0]);
needtosend = 0;
$gettim(timadr = current_time);
timeout = .current_time + 20000000; ! Two seconds
end;
end
eludom
DECnotes Script provided by
Roland
Kessi, 21 February 1996