diff --git a/openmilight.cpp b/openmilight.cpp index dc4475b..7acfd07 100644 --- a/openmilight.cpp +++ b/openmilight.cpp @@ -1,13 +1,4 @@ /** - * On a Raspberry Pi 2 compile with: - * - * g++ -Ofast -mfpu=vfp -mfloat-abi=hard -march=armv7-a -mtune=arm1176jzf-s -I/usr/local/include -L/usr/local/lib -lrf24-bcm PL1167_nRF24.cpp MiLightRadio.cpp openmili.cpp -o openmilight - * - * for receiver mode run with: - * sudo ./openmilight - * - * for sender mode run with: - * sudo ./openmilight "B0 F2 EA 6D B0 02 f0" */ #include @@ -17,6 +8,9 @@ #include +#include +#include + using namespace std; #include @@ -36,13 +30,13 @@ static int dupesPrinted = 0; void receive() { while(1){ - if (mlr.available()) { + if(mlr.available()) { printf("\n"); uint8_t packet[7]; size_t packet_length = sizeof(packet); mlr.read(packet, packet_length); - for (int i = 0; i < packet_length; i++) { + for(size_t i = 0; i < packet_length; i++) { printf("%02X ", packet[i]); fflush(stdout); } @@ -55,37 +49,62 @@ void receive() } } -void send(uint8_t color, uint8_t bright, uint8_t key, - uint8_t remote = 0x01, uint8_t remote_prefix = 0x00, - uint8_t prefix = 0xB8) +void send(uint8_t data[8]) { + static uint8_t seq = 1; - static uint8_t seq = 1; - - uint8_t data[7]; - data[0] = prefix; - data[1] = remote_prefix; - data[2] = remote; - data[3] = color; - data[4] = bright; - data[5] = key; + uint8_t resends = data[7]; + if(data[6] == 0x00){ data[6] = seq; - - if(debug){ - printf("Sending: "); - for (int i = 0; i < 7; i++) { - printf("%02X ", data[i]); - } - printf("\n"); + seq++; + } + + if(debug){ + printf("2.4GHz --> Sending: "); + for (int i = 0; i < 7; i++) { + printf("%02X ", data[i]); } + printf(" [x%d]\n", resends); + } - mlr.write(data, sizeof(data)); + mlr.write(data, 7); - for(int i = 0; i < 10; i++){ - mlr.resend(); - } + for(int i = 0; i < resends; i++){ + mlr.resend(); + } - seq++; +} + +void send(uint64_t v) +{ + uint8_t data[8]; + data[7] = (v >> (7*8)) & 0xFF; + data[0] = (v >> (6*8)) & 0xFF; + data[1] = (v >> (5*8)) & 0xFF; + data[2] = (v >> (4*8)) & 0xFF; + data[3] = (v >> (3*8)) & 0xFF; + data[4] = (v >> (2*8)) & 0xFF; + data[5] = (v >> (1*8)) & 0xFF; + data[6] = (v >> (0*8)) & 0xFF; + + send(data); +} + +void send(uint8_t color, uint8_t bright, uint8_t key, + uint8_t remote = 0x01, uint8_t remote_prefix = 0x00, + uint8_t prefix = 0xB8, uint8_t seq = 0x00, uint8_t resends = 10) +{ + uint8_t data[8]; + data[0] = prefix; + data[1] = remote_prefix; + data[2] = remote; + data[3] = color; + data[4] = bright; + data[5] = key; + data[6] = seq; + data[7] = resends; + + send(data); } double getTime() @@ -95,29 +114,140 @@ double getTime() return tv.tv_sec + ((double)tv.tv_usec) * 1e-6; } +void fade(uint8_t prefix, uint8_t rem_p, uint8_t remote, uint8_t color, uint8_t bright, uint8_t resends) +{ + while(1){ + color++; + send(color, 0x00, 0x0F, 0x44, 0x00); + usleep(20000); + } +} + +void strobe(uint8_t prefix, uint8_t rem_p, uint8_t remote, uint8_t bright, uint8_t resends) +{ + while(1){ + uint8_t color = rand() % 255; + send(color, bright, 0x0F, remote, resends); + usleep(50000); + } +} + +void udp() +{ + int sockfd; + struct sockaddr_in servaddr, cliaddr; + char mesg[42]; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + bzero(&servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(8899); + bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); + + while(1){ + socklen_t len = sizeof(cliaddr); + int n = recvfrom(sockfd, mesg, 41, 0, (struct sockaddr *)&cliaddr, &len); + + mesg[n] = '\0'; + + if(n == 7){ + if(debug){ + printf("UDP --> Received hex value\n"); + } + uint8_t data[7]; + for(int i = 0; i < 7; i++){ + data[i] = (uint8_t)mesg[i]; + } + send(data); + } + else { + fprintf(stderr, "Message has invalid size %d (expecting 7)!\n", n); + } + } +} + +void usage(const char *arg, const char *options){ + printf("\n"); + printf("Usage: sudo %s [%s]\n", arg, options); + printf("\n"); + printf(" -h Show this help\n"); + printf(" -d Show debug output\n"); + printf(" -f Fade mode\n"); + printf(" -s Strobe mode\n"); + printf(" -l Listening (receiving) mode\n"); + printf(" -u UDP mode\n"); + printf(" -n NN Resends of the same message\n"); + printf(" -p PP Prefix value (Disco Mode)\n"); + printf(" -q RR First byte of the remote\n"); + printf(" -r RR Second byte of the remote\n"); + printf(" -c CC Color byte\n"); + printf(" -b BB Brightness byte\n"); + printf(" -k KK Key byte\n"); + printf(" -v SS Sequence byte\n"); + printf(" -w SSPPRRRRCCBBKKNN Complete message to send\n"); + printf("\n"); + printf(" Author: Roy Bakker (2015)\n"); + printf("\n"); + printf(" Inspired by sources from: - https://github.com/henryk/\n"); + printf(" - http://torsten-traenkner.de/wissen/smarthome/openmilight.php\n"); + printf("\n"); +} + int main(int argc, char** argv) { - mlr.begin(); + int do_receive = 0; + int do_udp = 0; + int do_strobe = 0; + int do_fade = 0; + int do_command = 0; + + uint8_t prefix = 0xB8; + uint8_t rem_p = 0x00; + uint8_t remote = 0x01; + uint8_t color = 0x00; + uint8_t bright = 0x00; + uint8_t key = 0x01; + uint8_t seq = 0x00; + uint8_t resends = 10; + + uint64_t command = 0x00; int c; - - uint8_t prefix = 0xB8; - uint8_t rem_p = 0x00; - uint8_t remote = 0x01; - uint8_t color = 0x01; - uint8_t bright = 0x01; - uint8_t key = 0x01; + uint64_t tmp; - while((c = getopt(argc, argv, "dlq:r:c:b:k:w:")) != -1){ + const char *options = "hdfslun:p:q:r:c:b:k:v:w:"; + + while((c = getopt(argc, argv, options)) != -1){ switch(c){ + case 'h': + usage(argv[0], options); + exit(0); + break; case 'd': debug = 1; break; + case 'f': + do_fade = 1; + break; + case 's': + do_strobe = 1; + break; case 'l': - printf("Receiving mode, press Ctrl-C to end\n"); - receive(); - exit(0); + do_receive = 1; + break; + case 'u': + do_udp = 1; + break; + case 'n': + tmp = strtoll(optarg, NULL, 10); + resends = (uint8_t)tmp; + break; + case 'p': + tmp = strtoll(optarg, NULL, 16); + prefix = (uint8_t)tmp; break; case 'q': tmp = strtoll(optarg, NULL, 16); @@ -139,20 +269,21 @@ int main(int argc, char** argv) tmp = strtoll(optarg, NULL, 16); key = (uint8_t)tmp; break; - case 'w': + case 'v': tmp = strtoll(optarg, NULL, 16); - rem_p = (tmp >> (4*8)) & 0xFF; - remote = (tmp >> (3*8)) & 0xFF; - color = (tmp >> (2*8)) & 0xFF; - bright = (tmp >> (1*8)) & 0xFF; - key = (tmp >> (0*8)) & 0xFF; + seq = (uint8_t)tmp; + break; + case 'w': + do_command = 1; + command = strtoll(optarg, NULL, 16); break; case '?': - if(optopt == 'q' || optopt == 'r' || optopt == 'c' || - optopt == 'b' || optopt == 'k' || optopt == 'w'){ + if(optopt == 'n' || optopt == 'p' || optopt == 'q' || + optopt == 'r' || optopt == 'c' || optopt == 'b' || + optopt == 'k' || optopt == 'w'){ fprintf(stderr, "Option -%c requires an argument.\n", optopt); } - else if(isprint (optopt)){ + else if(isprint(optopt)){ fprintf(stderr, "Unknown option `-%c'.\n", optopt); } else{ @@ -165,6 +296,35 @@ int main(int argc, char** argv) } } + int ret = mlr.begin(); + + if(ret < 0){ + fprintf(stderr, "Failed to open connection to the 2.4GHz module.\n"); + fprintf(stderr, "Make sure to run this program as root (sudo)\n\n"); + usage(argv[0], options); + exit(-1); + } + + if(do_receive){ + printf("Receiving mode, press Ctrl-C to end\n"); + receive(); + } + + if(do_udp){ + printf("UDP mode, press Ctrl-C to end\n"); + udp(); + } + + if(do_fade){ + printf("Fade mode, press Ctrl-C to end\n"); + fade(prefix, rem_p, remote, color, bright, resends); + } + + if(do_strobe){ + printf("Strobe mode, press Ctrl-C to end\n"); + strobe(prefix, rem_p, remote, bright, resends); + } + /* double from = getTime(); @@ -177,7 +337,12 @@ int main(int argc, char** argv) printf("Time: %f %f %f\n", time, time / 200, 1 / (time/200)); */ - send(color, bright, key, remote, rem_p, prefix); + if(do_command){ + send(command); + } + else{ + send(color, bright, key, remote, rem_p, prefix, seq, resends); + } return 0; }