From 9b2c653fcd2dc387fef11231cfa4df8ab1c19dcf Mon Sep 17 00:00:00 2001 From: Micke Prag Date: Sun, 22 Jun 2008 10:48:17 +0000 Subject: [PATCH] rfcmd v0.3 with support for IKEA. Thanks to Gudmund Berggren! --- rfcmd/rfcmd.c | 281 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 243 insertions(+), 38 deletions(-) diff --git a/rfcmd/rfcmd.c b/rfcmd/rfcmd.c index c0ceeb5d..aaf80032 100644 --- a/rfcmd/rfcmd.c +++ b/rfcmd/rfcmd.c @@ -2,14 +2,38 @@ ** rfcmd.c *********************************************************** **************************************************************************** * - * rfcmd - utility to control NEXA and other RF remote receivers through a TellStick + * rfcmd - utility to control NEXA and other RF remote receivers through a TellStick USB interface * * Copyright (C) 2007 Tord Andersson * * License: GPL v. 2 * - */ + * Authors: + * Tord Andersson + * Micke Prag + * Gudmund Berggren + */ + +/******************************************************************************* + * Modifications from rfcmd.c ver 0.2 done by Gudmund + * Added support for IKEA + * Note: + * 1. System code + * 2. Level 0 == Off (For dimmers and non dimmers) + * Level 1== 10%. (for dimmers) + * .... + * Level 9 == 90 % (for dimmers) + * Level 10 == 100 % (or ON for non dimmers) + * 3. Command line syntax: + * /usr/local/bin/rfcmd /dev/ttyUSB0 IKEA 0 1 10 1" + * Arg 1: device + * Arg 2: Protocoll + * Arg 3: System code + * Arg 4: Device code + * Arg 5: Level (0=off, 1 = 10%, 2=20%,...9=90%, 10=100%) + * Arg 6: DimStyle (0=instant change, 1=gradually change) + ******************************************************************************/ #include #include @@ -19,14 +43,17 @@ #include #define PROG_NAME "rfcmd" -#define PROG_VERSION "0.2" +#define PROG_VERSION "0.3" /* #define RFCMD_DEBUG */ /* Local function declarations */ -int createNexaString(const char * pHouseStr, const char * pChannelStr, - const char * pOn_offStr, char * pTxStr, int waveman); -int createSartanoString(const char * pChannelStr, const char * pOn_offStr, - char * pTxStr); +int createNexaString(const char * pHouseStr, const char * pChannelStr, + const char * pOn_offStr, char * pTxStr, int waveman); +int createSartanoString(const char * pChannelStr, const char * pOn_offStr, + char * pTxStr); +int createIkeaString(const char * pSystemStr, const char * pChannelStr, + const char * pLevelStr, const char *pDimStyle, + char * pStrReturn); void printUsage(void); @@ -34,13 +61,10 @@ int main( int argc, char **argv ) { struct termios tio; int fd = -1; - char txStr[250]; - - + char txStr[100]; if( (argc == 6) && (strcmp(*(argv+2), "NEXA") == 0)) { - if (createNexaString(*(argv+3), *(argv+4), *(argv+5), txStr, 0) == 0) { printUsage(); @@ -58,7 +82,6 @@ int main( int argc, char **argv ) } else if( (argc == 5) && (strcmp(*(argv+2), "SARTANO") == 0)) { - if (createSartanoString(*(argv+3), *(argv+4), txStr) == 0) { printUsage(); @@ -66,13 +89,22 @@ int main( int argc, char **argv ) } /* else - a send cmd string was created */ } + else if ( (argc == 7) && (strcmp(*(argv+2),"IKEA")==0) ) + { + // System, Channel, Level, DimStyle, TXString + if ( createIkeaString(*(argv+3), *(argv+4), *(argv+5), *(argv+6),txStr) == 0 ) + { + printUsage(); + exit(1); + } + /* else - a send cmd string was created */ + } else /* protocol or parameters not recognized */ { printUsage(); exit(1); } - #ifdef RFCMD_DEBUG printf("txStr: %s\n", txStr); #endif @@ -83,28 +115,29 @@ int main( int argc, char **argv ) exit(1); } - if(strlen(txStr) > 0) { /* adjust serial port parameters */ bzero(&tio, sizeof(tio)); /* clear struct for new port settings */ - tio.c_cflag = B4800 | CS8 | CLOCAL | CREAD; /* CREAD not used yet */ + tio.c_cflag = B4800 | CS8 | CLOCAL | CREAD; /* CREAD not used yet */ tio.c_iflag = IGNPAR; tio.c_oflag = 0; tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&tio); write(fd, txStr, strlen(txStr)); - sleep(1); /* one second sleep to avoid device 'choking' */ + + sleep(1); /* one second sleep to avoid device 'choking' */ + close(fd); /* Modified : Close fd to make a clean exit */ } exit(0); } -int createNexaString(const char * pHouseStr, const char * pChannelStr, - const char * pOn_offStr, char * pTxStr, int waveman) +int createNexaString(const char * pHouseStr, const char * pChannelStr, + const char * pOn_offStr, char * pTxStr, int waveman) { - * pTxStr = '\0'; /* Make sure tx string is empty */ + * pTxStr = '\0'; /* Make sure tx string is empty */ int houseCode; int channelCode; int on_offCode; @@ -130,18 +163,18 @@ int createNexaString(const char * pHouseStr, const char * pChannelStr, } else { - /* b0..b11 txCode where 'X' will be represented by 1 for simplicity. - b0 will be sent first */ + /* b0..b11 txCode where 'X' will be represented by 1 for simplicity. + b0 will be sent first */ txCode = houseCode; txCode |= (channelCode << 4); if (waveman && on_offCode == 0) { } else { txCode |= (unknownCode << 8); - txCode |= (on_offCode << 11); + txCode |= (on_offCode << 11); } - + /* convert to send cmd string */ - strcat(pTxStr,"S"); + strcat(pTxStr,"S"); for(bit=0;bit<12;bit++) { if((bitmask & txCode) == 0) @@ -158,7 +191,7 @@ int createNexaString(const char * pHouseStr, const char * pChannelStr, bitmask = bitmask<<1; } /* add stop/sync bit and command termination char '+'*/ - strcat(pTxStr," }+"); + strcat(pTxStr," }+"); /* strcat(pTxStr,"$}+"); */ } @@ -169,10 +202,10 @@ int createNexaString(const char * pHouseStr, const char * pChannelStr, return strlen(pTxStr); } -int createSartanoString(const char * pChannelStr, const char * pOn_offStr, - char * pTxStr) +int createSartanoString(const char * pChannelStr, const char * pOn_offStr, + char * pTxStr) { - * pTxStr = '\0'; /* Make sure tx string is empty */ + * pTxStr = '\0'; /* Make sure tx string is empty */ int on_offCode; int bit; @@ -190,7 +223,7 @@ int createSartanoString(const char * pChannelStr, const char * pOn_offStr, } else { - strcat(pTxStr,"S"); + strcat(pTxStr,"S"); for(bit=0;bit<=9;bit++) { if(strncmp(pChannelStr+bit, "1", 1) == 0) //If it is a "1" @@ -206,9 +239,9 @@ int createSartanoString(const char * pChannelStr, const char * pOn_offStr, strcat(pTxStr,"$k$k$kk$"); //the "turn on"-code else strcat(pTxStr,"$kk$$k$k"); //the "turn off"-code - + /* add stop/sync bit and command termination char '+'*/ - strcat(pTxStr,"$k+"); + strcat(pTxStr,"$k+"); } #ifdef RFCMD_DEBUG @@ -216,18 +249,190 @@ int createSartanoString(const char * pChannelStr, const char * pOn_offStr, #endif return strlen(pTxStr); - + } +int createIkeaString( const char * pSystemStr, const char * pChannelStr, const char * pLevelStr, const char *pDimStyle, char * pStrReturn) +{ + *pStrReturn = '\0'; /* Make sure tx string is empty */ + + const char STARTCODE[] = "STTTTTTª"; + const char TT[] = "TT"; + const char A[] = "ª"; + int systemCode = atoi(pSystemStr) - 1; /* System 1..16 */ + int channelCode = atoi(pChannelStr); /* Channel 1..10 */ + int Level = atoi(pLevelStr); /* off,10,20,..,90,on */ + int DimStyle = atoi(pDimStyle); + int intCode = 0; + int checksum1 = 0; + int checksum2 = 0; + int intFade ; + int i ; + int rawChannelCode = 0; + + /* check converted parameters for validity */ + if ( (channelCode <= 0) || (channelCode > 10) || + (systemCode < 0) || (systemCode > 15) || + (Level < 0) || (Level > 10) || + (DimStyle < 0) || (DimStyle > 1)) + { + return 0; + } + + if (channelCode == 10) + { + channelCode = 0; + } + rawChannelCode = (1<<(9-channelCode)); + + strcat(pStrReturn, STARTCODE ) ; //Startcode, always like this; + intCode = (systemCode << 10) | rawChannelCode; + + for ( i = 13; i >= 0; --i) + { + if ((intCode>>i) & 1) + { + strcat(pStrReturn, TT ); + if (i % 2 == 0) + { + checksum2++; + } + else + { + checksum1++; + } + } + else + { + strcat(pStrReturn,A); + } + } + + if (checksum1 %2 == 0) + { + strcat(pStrReturn, TT ); + } + else + { + strcat(pStrReturn, A) ; //1st checksum + } + + if (checksum2 %2 == 0) + { + strcat(pStrReturn, TT ); + } + else + { + strcat(pStrReturn, A ) ; //2nd checksum + } + + if (DimStyle == 1) + { + intFade = 11 << 4; //Smooth + } + else + { + intFade = 1 << 4; //Instant + } + + switch ( Level ) + { + case 0 : + intCode = (10 | intFade) ; //Concat level and fade + break; + case 1 : + intCode = (1 | intFade) ; //Concat level and fade + break; + case 2 : + intCode = (2 | intFade) ; //Concat level and fade + break; + case 3 : + intCode = (3 | intFade) ; //Concat level and fade + break; + case 4 : + intCode = (4 | intFade) ; //Concat level and fade + break; + case 5 : + intCode = (5 | intFade) ; //Concat level and fade + break; + case 6 : + intCode = (6 | intFade) ; //Concat level and fade + break; + case 7 : + intCode = (7 | intFade) ; //Concat level and fade + break; + case 8 : + intCode = (8 | intFade) ; //Concat level and fade + break; + case 9 : + intCode = (9 | intFade) ; //Concat level and fade + break; + case 10 : + default : + intCode = (0 | intFade) ; //Concat level and fade + break; + } + + checksum1 = 0; + checksum2 = 0; + + for (i = 0; i < 6; ++i) + { + if ((intCode>>i) & 1) + { + strcat(pStrReturn, TT); + + if (i % 2 == 0) + { + checksum1++; + } + else + { + checksum2++; + } + } + else + { + strcat(pStrReturn, A ); + } + } + + if (checksum1 %2 == 0) + { + strcat(pStrReturn, TT); + } + else + { + strcat(pStrReturn, A ) ; //2nd checksum + } + + if (checksum2 %2 == 0) + { + strcat(pStrReturn, TT ); + } + else + { + strcat(pStrReturn, A ) ; //2nd checksum + } + + strcat(pStrReturn, "+"); + + return strlen(pStrReturn); +} + + void printUsage(void) { - printf("%s %s - Send RF remote commands\n", PROG_NAME, PROG_VERSION); + printf("%s v%s - Send RF remote commands\n", PROG_NAME, PROG_VERSION); printf("Usage: rfcmd DEVICE PROTOCOL [PROTOCOL_ARGUMENTS] \n"); printf("\t DEVICE: /dev/ttyUSB[0..n]\n" ); - printf("\t PROTOCOLS: NEXA, SARTANO, WAVEMAN\n" ); - printf("\t PROTOCOL ARGUMENTS - NEXA, WAVEMAN: \n"); - printf("\t\t HOUSE_CODE: A..P\n\t\t CHANNEL: 1..16\n\t\t OFF_ON: 0..1\n" ); - printf("\t PROTOCOL ARGUMENTS - SARTANO: \n"); - printf("\t\t CHANNEL: 0000000000..1111111111\n\t\t OFF_ON: 0..1\n" ); + printf("\t PROTOCOLS: NEXA, SARTANO, WAVEMAN, IKEA\n" ); + printf("\t PROTOCOL ARGUMENTS - NEXA, WAVEMAN:\n"); + printf("\t\tHOUSE_CODE: A..P\n\t\tCHANNEL: 1..16\n\t\tOFF_ON: 0..1\n" ); + printf("\t PROTOCOL ARGUMENTS - SARTANO:\n"); + printf("\t\tCHANNEL: 0000000000..1111111111\n\t\tOFF_ON: 0..1\n" ); + printf("\t PROTOCOL ARGUMENTS - IKEA:\n"); + printf("\t\tSYSTEM: 1..16\n\t\tDEVICE: 1..10\n"); + printf("\t\tDIM_LEVEL: 0..10\n\t\tDIM_STYLE: 0..1\n" ); printf("Copyright(C) Tord Andersson 2007\r\n"); }