/*----------------------------------------------------------------------------+ | +----------------------------------------------------------------------------*/ void xlate_rf( unsigned char type, char **fname, unsigned int rfword, char *hcp, int *unitp, unsigned char *nosw ) { int j; *fname = rf_func_name[type]; if ( type == 9 ) return; *hcp = rf2hc[(rfword & HC_MASK) >> 12]; *nosw = rfword & NOSW_MASK; rfword &= UNIT_MASK; *unitp = 0; for ( j = 0; j < 16; j++ ) { if ( rfword == rf_unit_code[j] ) { *unitp = code2unit(j); break; } } return; }
/*---------------------------------------------------------------------+ | Display a Digimax data value stored in the x10state structure. | +---------------------------------------------------------------------*/ int c_dmxcmds ( int argc, char *argv[] ) { ALIAS *aliasp; unsigned char hcode, ucode, mode; unsigned long aflags; unsigned long longvdata; char hc; unsigned int bitmap; int unit, index, tempc; int read_x10state_file ( void ); if ( argc < 3 ) { fprintf(stderr, "Usage: %s %s Hu\n", argv[0], argv[1]); return 1; } if ( check_for_engine() != 0 ) { fprintf(stderr, "State engine is not running.\n"); return 1; } if ( read_x10state_file() != 0 ) { fprintf(stderr, "Unable to read state file.\n"); return 1; } if ( (aliasp = configp->aliasp) == NULL ) return 1; aflags = parse_addr(argv[2], &hc, &bitmap); if ( !(aflags & A_VALID) || aflags & (A_DUMMY | A_PLUS | A_MINUS) || bitmap == 0 ) { fprintf(stderr, "Invalid Hu address '%s'\n", argv[2]); return 1; } if ( aflags & A_MULT ) { fprintf(stderr, "Only a single unit address is valid.\n"); return 1; } hcode = hc2code(hc); ucode = single_bmap_unit(bitmap); unit = code2unit(ucode); if ( (index = alias_lookup_index(hc, bitmap, RF_DIGIMAX)) < 0 ) { fprintf(stderr, "Address %c%d is not configured as a Digimax\n", hc, unit); return 1; } longvdata = x10global.data_storage[aliasp[index].storage_index]; if ( (longvdata & 0x01) == 0 ) { fprintf(stderr, "Not ready\n"); return 1; } if ( strcmp(argv[1], "dmxtemp") == 0 ) { tempc = (longvdata & TCURRMASK) >> TCURRSHIFT; tempc = (tempc & 0x80) ? (0x80 - tempc) : tempc; printf("%d\n", tempc); }
/*------------------------------------------------------------------------+ | Interpret Digimax data string, update the state, and test whether | | any launch condition is satisfied. | | The data packet has been forwarded 3 times in succession so it can be | | split here into 3 separate Heyu functions. Parameter 'seq' numbers the | | packets 1, 2, 3. | | buffer references: | | ST_COMMAND, ST_LONGVDATA, vtype, seq, vidhi, vidlo, nbytes, bytes 1-N | +------------------------------------------------------------------------*/ char *translate_digimax ( unsigned char *buf, unsigned char *sunchanged, int *launchp ) { #ifdef HAVE_FEATURE_DMX static char outbuf[160]; char flagslist[80], unknown[32]; ALIAS *aliasp; LAUNCHER *launcherp; extern unsigned int signal_source; unsigned char func, *vdatap, vtype, seq, vdata = 0; unsigned short vident; int unit, loc, tempc; unsigned char status, settempc; unsigned long longvdata, prevdata, currdata, heatmode, onoff; char hc; unsigned char actfunc, xactfunc; unsigned int trigaddr, mask, active, trigactive; unsigned int modchgstate, changestate; unsigned int bmaplaunch, launched; unsigned long afuncmap, xfuncmap; int j, k, found, index = -1; unsigned char hcode, ucode, trig; unsigned int bitmap = 0, vflags = 0; static unsigned int startupstate; static char *typename[] = {"Std", "Ent", "Sec", "RFXSensor", "RFXMeter", "?", "??", "???", "????", "DigiMax", "Noise", "Noise2"}; launcherp = configp->launcherp; aliasp = configp->aliasp; *launchp = -1; *sunchanged = 0; flagslist[0] = '\0'; unknown[0] = '\0'; *outbuf = '\0'; changestate = modchgstate = 0; vtype = buf[2]; seq = buf[3]; vident = (buf[4] << 8) | buf[5]; vdatap = buf + 9; func = VdataFunc; x10global.longvdata = 0; x10global.lastvtype = vtype; hcode = ucode = 0; found = 0; j = 0; /* Look up the alias, if any */ while ( !found && aliasp && aliasp[j].line_no > 0 ) { if ( aliasp[j].vtype == vtype && (bitmap = aliasp[j].unitbmap) > 0 && (ucode = single_bmap_unit(aliasp[j].unitbmap)) != 0xff ) { for ( k = 0; k < aliasp[j].nident; k++ ) { if ( aliasp[j].ident[k] == vident ) { index = j; found = 1; break; } } } j++; } if ( !found || !aliasp ) { if ( seq == 1 ) { sprintf(outbuf, "func %12s : Type %s ID 0x%04X Data 0x%02X%02X%02X%02X", "RFdata", typename[vtype], vident, vdatap[0], vdatap[1], vdatap[2], vdatap[3]); } return outbuf; } hc = aliasp[index].housecode; hcode = hc2code(hc); unit = code2unit(ucode); loc = aliasp[index].storage_index; prevdata = x10global.data_storage[loc]; currdata = (vdatap[0] << 24) | (vdatap[1] << 16) | (vdatap[2] << 8) | vdatap[3]; /* Blank out parity bits */ currdata &= ~PARMASK; switch ( seq ) { case 1 : /* Process current temperature */ /* Create a special message if any of the undefined status bits are set */ /* Hopefully a user seeing this message will report it so we can figure */ /* out their meaning (low battery perhaps). */ if ( currdata & UNDEFMASK ) { sprintf(unknown, "unknown = 0x%08lx ", currdata & UNDEFMASK); } status = (currdata & STATMASK) >> STATSHIFT; longvdata = (prevdata & (TSETPMASK | SETPFLAG | ONOFFMASK)) | (currdata & (STATMASK | TCURRMASK | HEATMASK)) | VALMASK; if ( status == 0 || status == 3 ) { longvdata &= ~ONOFFMASK; } if ( status == 0 ) longvdata &= ~(TSETPMASK | SETPFLAG); vflags = (longvdata & HEATMASK) ? 0 : DMX_HEAT; vflags |= (status == 3) ? DMX_INIT : 0; vflags |= (longvdata & SETPFLAG) ? DMX_SET : 0; vflags |= DMX_TEMP; tempc = (longvdata & TCURRMASK) >> TCURRSHIFT; tempc = (tempc & 0x80) ? 0x80 - tempc : tempc; modchgstate = ((prevdata ^ currdata) & TCURRMASK) ? bitmap : 0; /* Update the storage location */ x10global.data_storage[loc] = longvdata; x10global.longvdata = longvdata; func = DmxTempFunc; trig = DmxTempTrig; create_flagslist (vtype, vflags, flagslist); sprintf(outbuf, "func %12s : hu %c%-2d Temp %dC %s %s(%s)", funclabel[func], hc, unit, tempc, flagslist, unknown, aliasp[index].label); break; case 2 : status = (currdata & STATMASK) >> STATSHIFT; longvdata = (prevdata & (TCURRMASK | HEATMASK | ONOFFMASK)) | (currdata & (STATMASK | TSETPMASK)) | VALMASK; if ( status == 0 || status == 3 ) longvdata &= ~ONOFFMASK; if ( status == 0 ) longvdata &= ~(TSETPMASK | SETPFLAG); else longvdata |= SETPFLAG; modchgstate = ((prevdata ^ longvdata) & TSETPMASK) ? bitmap : 0; settempc = (longvdata & TSETPMASK) >> TSETPSHIFT; vflags = (longvdata & HEATMASK) ? 0 : DMX_HEAT; vflags |= (longvdata & SETPFLAG) ? DMX_SET : 0; vflags |= (status == 3) ? DMX_INIT : 0; vflags |= DMX_TEMP; /* Update stored data */ x10global.data_storage[loc] = longvdata; x10global.longvdata = longvdata; if ( status == 0 ) return ""; func = DmxSetPtFunc; trig = DmxSetPtTrig; create_flagslist(vtype, vflags, flagslist); sprintf(outbuf, "func %12s : hu %c%-2d Setpoint %dC %s (%s)", funclabel[func], hc, unit, settempc, flagslist, aliasp[index].label); break; case 3 : /* Process Heat On/Off */ status = (currdata & STATMASK) >> STATSHIFT; longvdata = ((prevdata & (TCURRMASK | TSETPMASK | HEATMASK | SETPFLAG)) | ((currdata & STATMASK)) ) | VALMASK; if ( status == 1 || status == 2 ) { longvdata |= (status << ONOFFSHIFT); } x10global.data_storage[loc] = longvdata; x10global.longvdata = longvdata; modchgstate = ((prevdata ^ longvdata) & ONOFFMASK) ? bitmap : 0; vflags = (longvdata & HEATMASK) ? 0 : DMX_HEAT; vflags |= (status != 0) ? DMX_SET : 0; vflags |= (status == 3) ? DMX_INIT : 0; vflags |= DMX_TEMP; /* Update stored data */ x10global.data_storage[loc] = longvdata; x10global.longvdata = longvdata; onoff = (longvdata & ONOFFMASK) >> ONOFFSHIFT; if ( onoff == 0 ) return ""; heatmode = (longvdata & HEATMASK) >> HEATSHIFT; x10state[hcode].state[DimState] &= ~bitmap; /* Not sure if On/Off needs to be swapped in "cool" mode */ /* (which requires cutting a jumper wire in the thermostat) */ /* or if the DigiMax or it's base station will handle this */ /* automatically. (DMXCOOLSWAP YES|NO is defined in digimax.h) */ if ( DMXCOOLSWAP == YES ) onoff = (heatmode == 0) ? onoff : ((onoff + 2) % 2) + 1; if ( onoff == 1 ) { func = DmxOnFunc; trig = DmxOnTrig; x10state[hcode].state[OnState] |= bitmap; x10state[hcode].dimlevel[ucode] = vdata = 0xff; } else { func = DmxOffFunc; trig = DmxOffTrig; x10state[hcode].state[OnState] &= ~bitmap; x10state[hcode].dimlevel[ucode] = vdata = 0; } create_flagslist (vtype, vflags, flagslist); sprintf(outbuf, "func %12s : hu %c%-2d %s (%s)", funclabel[func], hc, unit, flagslist, aliasp[index].label); break; default : return ""; } x10state[hcode].vaddress = bitmap; x10state[hcode].lastcmd = func; x10state[hcode].lastunit = unit; x10state[hcode].vident[ucode] = vident; x10state[hcode].vflags[ucode] = vflags; x10state[hcode].timestamp[ucode] = time(NULL); x10global.lasthc = hcode; x10global.lastaddr = 0; if ( vflags & SEC_LOBAT ) { x10state[hcode].state[LoBatState] |= (1 << ucode); } else { x10state[hcode].state[LoBatState] &= ~(1 << ucode); } actfunc = 0; afuncmap = 0; xactfunc = func; xfuncmap = (1 << trig); trigaddr = bitmap; mask = modmask[VdataMask][hcode]; active = bitmap & mask; if ( seq == 1 ) { startupstate = ~x10state[hcode].state[ValidState] & active; x10state[hcode].state[ValidState] |= active; /* Update activity timeout for sensor */ update_activity_timeout(aliasp, index); update_activity_states(hcode, aliasp[index].unitbmap, S_ACTIVE); } x10state[hcode].state[ModChgState] = modchgstate; x10state[hcode].state[ChgState] = x10state[hcode].state[ModChgState] | (x10state[hcode].state[ActiveChgState] & active) | (startupstate & ~modmask[PhysMask][hcode]); changestate = x10state[hcode].state[ChgState]; *sunchanged = (changestate & active) ? 0 : 1; if ( configp->show_change == YES ) { snprintf(outbuf + strlen(outbuf), sizeof(outbuf), "%s", ((changestate & active) ? " Chg" : " UnChg")); } if ( i_am_state ) write_x10state_file(); /* Heyuhelper, if applicable */ if ( i_am_state && signal_source & RCVI && configp->script_mode & HEYU_HELPER ) { launch_heyuhelper(hcode, trigaddr, func); return outbuf; } bmaplaunch = 0; launched = 0; j = 0; while ( launcherp && launcherp[j].line_no > 0 ) { if ( launcherp[j].type != L_NORMAL || launcherp[j].hcode != hcode || is_unmatched_flags(&launcherp[j]) || (launcherp[j].vflags & x10state[hcode].vflags[ucode]) != launcherp[j].vflags || (launcherp[j].notvflags & ~x10state[hcode].vflags[ucode]) != launcherp[j].notvflags ) { j++; continue; } if ( launcherp[j].xfuncmap & xfuncmap && launcherp[j].source & signal_source ) { trigactive = trigaddr & (mask | launcherp[j].signal); if ( (bmaplaunch = (trigactive & launcherp[j].bmaptrig) & (changestate | ~launcherp[j].chgtrig)) || (launcherp[j].unitstar && !trigaddr)) { launcherp[j].matched = YES; *launchp = j; launcherp[j].actfunc = xactfunc; launcherp[j].genfunc = 0; launcherp[j].xfunc = xactfunc; launcherp[j].level = x10state[hcode].dimlevel[ucode]; launcherp[j].bmaplaunch = bmaplaunch; launcherp[j].actsource = signal_source; launched |= bmaplaunch; if ( launcherp[j].scanmode & FM_BREAK ) break; } } j++; } x10state[hcode].launched = launched; return outbuf; #else return ""; #endif /* HAVE_FEATURE_DMX */ }
/*---------------------------------------------------------------------+ | Display stored data for Digimax thermostat | +---------------------------------------------------------------------*/ int show_digimax ( void ) { #ifdef HAVE_FEATURE_DMX ALIAS *aliasp; char hc; int unit, index, temp, count = 0, maxlabel = 0; unsigned char hcode, ucode, status, onoff; unsigned long longvdata; static char *onoff_status[] = {"---", "On", "Off", ""}; if ( !(aliasp = configp->aliasp) ) return 0; /* Get maximum lengths of module name and alias label */ index = 0; while ( aliasp[index].line_no > 0 ) { if ( aliasp[index].vtype == RF_DIGIMAX ) { count++; maxlabel = max(maxlabel, (int)strlen(aliasp[index].label)); } index++; } if ( count == 0 ) return 0; index = 0; while ( aliasp[index].line_no > 0 ) { if ( aliasp[index].vtype != RF_DIGIMAX ) { index++; continue; } ucode = single_bmap_unit(aliasp[index].unitbmap); unit = code2unit(ucode); hc = aliasp[index].housecode; hcode = hc2code(hc); longvdata = x10global.data_storage[aliasp[index].storage_index]; if ( longvdata == 0 ) { printf("%c%-2d %-*s Temp --- Setpoint --- mode: ---- status: ---\n", hc, unit, maxlabel, aliasp[index].label); index++; continue; } status = (longvdata & STATMASK) >> STATSHIFT; printf("%c%-2d %-*s", hc, unit, maxlabel, aliasp[index].label); temp = (longvdata & TCURRMASK) >> TCURRSHIFT; if ( temp & 0x80 ) temp = 0x80 - temp; printf(" Temp %2dC", temp); temp = (longvdata & TSETPMASK) >> TSETPSHIFT; if ( (longvdata & SETPFLAG) == 0 ) printf(" Setpoint ---"); else printf(" Setpoint %2dC", temp); printf(" mode: %s", ((longvdata & HEATMASK) ? "Cool" : "Heat")); onoff = (longvdata & ONOFFMASK) >> ONOFFSHIFT; printf(" status: %s", onoff_status[onoff]); printf("\n"); index++; } #endif /* HAVE_FEATURE_DMX */ return 0; }