diff options
Diffstat (limited to 'trasmitter')
-rw-r--r-- | trasmitter/.gitignore | 3 | ||||
-rw-r--r-- | trasmitter/Makefile | 10 | ||||
-rw-r--r-- | trasmitter/README.rst.txt | 42 | ||||
-rw-r--r-- | trasmitter/arduino/Makefile | 19 | ||||
-rw-r--r-- | trasmitter/arduino/sender.ino | 93 | ||||
-rw-r--r-- | trasmitter/sender-chip.c | 146 | ||||
-rw-r--r-- | trasmitter/sender-chip.pl | 91 |
7 files changed, 404 insertions, 0 deletions
diff --git a/trasmitter/.gitignore b/trasmitter/.gitignore new file mode 100644 index 0000000..bd6f3a9 --- /dev/null +++ b/trasmitter/.gitignore @@ -0,0 +1,3 @@ +/arduino/build-*/ +/sender-chip + diff --git a/trasmitter/Makefile b/trasmitter/Makefile new file mode 100644 index 0000000..b31025b --- /dev/null +++ b/trasmitter/Makefile @@ -0,0 +1,10 @@ +CFLAGS = -Wall + +all: sender-chip setcap + +sender-chip: sender-chip.c + +setcap: sender-chip + sudo setcap CAP_SYS_NICE=eip $< + +.PHONY: setcap diff --git a/trasmitter/README.rst.txt b/trasmitter/README.rst.txt new file mode 100644 index 0000000..78200a4 --- /dev/null +++ b/trasmitter/README.rst.txt @@ -0,0 +1,42 @@ +Some links: + +* capturing radio signals + http://www.stevenhale.co.uk/main/2013/08/home-automation-reverse-engineering-a-worcester-bosch-dt10rf-wireless-thermostat/ + https://damn.technology/controlling-british-gas-wr1-receiver-arduino + http://rossharper.net/2015/11/decoding-a-siemens-rcr10433-thermostat-signal-to-control-a-boiler-from-a-raspberry-pi/ + +IMPORTANT: the transmitter prefers 3.3V, it stops working after a +while on 5V. + +Reveng +====== + +Sampled at 192k samples/second, found that the transmissions had 3 +types of (presumably square) pulses: + +======== ======= ======== +name samples duration +======== ======= ======== +narrow 200 ~ 1ms +middle 300 ~ 1.5ms +wide 400 ~ 2ms +======== ======= ======== + +The two sequences are: + +* ``nnnnnnWnWnnMnnMnnnnnWnnnnMnMWn`` +* ``nnnnnnWnWnnMnnMnnnnnnnnnnWMMWn`` + +Actually no, the pulses are not ½ high and ½ low, they're shaped +weird. The source code has the correct widths. + +Without Arduino +=============== + +The GPIO / XIO pins on NextThing's CHIP, even when driven via the `slow +sysfs interface`_, seem to be fast enough for our purposes. + +See the ``sender-chip.pl`` test program. + +If we keep the ``*/value`` file open, we get good enough timing. The +``sender-chip.c`` program works. diff --git a/trasmitter/arduino/Makefile b/trasmitter/arduino/Makefile new file mode 100644 index 0000000..9815090 --- /dev/null +++ b/trasmitter/arduino/Makefile @@ -0,0 +1,19 @@ +ARDMK_DIR = /home/dakkar/src/Arduino-Makefile +ARDUINO_DIR = /usr/share/arduino +MONITOR_PORT = /dev/ttyACM* +CURRENT_DIR = $(basename $(CURDIR)) +AVR_TOOLS_DIR = /usr +AVRDUDE_CONF = /etc/avrdude.conf + +PROJECT_DIR = $(CURDIR) +BOARD_TAG = uno +MONITOR_BAUDRATE = 115200 + +CFLAGS_STD = -std=gnu11 +CXXFLAGS_STD = -std=gnu++11 +CXXFLAGS += -pedantic -Wall -Wextra + +include $(ARDMK_DIR)/Arduino.mk + +check-syntax: + $(CXX) -c -include Arduino.h -x c++ $(CXXFLAGS) $(CPPFLAGS) -fsyntax-only $(CHK_SOURCES) diff --git a/trasmitter/arduino/sender.ino b/trasmitter/arduino/sender.ino new file mode 100644 index 0000000..9373875 --- /dev/null +++ b/trasmitter/arduino/sender.ino @@ -0,0 +1,93 @@ +const uint16_t pulseScale = 520; // usec per sample unit + +// alternate HIGH and LOW, first one of each array is HIGH +const uint8_t prologue[] = { + 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, + 2,3, 1,1, 2,2, 1,1, 1,1, 2,1, + 1,1, 1,1, 1,2, 1,1, 1,1, 1,1, + 1,1, 1,1, +}; +const size_t prologueSize = sizeof(prologue) / sizeof(uint8_t); + +const uint8_t epilogue[] = { + 1,2, 2,2, 1,3, // the last value doesn't much matter +}; +const size_t epilogueSize = sizeof(epilogue) / sizeof(uint8_t); + +const uint8_t onSignal[] = { + 2,2, 1,1, 1,1, 1,1, 1,1, 2,1, 1,1, +}; +const size_t onSize = sizeof(onSignal) / sizeof(uint8_t); + +const uint8_t offSignal[] = { + 1,1, 1,1, 1,1, 1,1, 1,1, 2,2, 2,1, +}; +const size_t offSize = sizeof(offSignal) / sizeof(uint8_t); + +const int nTxPin = 7; // Arduino digital pin you're using for radio data. + +void transmitArray(const uint8_t pulses[], size_t pulseCount) { + for(size_t idx = 0; idx < pulseCount; idx+=2) { + digitalWrite(nTxPin, HIGH); + delayMicroseconds(pulseScale*pulses[idx]); + + digitalWrite(nTxPin, LOW); + delayMicroseconds(pulseScale*pulses[idx+1]); + } +} + +void transmitSignal(const uint8_t signal[], size_t signalSize) { + transmitArray(prologue,prologueSize); + transmitArray(signal,signalSize); + transmitArray(epilogue,epilogueSize); +} + +void sendTrain(const uint8_t signal[], size_t signalSize) { + transmitSignal(signal,signalSize); + delay(1000); + transmitSignal(signal,signalSize); + delay(2000); + transmitSignal(signal,signalSize); +} + + +/** + * The setup() function is called when a sketch starts. Used to initialize + * variables, pin modes, start using libraries, etc. The setup function will + * only run once, after each powerup or reset of the Arduino board. + */ +void setup() +{ + pinMode(nTxPin, OUTPUT); + digitalWrite(nTxPin, LOW); + + Serial.begin(9600); + Serial.println("Press 0 to turn off heating"); + Serial.println("Press 1 to turn on heating"); + +} + + +/** + * The loop() function loops consecutively, allowing the program to change and + * respond. Used to actively control the Arduino board. + */ +void loop() +{ + if (Serial.available() > 0) + { + int nIncomming = Serial.read(); + if (nIncomming == 49) { // char code for 1 + Serial.println("ON"); + sendTrain(onSignal,onSize); + } + + if (nIncomming == 48) { // char code for 0 + Serial.println("OFF"); + sendTrain(offSignal,offSize); + } + + Serial.println("Press 0 to turn off heating"); + Serial.println("Press 1 to turn on heating"); + } +}
\ No newline at end of file diff --git a/trasmitter/sender-chip.c b/trasmitter/sender-chip.c new file mode 100644 index 0000000..7ada0cf --- /dev/null +++ b/trasmitter/sender-chip.c @@ -0,0 +1,146 @@ +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <sched.h> +#include <inttypes.h> + +#define PIN "132" + +void init_pin() { + int fd = open("/sys/class/gpio/export",O_WRONLY); + char buf[16]; + int len = sprintf(buf,"%s\n",PIN); + write(fd,buf,len); + close(fd); + fd = open("/sys/class/gpio/gpio" PIN "/direction",O_WRONLY); + write(fd,"out\n",4); + close(fd); +} + +void deinit_pin() { + int fd = open("/sys/class/gpio/unexport",O_WRONLY); + char buf[16]; + int len = sprintf(buf,"%s\n",PIN); + write(fd,buf,len); + close(fd); +} + +int pin_fd; +void write_pin(uint8_t value) { + if (!pin_fd) { + pin_fd = open("/sys/class/gpio/gpio" PIN "/value",O_WRONLY); + } + char buf[16]; + int len = sprintf(buf,"%d\n",value); + write(pin_fd,buf,len); +} + +void init_sched() { + struct sched_param sp; + sp.sched_priority=99; + + // to make this work, sudo setcap CAP_SYS_NICE=eip clock + sched_setscheduler(0,SCHED_RR,&sp); +} + +const int width=520000; +struct timespec next_step; +void send_array(const uint8_t values[],size_t len) { + if (next_step.tv_sec == 0) { + clock_gettime(CLOCK_REALTIME,&next_step); + } + uint8_t pin_value = 1; + for (int i=0; i<len; ++i) { + write_pin(pin_value); + pin_value = 1 - pin_value; + + next_step.tv_nsec += width * values[i]; + + if (next_step.tv_nsec > 1000000000UL) { + next_step.tv_nsec -= 1000000000UL; + ++next_step.tv_sec; + } + + int rc = clock_nanosleep(CLOCK_REALTIME, + TIMER_ABSTIME, + &next_step, + NULL); + if (rc) { + printf("problems: %d\n",rc); + } + } +} +void my_sleep(uint8_t seconds) { + next_step.tv_sec += seconds; + + int rc = clock_nanosleep(CLOCK_REALTIME, + TIMER_ABSTIME, + &next_step, + NULL); + if (rc) { + printf("problems: %d\n",rc); + } +} + +// alternate HIGH and LOW, first one of each array is HIGH +const uint8_t prologue[] = { + 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, + 2,3, 1,1, 2,2, 1,1, 1,1, 2,1, + 1,1, 1,1, 1,2, 1,1, 1,1, 1,1, + 1,1, 1,1, +}; +const size_t prologueSize = sizeof(prologue) / sizeof(uint8_t); + +const uint8_t epilogue[] = { + 1,2, 2,2, 1,3, // the last value doesn't much matter +}; +const size_t epilogueSize = sizeof(epilogue) / sizeof(uint8_t); + +const uint8_t onSignal[] = { + 2,2, 1,1, 1,1, 1,1, 1,1, 2,1, 1,1, +}; +const size_t onSize = sizeof(onSignal) / sizeof(uint8_t); + +const uint8_t offSignal[] = { + 1,1, 1,1, 1,1, 1,1, 1,1, 2,2, 2,1, +}; +const size_t offSize = sizeof(offSignal) / sizeof(uint8_t); + +void transmitSignal(const uint8_t signal[], size_t signalSize) { + send_array(prologue,prologueSize); + send_array(signal,signalSize); + send_array(epilogue,epilogueSize); +} + +void sendTrain(const uint8_t signal[], size_t signalSize) { + transmitSignal(offSignal,offSize); + my_sleep(1); + transmitSignal(signal,signalSize); + my_sleep(2); + transmitSignal(offSignal,offSize); +} + +int main(int argc,char **argv) { + if (argc != 2) { + fprintf(stderr,"thing 0/1\n"); + return 1; + } + + init_sched(); + init_pin(); + write_pin(0); + + if (argv[1][0] == '1') { + sendTrain(onSignal,onSize); + } + else { + sendTrain(offSignal,offSize); + } + + deinit_pin(); + + return 0; +} diff --git a/trasmitter/sender-chip.pl b/trasmitter/sender-chip.pl new file mode 100644 index 0000000..f6d3dd3 --- /dev/null +++ b/trasmitter/sender-chip.pl @@ -0,0 +1,91 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Time::HiRes qw(usleep sleep gettimeofday tv_interval); + +# my $base = do { +# open my $fh,'<','/sys/class/gpio/gpiochip405/base' or die "can't get base: $!"; +# my $line = <$fh>; +# chomp($line); +# $line; +# }; + +sub gpio_enable { + my ($pin,$state) = @_; + + if ($state) { + open my $fh,'>','/sys/class/gpio/export' or die "Can't export: $!"; + print $fh $pin,"\n"; + } + else { + open my $fh,'>','/sys/class/gpio/unexport' or die "Can't unexport: $!"; + print $fh $pin,"\n"; + } +} + +sub gpio_direction { + my ($pin,$direction) = @_; + + my $file = "/sys/class/gpio/gpio$pin/direction"; + open my $fh,'>',$file + or die "Can't direction $file: $!"; + print $fh ($direction ? 'out' : 'in' ),"\n"; +} + +sub gpio_write { + my ($pin,$value) = @_; + + open my $fh,'>',"/sys/class/gpio/gpio$pin/value" + or die "Can't write: $!"; + print $fh $value,"\n"; +} + +my $pin = 132; # CSID0 +#my $pin = $base+0; # XIO0 + +gpio_enable($pin,1); +gpio_direction($pin,1); +gpio_write($pin,0); +$SIG{INT} = sub {warn"disabling";gpio_enable($pin,0) }; +END { warn"disabling";gpio_enable($pin,0) } + +my $width = 370; # this seems to provide pulse widths close enough to + # what we need, it's 106 samples at 192kHz + +sub send_array { + my $state = 1; + for (@_) { + gpio_write($pin,$state); + usleep($width*$_); + $state = $state ? 0 : 1; + } +} + +my @prologue = ( + 1,1, 1,1, 1,1, 1,1, 1,1, 1,1, + 2,3, 1,1, 2,2, 1,1, 1,1, 2,1, + 1,1, 1,1, 1,2, 1,1, 1,1, 1,1, + 1,1, 1,1, +); +my @epilogue = ( + 1,2, 2,2, 1,3, # the last value doesn't much matter +); + +my @on_signal = ( + 2,2, 1,1, 1,1, 1,1, 1,1, 2,1, 1,1, +); +my @off_signal = ( + 1,1, 1,1, 1,1, 1,1, 1,1, 2,2, 2,1, +); + +my @train = ( + @prologue, + ( $ARGV[0] ? @on_signal : @off_signal ), + @epilogue, +); + +send_array(@train); +sleep(1); +send_array(@train); +sleep(2); +send_array(@train); |