home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d8xx
/
d801
/
cyberx10.lha
/
CyberX10
/
Source
/
CyberX10.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-24
|
11KB
|
543 lines
/*
* CyberX10.c
*
* Copyright © 1992 by Christopher A. Wichura (caw@miroc.chi.il.us)
* All Rights Reserved.
*/
/* stuff for our ReadArgs() call */
#define ARG_TEMPLATE "TARGETS/M,ON/S,OFF/S,DIM/K/N,BASEHC/K,SETCLOCK/S,DIAG/S,DOWNLOAD/K,UPLOAD/K,DEVICE/K,UNIT/K/N,ATTEMPT/S"
enum ReadArgsArray {
ARG_TARGETS,
ARG_ON,
ARG_OFF,
ARG_DIM,
ARG_BASEHC,
ARG_SETCLOCK,
ARG_DIAG,
ARG_DOWNLOAD,
ARG_UPLOAD,
ARG_DEVICE,
ARG_UNIT,
ARG_ATTEMPT,
ARG_sizeof
};
const UBYTE HouseCode[16] =
{0x60, 0xE0, 0x20, 0xA0, 0x10, 0x90, 0x50, 0xD0, 0x70, 0xF0, 0x30, 0xB0, 0x00, 0x80, 0x40, 0xC0};
struct Library *IconBase;
struct Library *UtilityBase;
struct LocaleInfo LocaleInfo;
struct Locale *DefaultLocale;
int __regargs main(char *cmdptr, int cmdlen, struct WBStartup * WBMsg)
{
STRPTR WBArgs;
STRPTR ArgHelp;
LONG index;
extern UBYTE __far arg_help[];
extern UBYTE __far copyright[];
/*
* the first thing we do is try and open up the locale library and
* grab our catalog as we will need it if we want to print any error
* messages or other text
*/
if (LocaleInfo.li_LocaleBase = (APTR) OpenLibrary("locale.library", 38)) {
DefaultLocale = OpenLocale(NULL); /* autodocs say this is
* guarenteed a valid
* return */
LocaleInfo.li_Catalog = OpenCatalogA(NULL, "CyberX10.catalog", NULL);
}
/* try and open up utility.library */
if (UtilityBase = OpenLibrary("utility.library", 37)) {
if (ArgHelp = AllocVec(strlen(GetString(&LocaleInfo, MSG_ARG_HELP)) + strlen(GetString(&LocaleInfo, MSG_COPYRIGHT)) + strlen(PROGNAME) + strlen(VersionID) + 1, MEMF_CLEAR)) {
sprintf(ArgHelp, GetString(&LocaleInfo, MSG_ARG_HELP), PROGNAME, VersionID, GetString(&LocaleInfo, MSG_COPYRIGHT));
if (WBMsg) {
ErrorsToEzReq = TRUE;
if (IconBase = OpenLibrary("icon.library", 37)) {
for (index = (WBMsg->sm_NumArgs != 1 ? 1 : 0); index < WBMsg->sm_NumArgs; index++) {
if (WBArgs = WBtoCLIargs(&WBMsg->sm_ArgList[index], ARG_TEMPLATE)) {
DoInstance(WBArgs, NULL);
FreeVec(WBArgs);
}
}
CloseLibrary(IconBase);
}
}
else
DoInstance(NULL, ArgHelp);
FreeVec(ArgHelp);
}
CloseLibrary(UtilityBase);
}
else
ErrorMsg(MSG_COULDNT_OPEN, "utility.library");
if (LocaleInfo.li_LocaleBase) {
CloseCatalog(LocaleInfo.li_Catalog);
CloseLocale(DefaultLocale);
CloseLibrary((struct Library *) LocaleInfo.li_LocaleBase);
}
}
/* actually proccess the argument line and do what was requested */
void DoInstance(STRPTR ArgLine, STRPTR ArgHelp)
{
struct RDArgs *RArgs, *MyRArgs;
STRPTR ArgArray[ARG_sizeof];
STRPTR SerDevice;
ULONG SerUnit;
/* do the stuff needed to call ReadArgs to parse the command line */
memset(ArgArray, 0, sizeof(ArgArray));
if (MyRArgs = AllocDosObject(DOS_RDARGS, TAG_DONE)) {
if (ArgLine) {
MyRArgs->RDA_Source.CS_Buffer = ArgLine;
MyRArgs->RDA_Source.CS_Length = strlen(ArgLine);
MyRArgs->RDA_Source.CS_CurChr = 0L;
}
if (ArgHelp)
MyRArgs->RDA_ExtHelp = ArgHelp;
else
MyRArgs->RDA_Flags |= RDAF_NOPROMPT;
if (RArgs = ReadArgs(ARG_TEMPLATE, (LONG *) & ArgArray, MyRArgs)) {
if (ArgArray[ARG_DEVICE])
SerDevice = ArgArray[ARG_DEVICE];
else
SerDevice = "serial.device";
if (ArgArray[ARG_UNIT])
SerUnit = *((LONG *) ArgArray[ARG_UNIT]);
else
SerUnit = 0;
if (OpenTimer()) {
if (OpenSerial(SerDevice, SerUnit, (BOOL) ArgArray[ARG_ATTEMPT])) {
if (ArgArray[ARG_ON])
X10TurnOn((STRPTR *) ArgArray[ARG_TARGETS]);
else if (ArgArray[ARG_OFF])
X10TurnOff((STRPTR *) ArgArray[ARG_TARGETS]);
else if (ArgArray[ARG_DIM])
X10Dim((STRPTR *) ArgArray[ARG_TARGETS], *((LONG *) ArgArray[ARG_DIM]));
else if (ArgArray[ARG_BASEHC])
X10SetBaseHC(ArgArray[ARG_BASEHC]);
else if (ArgArray[ARG_SETCLOCK])
X10SetClock();
else if (ArgArray[ARG_DIAG])
X10Diagnostic();
else if (ArgArray[ARG_DOWNLOAD])
X10Download(ArgArray[ARG_DOWNLOAD]);
else if (ArgArray[ARG_UPLOAD])
X10Upload(ArgArray[ARG_UPLOAD]);
else
ErrorMsg(MSG_NOTHING_TO_DO);
CloseSerial();
}
else
ErrorMsg(MSG_NO_SER_DEV, SerDevice, SerUnit);
CloseTimer();
}
else
ErrorMsg(MSG_NO_TIMER);
FreeArgs(RArgs);
}
else
PrintFault(IoErr(), PROGNAME);
FreeDosObject(DOS_RDARGS, MyRArgs);
}
else
ErrorMsg(MSG_NO_RDARGS);
}
/* turn on the selected X10 units */
void X10TurnOn(STRPTR * Targets)
{
OnOffDimHandler(Targets, 0, 2, MSG_TURN_ON);
}
/* turn off the selected X10 units */
void X10TurnOff(STRPTR * Targets)
{
OnOffDimHandler(Targets, 0, 3, MSG_TURN_OFF);
}
/* set the selected targets to the specified dim level */
void X10Dim(STRPTR * Targets, ULONG DimLevel)
{
if (DimLevel < 1 || DimLevel > 16) {
ErrorMsg(MSG_INVALID_DIM_LEVEL, DimLevel);
return;
}
DimLevel--;
OnOffDimHandler(Targets, DimLevel, 5, MSG_DIM);
}
/* loop that handles X10TurnOn, X10TurnOff and X10Dim */
void OnOffDimHandler(STRPTR * Targets, ULONG DimLevel, ULONG Function, LONG Msg)
{
int hc;
int unit;
UBYTE *currentTarget;
if (!Targets)
ErrorMsg(MSG_NO_UNITS_SPECIFIED);
else
do {
currentTarget = *Targets;
hc = X10GetHC(*currentTarget++);
if (hc == -1)
ErrorMsg(MSG_INVALID_UNIT, *Targets);
else {
unit = atol(currentTarget);
if (unit < 1 || unit > 16)
ErrorMsg(MSG_INVALID_UNIT, *Targets);
else {
unit--;
if (!(X10SendDirectCmd(hc, unit, Function, DimLevel)))
ErrorMsg(MSG_CP290_ERROR_DIRECT, GetString(&LocaleInfo, Msg), *Targets);
}
}
Targets++;
} while (*Targets);
}
/* set the base housecode for the buttons on the controller unit */
void X10SetBaseHC(STRPTR BaseHC)
{
int hc;
UBYTE Buf[18];
if (!BaseHC)
ErrorMsg(MSG_NO_BASE_HC);
else {
hc = X10GetHC(BaseHC[0]);
if (hc == -1)
ErrorMsg(MSG_INVALID_BASE_HC, BaseHC[0]);
else {
memset(Buf, 0xFF, 16);
Buf[16] = 0;
Buf[17] = HouseCode[hc];
ClearSerial();
SerWrite(Buf, 18);
if (!X10WaitForAck(FALSE))
ErrorMsg(MSG_CP290_ERROR_BASEHC);
}
}
}
/* set the controller unit's clock */
void X10SetClock(void)
{
UBYTE Buf[21];
struct timeval tr_time;
ULONG secs;
int DOW;
GetSysTime(&tr_time);
secs = tr_time.tv_secs % SECSINDAY;
memset(Buf, 0xFF, 16);
Buf[16] = 2;
Buf[18] = secs / SECSINHOUR;
secs %= SECSINHOUR;
Buf[17] = secs / SECSINMINUTE;
DOW = ((tr_time.tv_secs / SECSINDAY) % 7) - 1;
if (DOW == -1)
DOW = 6;
Buf[19] = 1L << DOW;
Buf[20] = Buf[17] + Buf[18] + Buf[19];
ClearSerial();
SerWrite(Buf, 21);
if (!X10WaitForAck(FALSE))
ErrorMsg(MSG_CP290_ERROR_SETCLOCK);
}
/* runs a diagnostic test on the x10 interface */
void X10Diagnostic(void)
{
UBYTE Buf[17];
int index;
UWORD raw;
UBYTE BaseHC;
STRPTR DOW;
/*
* send the code for a self diagnostic and wait for the unit's
* response
*/
memset(Buf, 0xFF, 16);
Buf[16] = 7;
ClearSerial();
SerWrite(Buf, 17);
for (index = 0;; index++) {
raw = SerGetRawChar(15);
if (raw == TIMEOUT) {
ErrorMsg(MSG_CP290_ERROR_DIAG, GetString(&LocaleInfo, MSG_TIMEOUT));
return;
}
if (raw == 0xFF)
index++;
else if (index > 5)
if ((raw & 1) == 1) {
ErrorMsg(MSG_CP290_ERROR_DIAG, GetString(&LocaleInfo, MSG_STATUS_FLAG));
return;
}
else
break;
}
/*
* if the interface passed the diagnositc test then query it about
* the base housecode and what time it thinks it is and display this
* to the user as part of the status message.
*/
memset(Buf, 0xFF, 16);
Buf[16] = 4;
ClearSerial();
SerWrite(Buf, 17);
for (index = 0;;) {
raw = SerGetRawChar(15);
if (raw == TIMEOUT) {
ErrorMsg(MSG_CP290_ERROR_NO_RESPONSE);
return;
}
if (raw == 0xFF) {
Buf[index++] = raw;
break;
}
}
while (index < 12) {
raw = SerGetRawChar(2);
if (raw == TIMEOUT) {
ErrorMsg(MSG_CP290_ERROR_READING, GetString(&LocaleInfo, MSG_TIMEOUT));
return;
}
Buf[index++] = raw;
}
if (Buf[11] != Buf[7] + Buf[8] + Buf[9] + Buf[10]) {
ErrorMsg(MSG_CP290_ERROR_READING, GetString(&LocaleInfo, MSG_CHECKSUM));
return;
}
for (index = 0; index < 16; index++)
if (HouseCode[index] == Buf[10])
BaseHC = 'A' + index;
switch (Buf[9]) {
case 64:
if (LocaleBase)
DOW = GetLocaleStr(DefaultLocale, DAY_1);
else
DOW = "Sunday";
break;
case 32:
if (LocaleBase)
DOW = GetLocaleStr(DefaultLocale, DAY_7);
else
DOW = "Saturday";
break;
case 16:
if (LocaleBase)
DOW = GetLocaleStr(DefaultLocale, DAY_6);
else
DOW = "Friday";
break;
case 8:
if (LocaleBase)
DOW = GetLocaleStr(DefaultLocale, DAY_5);
else
DOW = "Thursday";
break;
case 4:
if (LocaleBase)
DOW = GetLocaleStr(DefaultLocale, DAY_4);
else
DOW = "Wednesday";
break;
case 2:
if (LocaleBase)
DOW = GetLocaleStr(DefaultLocale, DAY_3);
else
DOW = "Tuesday";
break;
case 1:
if (LocaleBase)
DOW = GetLocaleStr(DefaultLocale, DAY_2);
else
DOW = "Monday";
break;
default:
DOW = "???";
break;
};
MyPrintf(MSG_CP290_PASSED_DIAG, BaseHC, DOW, Buf[8], Buf[7]);
/*
* when a diagnostic is run, the interface whacks out all of its
* memory. Thus, if we tried to upload data from it we would get
* garbage. we also have garbage sitting there that might cause
* funny events to happen. So we set the unit's base housecode to
* what we were just told it was by the interface. This causes the
* interface to properly reset its memory so that we don't have bogus
* data sitting in it.
*/
sprintf(Buf, "%lc", BaseHC);
X10SetBaseHC(Buf);
return;
}
/*
* look at the character passed in and decide if it's a valid house code or
* not. translate it into the appripriate index value for use with the
* controller unit if it's valid. else return -1.
*/
int X10GetHC(UBYTE Char)
{
if (isalpha(Char)) {
Char = tolower(Char);
if (Char >= 'a' && Char <= 'p')
return Char - 'a';
}
return -1;
}
/* build an x10 direct command to turn a specified unit on, off, etc. */
BOOL X10SendDirectCmd(int HC, int Unit, ULONG Function, ULONG DimLevel)
{
UBYTE Buf[22];
int unitByte;
memset(Buf, 0xFF, 16);
Buf[16] = 1;
Buf[17] = ((DimLevel & 0x0F) << 4L) | (Function & 0x0F);
Buf[18] = HouseCode[HC];
if (Unit < 8) {
Buf[19] = 0;
unitByte = 20;
}
else {
Buf[20] = 0;
unitByte = 19;
Unit -= 8;
}
Buf[unitByte] = 1L << (7 - Unit);
Buf[21] = Buf[17] + Buf[18] + Buf[19] + Buf[20];
ClearSerial();
SerWrite(Buf, 22);
return X10WaitForAck(TRUE);
}
/*
* wait for the ack message from the controller unit. we return the ack's
* status bit as either true or false
*/
BOOL X10WaitForAck(BOOL WaitForUploadReport)
{
int SYNCs;
UWORD raw;
/* look for ack to our command */
for (SYNCs = 0; SYNCs < 16; SYNCs++) {
raw = SerGetRawChar(15);
if (raw == TIMEOUT)
return FALSE;
if (raw != 0xFF)
SYNCs = 255;
}
if (WaitForUploadReport) {
/* look for upload report */
for (SYNCs = 0; SYNCs < 16; SYNCs++) {
raw = SerGetRawChar(15);
if (raw == TIMEOUT)
return FALSE;
if (raw != 0xFF)
SYNCs = 255;
}
/* suck the remaining characters in the upload report */
do {
raw = SerGetRawChar(1);
} while (raw != TIMEOUT);
}
return TRUE;
}