/* * Copyright 1996, 1997, 1998, 1999, 2002 by Daniel B. Suthers, * Pleasanton Ca. 94588 USA * E-MAIL dbs@tanj.com * * You may freely copy, use, and distribute this software, * in whole or in part, subject to the following restrictions: * * 1) You may not charge money for it. * 2) You may not remove or alter this copyright notice. * 3) You may not claim you wrote it. * 4) If you make improvements (or other changes), you are requested * to send them to me, so there's a focal point for distributing * improved versions. * */ /* * Original code written for the cp290 series by Larry Campbell, * 73 Concord Street, Maynard MA 01754 USA. (maynard!campbell) */ /* * Code modified for Heyu ver 2 by Charles Sullivan */ #include #include #include #include #include "x10.h" #include #include #include #include "process.h" extern int tty; extern int sptty; extern char *wday_name[7]; extern char *month_name[12]; extern int i_am_relay; extern int x10_housecode; extern int verbose; extern unsigned int jul(); extern CONFIG config; extern CONFIG *configp; /* ARGSUSED */ int c_setclock ( int argc, char *argv[] ) { unsigned char data[9]; unsigned char buf[3]; char msgbuf[1000]; unsigned int n; unsigned int clear; struct tm *tp; time_t dtime; extern int usage(), xwrite(), xread(), exread(), sxread(), check4poll(), get_status(); extern void wait_next_tick(); extern struct tm *legal_to_cm11a(); int code; unsigned char cksum; if ( invalidate_for_cm10a() != 0 ) return -1; /* Argc == 1 means use system time. * Argc == 2 means parse a date from the input or reset the clock. */ if ( argc < 1 || argc > 3 ) { if ( argc != 7 ) usage(E_2MANY); } clear = 0; if ( i_am_relay != 1 ) wait_next_tick(); /* System clock rolls over to next second */ dtime = time(NULL); tp = localtime(&dtime); if ( argc == 2 ) { if ( strcmp( "reset", argv[1]) == 0 ) { clear = 1; } } if ( argc == 3 ) { /* must be date information. Load it in the structure * and then remake the structure with the right time. * (In Heyu 1, entered data was taken to be Standard Time * but is now taken to be Legal Time.) */ if ( sscanf(argv[2], "%2d%2d%2d%2d%2d", &tp->tm_mon, &tp->tm_mday, &tp->tm_hour, &tp->tm_min, &tp->tm_sec) != 5 ) { printf(" Bad argument. Expected %s %s MMDDhhmmss\n", argv[0], argv[1]); return(-1); } tp->tm_mon -= 1; /* tm month is 0 relative */ tp->tm_isdst = -1; dtime = mktime(tp); /* reset day of week, julian */ if ( dtime < 1 ) { printf("An error was encountered parsing the input %s\n", argv[2]); return(-1); } } /* * Translate Legal Time into CM11a clock time per the * X10 Record File, if it exists, or to Standard Time * if it doesn't. */ tp = legal_to_cm11a( &dtime ); data[0] = 0x9b; /* CM11A timer download code */ data[1] = tp->tm_sec ; data[2] = tp->tm_min + (((tp->tm_hour) %2) * 60 ) ; /* minutes 0 - 119 */ data[3] = tp->tm_hour / 2 ; /* hour / 2 0 - 11 */ data[4] = tp->tm_yday % 256 ; /* mantisa of julian date */ data[5] = ((tp->tm_yday / 256 ) << 7); /* radix of julian date */ data[5] |= (0x01 << (tp->tm_wday)); /* bits 0-6 = single bit mask day */ /* of week ( smtwtfs ) */ data[6] = (x10_housecode << 4); data[6] |= clear; if ( verbose ) { sprintf(msgbuf, "would send %0x %0x %0x %0x %0x %0x %0x\n", data[0], data[1], data[2], data[3], data[4], data[5], data[6]); if ( i_am_relay == 1 ) syslog(LOG_ERR, msgbuf); else fprintf(stderr, msgbuf); } cksum = checksum(data + 1, 6); code = 0; if ( i_am_relay ) { write(tty, (char *) data, 7); n = sxread(tty, buf, 1, 1); } else { xwrite(tty, (char *) data, 7); n = exread(sptty, buf, 1, 1); } if ( n != 1 ) code |= 0x10; else if ( buf[0] != cksum ) code |= 0x01; if ( i_am_relay ) { write(tty, "\0", 1); /* WRMI */ n = sxread(tty, buf, 1, 1); } else { xwrite(tty, "\0", 1); /* WRMI */ n = exread(sptty, buf, 1, 1); } if ( n != 1 ) code |= 0x20; else if ( buf[0] != 0x55 ) code |= 0x02; if ( argc == 2 || argc == 3 ) { check4poll(0,1); /* zero means to discard data */ get_status(); if ( clear == 0) { if ( i_am_relay != 1 ) fprintf(stderr, "CM11A clock set to %s, %02d:%02d:%02d (Standard Time), Day %d\n", wday_name[tp->tm_wday], tp->tm_hour, tp->tm_min, tp->tm_sec, tp->tm_yday); } else { if ( i_am_relay != 1 ) printf("CM11A house code set to %c\n", code2hc( x10_housecode)); } } return(0); } /* Set clock without regard to the x10record file */ int c_setclockraw ( int argc, char *argv[] ) { unsigned char data[9]; unsigned char buf[3]; char msgbuf[1000]; unsigned int n; unsigned int clear; struct tm *tp; time_t dtime; int was_tm_isdst; extern int usage(), xwrite(), xread(), exread(), sxread(), check4poll(), get_status(); extern void wait_next_tick(); int code; unsigned char cksum; if ( invalidate_for_cm10a() != 0 ) return 1; /* Argc == 1 means use system time. * Argc == 2 means parse a date from the input or reset the clock. */ if ( argc < 1 || argc > 3 ) { if ( argc != 7 ) usage(E_2MANY); } clear = 0; if ( i_am_relay != 1 ) wait_next_tick(); /* System clock rolls over to next second */ dtime = time(NULL); tp = localtime(&dtime); if ( argc == 2 ) { if( strcmp( "reset", argv[1]) == 0 ) { clear = 1; } } if ( argc == 3) { /* must be date information. Load it in the structure * and then remake the structure with the right time. */ if ( sscanf(argv[2], "%2d%2d%2d%2d%2d", &tp->tm_mon, &tp->tm_mday, &tp->tm_hour, &tp->tm_min, &tp->tm_sec) != 5) { printf(" Bad argument. Expected %s %s MMDDhhmmss\n", argv[0], argv[1]); return(-1); } tp->tm_mon -= 1; /* tm month is 0 relative */ was_tm_isdst = tp->tm_isdst; /* save the current DST flag */ dtime = mktime(tp); /* reset day of week, julian */ if ( dtime < 1 ) { printf("An error was encountered parsing the input %s\n", argv[2]); return(-1); } /* we want absolute time, but mktime will reset the hour as necessary, * to match daylight savings. * we undo that here. */ if ( tp->tm_isdst != was_tm_isdst ) { if ( was_tm_isdst == 0 ) { dtime -= 3600; /* subtract an hour*/ } else { dtime += 3600; /* add an hour*/ } tp = localtime(&dtime); } } data[0] = 0x9b; /* CM11A timer download code */ data[1] = tp->tm_sec ; data[2] = tp->tm_min + (((tp->tm_hour) %2) * 60 ) ; /* minutes 0 - 119 */ data[3] = tp->tm_hour / 2 ; /* hour / 2 0 - 11 */ data[4] = tp->tm_yday % 256 ; /* mantisa of julian date */ data[5] = ((tp->tm_yday / 256 ) << 7); /* radix of julian date */ data[5] |= (0x01 << (tp->tm_wday)); /* bits 0-6 = single bit mask day */ /* of week ( smtwtfs ) */ data[6] = (x10_housecode << 4); data[6] |= clear; if ( verbose ) { sprintf(msgbuf, "would send %0x %0x %0x %0x %0x %0x %0x\n", data[0], data[1], data[2], data[3], data[4], data[5], data[6]); if ( i_am_relay == 1 ) syslog(LOG_ERR, msgbuf); else fprintf(stderr, msgbuf); } cksum = checksum(data + 1, 6); code = 0; xwrite(tty, (char *) data, 7); if ( i_am_relay ) n = sxread(tty, buf, 1, 1); else n = exread(sptty, buf, 1, 1); if ( n != 1 ) code |= 0x10; else if ( buf[0] != cksum ) code |= 0x01; xwrite(tty, "\0", 1); /* WRMI */ if ( i_am_relay ) n = sxread(tty, buf, 1, 1); else n = exread(sptty, buf, 1, 1); if ( n != 1 ) code |= 0x20; else if ( buf[0] != 0x55 ) code |= 0x02; if ( argc == 2 || argc == 3 ) { check4poll(0,1); /* zero means to discard data */ get_status(); if( clear == 0) { if ( i_am_relay != 1 ) fprintf(stderr, "CM11A clock set to %s, %d:%02d\n", wday_name[tp->tm_wday], tp->tm_hour, tp->tm_min); } else { if ( i_am_relay != 1 ) (void) printf("CM11A house code set to %c\n", code2hc( x10_housecode)); } } return(0); } /* Stop power-fail update polling without */ /* resetting clock. (For clock testing purposes) */ int c_stop_cm11a_poll ( int argc, char *argv[] ) { unsigned char data[3]; extern int xwrite(), check4poll(); data[0] = 0x9b; if ( i_am_relay ) { write(tty, (char *)data, 1); } else { xwrite(tty, (char *)data, 1); } if ( !i_am_relay ) check4poll(0,1); /* zero means to discard data */ /* Allow CM11A to recover */ millisleep(SETCLOCK_DELAY); return 0; }