├── src ├── .gitignore ├── Makefile ├── common.h ├── cul443.c ├── nexa.c ├── protocol.h ├── impulse.c ├── sartano.c ├── ikea.c └── rfctl.c ├── .gitignore ├── kernel ├── udev.rules ├── .gitignore ├── Makefile ├── README.md ├── COPYING └── rfctl.c ├── Makefile ├── .travis.yml ├── onoff.sh ├── onoff.tab ├── HARDWARE.md ├── README.md └── COPYING /src/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | rfctl 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | /ID 3 | /GTAGS 4 | /GSYMS 5 | /GRTAGS 6 | /GPATH 7 | -------------------------------------------------------------------------------- /kernel/udev.rules: -------------------------------------------------------------------------------- 1 | KERNEL=="rfctl", SUBSYSTEM=="rfctl", GROUP="dialout", MODE="0660" 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all clean install distclean: 3 | @make -C kernel $@ 4 | @make -C src $@ 5 | 6 | -------------------------------------------------------------------------------- /kernel/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.ko 4 | *.cmd 5 | *.mod.c 6 | .tmp_versions 7 | Module.symvers 8 | modules.order 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | compiler: 4 | - gcc 5 | - clang 6 | 7 | sudo: false 8 | 9 | addons: 10 | apt: 11 | packages: 12 | - tree 13 | - linux-headers-generic 14 | 15 | script: 16 | - cd src 17 | - make 18 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | EXEC_NAME = rfctl 2 | SRCS = rfctl.c cul443.c nexa.c ikea.c impulse.c sartano.c 3 | CROSS_COMPILE = 4 | CC = $(CROSS_COMPILE)gcc 5 | CFLAGS = -O2 -W -Wall -Wextra -Wno-unused-parameter -DVERSION=\"0.9\" 6 | LDFLAGS = 7 | LIBS = 8 | OBJS = $(SRCS:.c=.o) 9 | TARGET_ROOT = 10 | INSTALL_DIR = $(TARGET_ROOT)/usr/local/bin 11 | 12 | all: $(EXEC_NAME) 13 | 14 | OBJS: $(SRCS:.c=.o) 15 | $(CC) $(CFLAGS) -c $< 16 | 17 | $(OBJS): common.h protocol.h 18 | 19 | $(EXEC_NAME): $(OBJS) 20 | $(CC) -o $(EXEC_NAME) $(OBJS) $(LDFLAGS) $(LIBS) 21 | 22 | # Install will require root privilegies or sudo 23 | install: $(EXEC_NAME) 24 | cp $(EXEC_NAME) $(INSTALL_DIR) 25 | 26 | clean: 27 | rm -f *.o $(EXEC_NAME) core 28 | 29 | distclean: 30 | rm -f *~ 31 | rm -f *.o $(EXEC_NAME) core 32 | 33 | -------------------------------------------------------------------------------- /onoff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Example 433 MHz indoor light control 3 | # With optional support for Pimoroni Firely project 4 | # 5 | # Add to your crontab using: 6 | # 7 | # crontab onoff.tab 8 | # 9 | 10 | onoff=$1 11 | #FIREFLY=/home/pi/firefly.py 12 | RFCTL=/usr/local/bin/rfctl 13 | 14 | onoff() 15 | { 16 | for i in `seq 1 4`; do 17 | echo "$RFCTL -p CONRAD -g 1 -c $i -l $1" 18 | sleep 1 19 | $RFCTL -p CONRAD -g 1 -c $i -l $1 20 | done 21 | } 22 | 23 | if [ $# -lt 1 ]; then 24 | echo "usage: $0 <0|1>" 25 | exit 1 26 | fi 27 | 28 | if [ "x$onoff" = "x0" -o -f /tmp/firefly.pid ]; then 29 | PID=`cat /tmp/firefly.pid` 30 | kill -TERM $PID 31 | onoff 0 32 | rm /tmp/firefly.pid 2>/dev/null 33 | else 34 | if [ -n "$FIREFLY" ]; then 35 | python firefly.py & 36 | echo $! >/tmp/firefly.pid 37 | fi 38 | onoff 1 39 | fi 40 | 41 | exit 0 42 | -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | # rfctl kernel driver 2 | # 3 | # make 4 | # sudo make insmod 5 | # or 6 | # sudo make install 7 | # 8 | 9 | ifneq ($(KERNELRELEASE),) 10 | 11 | # For kernel build system 12 | obj-m += rfctl.o 13 | 14 | else 15 | 16 | # Helpers to call kernel build system and install 17 | ifneq ($(KERNEL_DIR),) 18 | KERNELDIR := $(KERNEL_DIR) 19 | else 20 | ifeq ($(KERNELDIR),) 21 | KERNELDIR := /lib/modules/`uname -r`/build 22 | endif 23 | endif 24 | PWD := $(shell pwd) 25 | 26 | all default: 27 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 28 | 29 | clean: 30 | $(MAKE) -C $(KERNELDIR) M=$(PWD) clean 31 | 32 | insmod: 33 | -insmod rfctl.ko 34 | # -mknod /dev/rfctl c `grep rf /proc/devices | sed 's/\([0-9]*\) rfctl/\1/'` 0 35 | # chown root:dialout /dev/rfctl 36 | # chmod g+rw /dev/rfctl 37 | 38 | rmmod: 39 | -rmmod rfctl.ko 40 | 41 | install: insmod 42 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install 43 | cp -v udev.rules /etc/udev/rules.d/99-rfctl.rules 44 | depmod -a 45 | grep rfctl /etc/modules || echo rfctl >> /etc/modules 46 | 47 | endif 48 | -------------------------------------------------------------------------------- /onoff.tab: -------------------------------------------------------------------------------- 1 | # Edit this file to introduce tasks to be run by cron. 2 | # 3 | # Load file with: crontab onoff.tab 4 | # Edit contab by: cronteb -e 5 | # 6 | # Each task to run has to be defined through a single line 7 | # indicating with different fields when the task will be run 8 | # and what command to run for the task 9 | # 10 | # To define the time you can provide concrete values for 11 | # minute (m), hour (h), day of month (dom), month (mon), 12 | # and day of week (dow) or use '*' in these fields (for 'any').# 13 | # Notice that tasks will be started based on the cron's system 14 | # daemon's notion of time and timezones. 15 | # 16 | # Output of the crontab jobs (including errors) is sent through 17 | # email to the user the crontab file belongs to (unless redirected). 18 | # 19 | # For example, you can run a backup of all your user accounts 20 | # at 5 a.m every week with: 21 | # 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ 22 | # 23 | # For more information see the manual pages of crontab(5) and cron(8) 24 | # 25 | # m h dom mon dow command 26 | 55 5 * * * /home/pi/rfctl/onoff.sh 0 27 | 55 20 * * * /home/pi/rfctl/onoff.sh 1 28 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* Control tool for NEXA and other RF remote receivers 2 | * 3 | * Copyright (C) 2010, 2012 Tord Andersson 4 | * Copyright (C) 2017 Joachim Nilsson 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, visit the Free Software Foundation 18 | * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the 19 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #ifndef RFCTL_COMMON_H_ 24 | #define RFCTL_COMMON_H_ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define PRINT(fmt, args...) if (verbose) printf(fmt, ##args) 34 | 35 | extern bool verbose; 36 | 37 | #endif /* RFCTL_COMMON_H_ */ 38 | -------------------------------------------------------------------------------- /src/cul443.c: -------------------------------------------------------------------------------- 1 | /* Control tool for NEXA and other RF remote receivers 2 | * 3 | * Copyright (C) 2010, 2012 Tord Andersson 4 | * Copyright (C) 2017 Joachim Nilsson 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, visit the Free Software Foundation 18 | * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the 19 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #include "common.h" 24 | #include "protocol.h" 25 | 26 | /* Convert generic bitstream format to CUL433 format */ 27 | int bitstream2cul443(int32_t *bitstream, int len, int repeat, char *cul) 28 | { 29 | int i; 30 | int pulses = 0; 31 | char tmp[20]; 32 | 33 | *cul = '\0'; 34 | 35 | strcat(cul, "\r\nX01\r\n"); /* start radio */ 36 | strcat(cul, "E\r\n"); /* empty tx buffer */ 37 | 38 | for (i = 0; i < len; i++) { 39 | sprintf(tmp, "%04X", LIRC_VALUE(bitstream[i])); 40 | 41 | if (LIRC_IS_PULSE(bitstream[i]) == true) { 42 | strcat(cul, "A"); 43 | strcat(cul, tmp); 44 | pulses++; 45 | } else { /* low */ 46 | 47 | strcat(cul, tmp); 48 | strcat(cul, "\r\n"); 49 | } 50 | } 51 | 52 | if (pulses > 1) { 53 | /* number of repetitions */ 54 | sprintf(tmp, "S%02d\r\n", repeat); 55 | strcat(cul, tmp); 56 | 57 | return strlen(cul); 58 | } 59 | 60 | cul[0] = '\0'; 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /kernel/README.md: -------------------------------------------------------------------------------- 1 | rfctl driver 2 | ============ 3 | 4 | This LIRC style driver transmits and records 433.92 MHz pulses and pause 5 | lengths by bit banging a single GPIO pin. To build on target you first 6 | need to install the kernel headers: 7 | 8 | ```sh 9 | sudo apt install raspberrypi-kernel-headers 10 | ``` 11 | 12 | Now we can build and install the kernel driver: 13 | 14 | ```sh 15 | cd rfctl/kernel 16 | make 17 | sudo make install 18 | ``` 19 | 20 | The `install` target calls `make insmod`, sets the correct direction of 21 | the GPIO pin, and also creates the device node used by the `rfctl` tool. 22 | 23 | Most users are done now and can start playing with `rfctl`. If you run 24 | into problems, check the below sections for some pointers. 25 | 26 | 27 | gpio direction 28 | -------------- 29 | 30 | For modern Raspberry Pi kernels the GPIO handling is a bit different. 31 | One needs to define in a device tree overlay the desired behavior of our 32 | pin(s). Writing a device tree overlay is outside the scope of this tiny 33 | README, but we can abuse an existing overlay. Add this line to the file 34 | `/boot/config.txt`: 35 | 36 | dtoverlay=gpio-poweroff,gpiopin=17,active_low=1 37 | 38 | 39 | troubleshooting 40 | --------------- 41 | 42 | The `KERNELDIR=` environment variable may be necessary to set if your 43 | kernel headers are not in `/lib/modules`: 44 | 45 | ```sh 46 | make KERNELDIR=/lib/modules/`uname -r`/build 47 | sudo insmod rfctl.ko 48 | ``` 49 | 50 | Verify that the device node is created after `insmod`, add it if not 51 | already there: 52 | 53 | ```sh 54 | ls -al /dev/rfctl 55 | dmesg 56 | cat /proc/devices |grep rfctl 57 | sudo mknod /dev/rfctl c 243 0 58 | sudo chown root:dialout /dev/rfctl 59 | sudo chmod g+rw /dev/rfctl 60 | ``` 61 | 62 | The dynamically allocated major device number can be found in the file 63 | `/proc/devices`, here the example `243` is used but it will vary 64 | depending on your system: 65 | 66 | ```sh 67 | grep rfctl /proc/devices | sed 's/\([0-9]*\) rfctl/\1/' 68 | ``` 69 | 70 | -------------------------------------------------------------------------------- /HARDWARE.md: -------------------------------------------------------------------------------- 1 | Hardware for the rfbb driver 2 | ============================ 3 | Latest update 2017-01-30, Joachim Nilsson 4 | 5 | Note! A monospaced font might make it easier to read tables below! 6 | 7 | 8 | RF Transmitter module pinout 9 | ---------------------------- 10 | 11 | A common RF transmitter module like [TX433N][] (433.92 MHz) has the 12 | following pinout: 13 | 14 | Pin Function 15 | --------------- 16 | 1 GND 17 | 2 Digital in 18 | 3 VCC 19 | 4 Antenna 20 | 21 | Make sure that VCC is able to operate from 5V DC and the Data In 22 | threshold is compatible with 3.3V logic. 23 | 24 | The range is often 3 - 12 V DC, but there might be other versions! 25 | 26 | 27 | RF Receiver module pinout 28 | ------------------------- 29 | 30 | A common RF receiver module, like [RX433N][] (433.92 MHz) has the 31 | following pinout: 32 | 33 | Pin Function 34 | --------------- 35 | 1 GND 36 | 2 Digital Out 37 | 3 Linear Out 38 | 4 VCC 39 | 5 VCC 40 | 6 GND 41 | 7 GND 42 | 8 Antenna 43 | 44 | Make sure that VCC is able to operate from 5V DC and the Data Out 45 | threshold is compatible with 3.3V logic. 46 | 47 | The range is often 3 - 12 V DC, but there might be other versions! 48 | 49 | 50 | Raspberry Pi Example 51 | -------------------- 52 | 53 | RPI TX433N/RX433N 54 | ------------------------------------------------------------- 55 | Pin, function - Pin, function 56 | P1-02, 5V0 - 3, VCC 57 | P1-06, GND - 1, GND 58 | P1-11, GPIO17 - 2, Data in 59 | P1-13, GPIO27 - 2, Data out 60 | No connection - 4/8, Antenna. Connect a 170mm wire as antenna 61 | 62 | 63 | RF Sockets 64 | ---------- 65 | 66 | There are several compatible 433 MHz remote controllable sockets on the 67 | market using the same base protocol. 68 | 69 | - [4teiliges Funk-Schalt-Set 433 MHz](https://www.conrad.de/de/4teiliges-funk-schalt-set-433-mhz-646452.html) (German/Swedish version) 70 | - [Remote Controlled Mains Sockets 5 Pack](http://www.maplin.co.uk/p/remote-controlled-mains-sockets-5-pack-n38hn) (UK version) 71 | - [Fjärrströmbrytare 433 MHz](https://www.kjell.com/se/sortiment/el-verktyg/smarta-hem/433-mhz/fjarrstrombrytare/utanpaliggande-brytare/luxorparts-fjarrstrombrytare-2000-w-3-pack-p50219) (Swedish) 72 | 73 | 74 | [TX433N]: https://www.kjell.com/se/sortiment/el-verktyg/elektronik/fjarrstyrning/tx433n-sandarmodul-433-mhz-p88901 75 | [RX433N]: https://www.kjell.com/se/sortiment/el-verktyg/elektronik/fjarrstyrning/rx433n-mottagarmodul-433-mhz-p88900 76 | -------------------------------------------------------------------------------- /src/nexa.c: -------------------------------------------------------------------------------- 1 | /* Control tool for NEXA and other RF remote receivers 2 | * 3 | * Copyright (C) 2010, 2012 Tord Andersson 4 | * Copyright (C) 2017 Joachim Nilsson 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, visit the Free Software Foundation 18 | * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the 19 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #include "common.h" 24 | #include "protocol.h" 25 | 26 | static int bs(const char *group, const char *chan, const char *onoff, int32_t *bitstream, int *repeat, bool waveman) 27 | { 28 | int house; 29 | int channel; 30 | int enable; 31 | int code = 0; 32 | const int unknown = 0x6; 33 | int bit; 34 | int bitmask = 0x0001; 35 | int i = 0; 36 | 37 | *repeat = NEXA_REPEAT; 38 | 39 | house = (int)((*group) - 65); /* House 'A'..'P' */ 40 | channel = atoi(chan) - 1; /* Channel 1..16 */ 41 | enable = atoi(onoff); /* ON/OFF 0..1 */ 42 | 43 | PRINT("House: %d, channel: %d, on_off: %d\n", house, channel, enable); 44 | 45 | /* check converted parameters for validity */ 46 | if ((house < 0) || (house > 15) || // House 'A'..'P' 47 | (channel < 0) || (channel > 15) || (enable < 0) || (enable > 1)) { 48 | fprintf(stderr, "Invalid group (house), channel or on/off code\n"); 49 | return 0; 50 | } 51 | 52 | /* 53 | * b0..b11 code where 'X' will be represented by 1 for simplicity. 54 | * b0 will be sent first 55 | */ 56 | code = house; 57 | code |= (channel << 4); 58 | if (waveman && enable == 0) { 59 | } else { 60 | code |= (unknown << 8); 61 | code |= (enable << 11); 62 | } 63 | 64 | /* convert to send cmd bitstream */ 65 | for (bit = 0; bit < 12; bit++) { 66 | if ((bitmask & code) == 0) { 67 | /* bit timing might need further refinement */ 68 | /* 340 us high, 1020 us low, 340 us high, 1020 us low */ 69 | bitstream[i++] = LIRC_PULSE(NEXA_SHORT_PERIOD); 70 | bitstream[i++] = LIRC_SPACE(NEXA_LONG_PERIOD); 71 | bitstream[i++] = LIRC_PULSE(NEXA_SHORT_PERIOD); 72 | bitstream[i++] = LIRC_SPACE(NEXA_LONG_PERIOD); 73 | } else { /* add 'X' (floating bit) */ 74 | /* 340 us high, 1020 us low, 1020 us high, 350 us low */ 75 | bitstream[i++] = LIRC_PULSE(NEXA_SHORT_PERIOD); 76 | bitstream[i++] = LIRC_SPACE(NEXA_LONG_PERIOD); 77 | bitstream[i++] = LIRC_PULSE(NEXA_LONG_PERIOD); 78 | bitstream[i++] = LIRC_SPACE(NEXA_SHORT_PERIOD); 79 | } 80 | bitmask = bitmask << 1; 81 | } 82 | 83 | /* add stop/sync bit and command termination char '+' */ 84 | bitstream[i++] = LIRC_PULSE(NEXA_SHORT_PERIOD); 85 | bitstream[i++] = LIRC_SPACE(NEXA_SYNC_PERIOD); 86 | 87 | return i; 88 | } 89 | 90 | int nexa_bitstream(const char *house, const char *chan, const char *onoff, int32_t *bitstream, int *repeat) 91 | { 92 | return bs(house, chan, onoff, bitstream, repeat, false); 93 | } 94 | 95 | int waveman_bitstream(const char *house, const char *chan, const char *onoff, int32_t *bitstream, int *repeat) 96 | { 97 | return bs(house, chan, onoff, bitstream, repeat, true); 98 | } 99 | -------------------------------------------------------------------------------- /src/protocol.h: -------------------------------------------------------------------------------- 1 | /* Control tool for NEXA and other RF remote receivers 2 | * 3 | * Copyright (C) 2010, 2012 Tord Andersson 4 | * Copyright (C) 2017 Joachim Nilsson 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, visit the Free Software Foundation 18 | * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the 19 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #ifndef RFCTL_PROTOCOL_H_ 24 | #define RFCTL_PROTOCOL_H_ 25 | 26 | #define DEFAULT_DEVICE "/dev/rfctl" 27 | 28 | #define RF_MAX_TX_BITS 4000 /* Max TX pulse/space elements in one message */ 29 | #define RF_MAX_RX_BITS 4000 /* Max read RX pulse/space elements at one go */ 30 | 31 | typedef enum { 32 | MODE_UNKNOWN, 33 | MODE_READ, 34 | MODE_WRITE 35 | } rf_mode_t; 36 | 37 | typedef enum { 38 | IFC_UNKNOWN, 39 | IFC_RFCTL, 40 | IFC_CUL, 41 | IFC_TELLSTICK 42 | } rf_interface_t; 43 | 44 | typedef enum { 45 | PROT_UNKNOWN, 46 | PROT_RAW, 47 | PROT_NEXA, 48 | PROT_PROOVE, 49 | PROT_NEXA_L, 50 | PROT_SARTANO, 51 | PROT_CONRAD, 52 | PROT_WAVEMAN, 53 | PROT_IKEA, 54 | PROT_ESIC, 55 | PROT_IMPULS 56 | } rf_protocol_t; 57 | 58 | #define LIRC_MODE2_SPACE 0x00000000 59 | #define LIRC_MODE2_PULSE 0x01000000 60 | #define LIRC_MODE2_TIMEOUT 0x03000000 61 | 62 | #define LIRC_VALUE_MASK 0x00FFFFFF 63 | #define LIRC_MODE2_MASK 0xFF000000 64 | 65 | #define LIRC_SPACE(val) (((val) & LIRC_VALUE_MASK) | LIRC_MODE2_SPACE) 66 | #define LIRC_PULSE(val) (((val) & LIRC_VALUE_MASK) | LIRC_MODE2_PULSE) 67 | #define LIRC_TIMEOUT(val) (((val) & LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT) 68 | 69 | #define LIRC_VALUE(val) ((val) & LIRC_VALUE_MASK) 70 | #define LIRC_MODE2(val) ((val) & LIRC_MODE2_MASK) 71 | 72 | #define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE) 73 | #define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE) 74 | #define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT) 75 | 76 | #define NEXA_SHORT_PERIOD 340 /* microseconds */ 77 | #define NEXA_LONG_PERIOD 1020 /* microseconds */ 78 | #define NEXA_SYNC_PERIOD (32 * NEXA_SHORT_PERIOD) /* between frames */ 79 | #define NEXA_REPEAT 4 80 | 81 | #define SARTANO_SHORT_PERIOD 320 /* microseconds */ 82 | #define SARTANO_LONG_PERIOD 960 /* microseconds */ 83 | #define SARTANO_SYNC_PERIOD (32 * SARTANO_SHORT_PERIOD) /* between frames */ 84 | #define SARTANO_REPEAT 5 85 | 86 | int nexa_bitstream (const char *house, const char *chan, const char *onoff, int32_t *bitstream, int *repeat); 87 | int waveman_bitstream (const char *house, const char *chan, const char *onoff, int32_t *bitstream, int *repeat); 88 | int sartano_bitstream ( const char *chan, const char *onoff, int32_t *bitstream, int *repeat); 89 | int conrad_bitstream (const char *house, const char *chan, const char *onoff, int32_t *bitstream, int *repeat); 90 | int impulse_bitstream ( const char *chan, const char *onoff, int32_t *bitstream, int *repeat); 91 | int ikea_bitstream (const char *house, const char *chan, const char *level, const char *dim_style, int32_t *bitstream, int *repeat); 92 | 93 | int bitstream2cul443 (int32_t *bitstream, int len, int repeat, char *cul); 94 | 95 | #endif /* RFCTL_PROTOCOL_H_ */ 96 | -------------------------------------------------------------------------------- /src/impulse.c: -------------------------------------------------------------------------------- 1 | /* Control tool for NEXA and other RF remote receivers 2 | * 3 | * Copyright (C) 2010, 2012 Tord Andersson 4 | * Copyright (C) 2017 Joachim Nilsson 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, visit the Free Software Foundation 18 | * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the 19 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #include "common.h" 24 | #include "protocol.h" 25 | 26 | int impulse_bitstream(const char *chan, const char *onoff, int32_t *bitstream, int *repeat) 27 | { 28 | int i = 0; 29 | int enable; 30 | int bit; 31 | 32 | enable = atoi(onoff); /* ON/OFF 0..1 */ 33 | *repeat = SARTANO_REPEAT; 34 | 35 | PRINT("Channel: %s, on_off: %d\n", chan, enable); 36 | 37 | /* check converted parameters for validity */ 38 | if ((strlen(chan) != 10) || (enable < 0) || (enable > 1)) { 39 | fprintf(stderr, "Invalid channel or on/off code\n"); 40 | return 0; 41 | } 42 | 43 | // The house code: 44 | for (bit = 0; bit < 5; bit++) { 45 | /* "1" bit */ 46 | // 11101110 is on 47 | if (strncmp(chan + bit, "1", 1) == 0) { 48 | bitstream[i++] = LIRC_PULSE(SARTANO_LONG_PERIOD); 49 | bitstream[i++] = LIRC_SPACE(SARTANO_SHORT_PERIOD); 50 | bitstream[i++] = LIRC_PULSE(SARTANO_LONG_PERIOD); 51 | bitstream[i++] = LIRC_SPACE(SARTANO_SHORT_PERIOD); 52 | } 53 | /* "0" bit */ 54 | else { 55 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 56 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 57 | bitstream[i++] = LIRC_PULSE(SARTANO_LONG_PERIOD); 58 | bitstream[i++] = LIRC_SPACE(SARTANO_SHORT_PERIOD); 59 | } 60 | } 61 | 62 | // The group code 63 | for (bit = 5; bit < 10; bit++) { 64 | /* "1" bit */ 65 | // 10001000 is on 66 | if (strncmp(chan + bit, "1", 1) == 0) { 67 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 68 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 69 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 70 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 71 | } 72 | /* "0" bit */ 73 | else { 74 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 75 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 76 | bitstream[i++] = LIRC_PULSE(SARTANO_LONG_PERIOD); 77 | bitstream[i++] = LIRC_SPACE(SARTANO_SHORT_PERIOD); 78 | } 79 | } 80 | 81 | if (enable >= 1) { 82 | /* ON == "10" */ 83 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 84 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 85 | bitstream[i++] = LIRC_PULSE(SARTANO_LONG_PERIOD); 86 | bitstream[i++] = LIRC_SPACE(SARTANO_SHORT_PERIOD); 87 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 88 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 89 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 90 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 91 | } else { 92 | /* OFF == "01" */ 93 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 94 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 95 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 96 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 97 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 98 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 99 | bitstream[i++] = LIRC_PULSE(SARTANO_LONG_PERIOD); 100 | bitstream[i++] = LIRC_SPACE(SARTANO_SHORT_PERIOD); 101 | } 102 | 103 | /* add stop/sync bit and command termination char '+' */ 104 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 105 | bitstream[i++] = LIRC_SPACE(SARTANO_SYNC_PERIOD); 106 | 107 | return i; 108 | } 109 | -------------------------------------------------------------------------------- /src/sartano.c: -------------------------------------------------------------------------------- 1 | /* Control tool for NEXA and other RF remote receivers 2 | * 3 | * Copyright (C) 2010, 2012 Tord Andersson 4 | * Copyright (C) 2017 Joachim Nilsson 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, visit the Free Software Foundation 18 | * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the 19 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #include "common.h" 24 | #include "protocol.h" 25 | 26 | static int manchester(const char *bitstring, int32_t bitstream[]) 27 | { 28 | int i = 0; 29 | const char *bit = bitstring; 30 | 31 | while (*bit) { 32 | if (*bit == '1') { 33 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 34 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 35 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 36 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 37 | } else { 38 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 39 | bitstream[i++] = LIRC_SPACE(SARTANO_LONG_PERIOD); 40 | bitstream[i++] = LIRC_PULSE(SARTANO_LONG_PERIOD); 41 | bitstream[i++] = LIRC_SPACE(SARTANO_SHORT_PERIOD); 42 | } 43 | 44 | bit++; 45 | } 46 | 47 | return i; 48 | } 49 | 50 | int sartano_bitstream(const char *chan, const char *onoff, int32_t *bitstream, int *repeat) 51 | { 52 | int i = 0; 53 | int enable; 54 | 55 | enable = atoi(onoff); /* ON/OFF 0..1 */ 56 | *repeat = SARTANO_REPEAT; 57 | 58 | PRINT("Channel: %s, onoff: %d\n", chan, enable); 59 | 60 | /* Validate converted parameters */ 61 | if ((strlen(chan) != 10) || (enable < 0) || (enable > 1)) { 62 | fprintf(stderr, "Invalid channel or on/off code\n"); 63 | return 0; 64 | } 65 | 66 | /* Convert channel and onoff to bitstream */ 67 | i = manchester(chan, &bitstream[i]); 68 | i += manchester(enable ? "10" : "01", &bitstream[i]); 69 | 70 | /* Add stop/sync bit and command termination char '+' */ 71 | bitstream[i++] = LIRC_PULSE(SARTANO_SHORT_PERIOD); 72 | bitstream[i++] = LIRC_SPACE(SARTANO_SYNC_PERIOD); 73 | 74 | return i; 75 | } 76 | 77 | /* 78 | * Encode the following pattern into a house(I..IV) and channel (1..4): 79 | * 80 | * 1000100000 <--> I - 1 81 | * 1000010000 <--> I - 2 82 | * 1000001000 <--> I - 3 83 | * 1000000100 <--> I - 4 84 | 85 | * 0100100000 <--> II - 1 86 | * 0100010000 <--> II - 2 87 | * 0100001000 <--> II - 3 88 | * 0100000100 <--> II - 4 89 | 90 | * 0010100000 <--> III - 1 91 | * 0010010000 <--> III - 2 92 | * 0010001000 <--> III - 3 93 | * 0010000100 <--> III - 4 94 | 95 | * 0001100000 <--> IV - 1 96 | * 0001010000 <--> IV - 2 97 | * 0001001000 <--> IV - 3 98 | * 0001000100 <--> IV - 4 99 | * 100 | * https://www.raspberrypi.org/forums/viewtopic.php?t=11159 101 | */ 102 | int conrad_bitstream(const char *house, const char *chan, const char *onoff, int32_t *bitstream, int *repeat) 103 | { 104 | int i; 105 | int group; 106 | int channel; 107 | char magic[20]; 108 | 109 | group = atoi(house); 110 | channel = atoi(chan); 111 | 112 | if (group < 1 || group > 4 || channel < 1 || channel > 4) { 113 | fprintf(stderr, "Invalid group(%d) or channel (%d).\nUse group 1..4, channel 1..4\n", group, channel); 114 | return 0; 115 | } 116 | 117 | for (i = 0; i < 4; i++) { 118 | if (i + 1 == group) 119 | magic[i] = '1'; 120 | else 121 | magic[i] = '0'; 122 | } 123 | for (i = 0; i < 4; i++) { 124 | if (i + 1 == channel) 125 | magic[4 + i] = '1'; 126 | else 127 | magic[4 + i] = '0'; 128 | } 129 | magic[8] = '0'; 130 | magic[9] = '0'; 131 | magic[10] = 0; 132 | 133 | return sartano_bitstream((const char *)magic, onoff, bitstream, repeat); 134 | } 135 | -------------------------------------------------------------------------------- /src/ikea.c: -------------------------------------------------------------------------------- 1 | /* Control tool for NEXA and other RF remote receivers 2 | * 3 | * Copyright (C) 2010, 2012 Tord Andersson 4 | * Copyright (C) 2017 Joachim Nilsson 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, visit the Free Software Foundation 18 | * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the 19 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #include "common.h" 24 | #include "protocol.h" 25 | 26 | int ikea_bitstream(const char *house, const char *chan, const char *level, 27 | const char *dim_style, int32_t *bitstream, int *repeat) 28 | { 29 | #if 0 30 | *pStrReturn = '\0'; /* Make sure tx Bitstream is empty */ 31 | 32 | const char STARTCODE[] = "STTTTTT�"; 33 | const char TT[] = "TT"; 34 | const char A[] = "�"; 35 | int system = atoi(house) - 1; /* System 1..16 */ 36 | int channel = atoi(chan); /* Channel 1..10 */ 37 | int lvl = atoi(level); /* off,10,20,..,90,on */ 38 | int dim = atoi(dim_style); 39 | int code = 0; 40 | int checksum1 = 0; 41 | int checksum2 = 0; 42 | int fade; 43 | int i; 44 | int raw = 0; 45 | 46 | /* check converted parameters for validity */ 47 | if ((channel <= 0) || (channel > 10) || (system < 0) || (system > 15) || 48 | (lvl < 0) || (lvl > 10) || (dim < 0) || (dim > 1)) 49 | return 0; 50 | 51 | if (channel == 10) 52 | channel = 0; 53 | raw = (1 << (9 - channel)); 54 | 55 | strcat(pStrReturn, STARTCODE); //Startcode, always like this; 56 | code = (system << 10) | raw; 57 | 58 | for (i = 13; i >= 0; --i) { 59 | if ((code >> i) & 1) { 60 | strcat(pStrReturn, TT); 61 | if (i % 2 == 0) 62 | checksum2++; 63 | else 64 | checksum1++; 65 | } else { 66 | strcat(pStrReturn, A); 67 | } 68 | } 69 | 70 | if (checksum1 % 2 == 0) 71 | strcat(pStrReturn, TT); 72 | else 73 | strcat(pStrReturn, A); //1st checksum 74 | 75 | if (checksum2 % 2 == 0) 76 | strcat(pStrReturn, TT); 77 | else 78 | strcat(pStrReturn, A); //2nd checksum 79 | 80 | if (dim == 1) 81 | fade = 11 << 4; //Smooth 82 | else 83 | fade = 1 << 4; //Instant 84 | 85 | switch (lvl) { 86 | case 0: 87 | code = (10 | fade); //Concat level and fade 88 | break; 89 | 90 | case 1: 91 | code = (1 | fade); //Concat level and fade 92 | break; 93 | 94 | case 2: 95 | code = (2 | fade); //Concat level and fade 96 | break; 97 | 98 | case 3: 99 | code = (3 | fade); //Concat level and fade 100 | break; 101 | 102 | case 4: 103 | code = (4 | fade); //Concat level and fade 104 | break; 105 | 106 | case 5: 107 | code = (5 | fade); //Concat level and fade 108 | break; 109 | 110 | case 6: 111 | code = (6 | fade); //Concat level and fade 112 | break; 113 | 114 | case 7: 115 | code = (7 | fade); //Concat level and fade 116 | break; 117 | 118 | case 8: 119 | code = (8 | fade); //Concat level and fade 120 | break; 121 | 122 | case 9: 123 | code = (9 | fade); //Concat level and fade 124 | break; 125 | 126 | case 10: 127 | default: 128 | code = (0 | fade); //Concat level and fade 129 | break; 130 | } 131 | 132 | checksum1 = 0; 133 | checksum2 = 0; 134 | 135 | for (i = 0; i < 6; ++i) { 136 | if ((code >> i) & 1) { 137 | strcat(pStrReturn, TT); 138 | 139 | if (i % 2 == 0) 140 | checksum1++; 141 | else 142 | checksum2++; 143 | } else { 144 | strcat(pStrReturn, A); 145 | } 146 | } 147 | 148 | if (checksum1 % 2 == 0) 149 | strcat(pStrReturn, TT); 150 | else 151 | strcat(pStrReturn, A); //2nd checksum 152 | 153 | if (checksum2 % 2 == 0) 154 | strcat(pStrReturn, TT); 155 | else 156 | strcat(pStrReturn, A); //2nd checksum 157 | strcat(pStrReturn, "+"); 158 | 159 | return strlen(pStrReturn); 160 | #endif 161 | return 0; 162 | } 163 | 164 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 433.92 MHz RF communication on Raspberry Pi 2 | =========================================== 3 | [![License Badge][]][License] [![Travis Status][]][Travis] 4 | 5 | [rfctl][] is a simple Linux driver and control tool for 433.92 MHz RF 6 | communication on Raspberry Pi. 7 | 8 | The following guide assumes the Raspbian Linux distribution is used on 9 | the Raspberry Pi. However, the kernel driver and the `rfctl` tool 10 | should work fine on any distribution with a relatively modern kernel. 11 | 12 | The following formum topic, although dated, also covers this driver and 13 | provides some helpful tips and discussions. 14 | 15 | - https://www.raspberrypi.org/forums/viewtopic.php?t=11159 16 | 17 | 18 | rfctl driver 19 | ------------ 20 | 21 | The default control interface of the `rfctl` tool utilizes `rfctl.ko`. 22 | It is a LIRC style kernel device driver transmitting and recording pulse 23 | and pause lengths by bit banging on a GPIO pin. See [HARDWARE.md][] for 24 | information on how to connect the GPIO to a common 433 MHz TX module. 25 | 26 | To build you first need to install the kernel headers, in Raspbian the 27 | `raspberrypi-kernel-headers` meta package points to the latest kernel 28 | headers, which will install somewhere in `/lib/modules`: 29 | 30 | ```sh 31 | sudo apt install raspberrypi-kernel-headers 32 | ``` 33 | 34 | Then enter the kernel driver directory to build, load the driver, and 35 | create the device node `rfctl` uses: 36 | 37 | ```sh 38 | cd rfctl/kernel 39 | make 40 | sudo make insmod 41 | ``` 42 | 43 | 44 | rfctl tool 45 | ---------- 46 | 47 | `rfctl` is a small tool that acts as a remote control for switches that 48 | use simple unidirectional communication based on OOK (On Off Keying) 49 | modulation on a 433 MHz carrier. By default `rfctl` uses the Linux 50 | `rfctl.ko` kernel driver. 51 | 52 | To build: 53 | 54 | ```sh 55 | cd rfctl/src 56 | make 57 | sudo make install 58 | ``` 59 | 60 | A simple test on an old style (not selflearning) NEXA/PROVE/ARC set to 61 | group D, channel 1. 62 | 63 | ```sh 64 | rfctl -p NEXA -g D -c 1 -l 1 65 | rfctl -p NEXA -g D -c 1 -l 0 66 | ``` 67 | 68 | Some popular (cheap) noname RF sockets, available from e.g. Conrad (DE), 69 | Kjell & C:o (SE), or Maplin (UK) use the SARTANO/ELRO protocol and need 70 | to be encoded like this: 71 | 72 | ```sh 73 | rfctl -p SARTANO -c 1000100000 -l 1 # I - 1 74 | rfctl -p SARTANO -c 1000010000 -l 1 # I - 2 75 | rfctl -p SARTANO -c 1000001000 -l 1 # I - 3 76 | rfctl -p SARTANO -c 1000000100 -l 1 # I - 4 77 | 78 | rfctl -p SARTANO -c 0100100000 -l 1 # II - 1 79 | rfctl -p SARTANO -c 0100010000 -l 1 # II - 2 80 | rfctl -p SARTANO -c 0100001000 -l 1 # II - 3 81 | rfctl -p SARTANO -c 0100000100 -l 1 # II - 4 82 | 83 | rfctl -p SARTANO -c 0010100000 -l 1 # III - 1 84 | rfctl -p SARTANO -c 0010010000 -l 1 # III - 2 85 | rfctl -p SARTANO -c 0010001000 -l 1 # III - 3 86 | rfctl -p SARTANO -c 0010000100 -l 1 # III - 4 87 | 88 | rfctl -p SARTANO -c 0001100000 -l 1 # IV - 1 89 | rfctl -p SARTANO -c 0001010000 -l 1 # IV - 2 90 | rfctl -p SARTANO -c 0001001000 -l 1 # IV - 3 91 | rfctl -p SARTANO -c 0001000100 -l 1 # IV - 4 92 | ``` 93 | 94 | Issue `rfctl --help` to get more information on supported protocols and 95 | options. 96 | 97 | **Note:** All protocols might not be fully tested due to lack of 98 | receivers and time :) 99 | 100 | 101 | there are four lights 102 | --------------------- 103 | 104 | As an example of how to automate your home, there is a small script 105 | included that can be set up to run from cron. For details, see the 106 | script header comments in [onoff.sh][] it also has optional support 107 | for the Pimoroni [Firefly Light][], this because the author has a 108 | small Raspberry Pi Zero at home. 109 | 110 | 111 | disclaimer 112 | ---------- 113 | 114 | Do not use this software in situations where operation of, or lack of 115 | operation, may result in property damage, personal injury, or death. 116 | Regulatory bodies may have locked down public use of RF communication in 117 | your location at a national level. Do not use the `rfctl` software to 118 | break applicable laws and regulations. 119 | 120 | 121 | origin & references 122 | ------------------- 123 | 124 | This project orignates from the [rf-bitbanger][] project which was 125 | created by Tord Andersson. It is released under the GNU General Public 126 | License (GPL), version 2. See the file [COPYING][] for details. 127 | 128 | Code fragments from `rfcmd` by Tord Andersson, Micke Prag, Gudmund 129 | Berggren, Tapani Rintala, and others. The kernel driver, `rfctl.ko`, 130 | is based on `lirc_serial.c` by Ralph Metzler et al. 131 | 132 | [COPYING]: COPYING 133 | [HARDWARE.md]: HARDWARE.md 134 | [rfctl]: https://github.com/troglobit/rfctl 135 | [onoff.sh]: https://github.com/troglobit/rfctl/onoff.sh 136 | [rf-bitbanger]: https://github.com/tandersson/rf-bitbanger 137 | [Firefly Light]: https://learn.pimoroni.com/tutorial/sandyj/firefly-light 138 | [License]: https://en.wikipedia.org/wiki/GPL_license 139 | [License Badge]: https://img.shields.io/badge/License-GPL%20v2-blue.svg 140 | [Travis]: https://travis-ci.org/troglobit/rfctl 141 | [Travis Status]: https://travis-ci.org/troglobit/rfctl.png?branch=master 142 | -------------------------------------------------------------------------------- /src/rfctl.c: -------------------------------------------------------------------------------- 1 | /* Control tool for NEXA and other RF remote receivers 2 | * 3 | * Copyright (C) 2010, 2012 Tord Andersson 4 | * Copyright (C) 2017 Joachim Nilsson 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, visit the Free Software Foundation 18 | * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the 19 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "common.h" 31 | #include "protocol.h" 32 | 33 | /* Local variables */ 34 | bool verbose = false; /* -v option */ 35 | bool running = true; 36 | 37 | /* Program name, derived from argv[0] */ 38 | static char *prognm = NULL; 39 | 40 | 41 | static int usage(int code) 42 | { 43 | printf("\n" 44 | "Usage: %s [rwVvh] [-d DEV] [-i IFACE] [-p PROTO] [-s NO]\n" 45 | " [-g GROUP] [-c CHAN] [-l LEVEL]\n" 46 | "\n" 47 | " -d, --device=DEV Device to use, defaults to %s\n" 48 | " -i, --interface=IFACE RFCTL*, CUL, or TELLSTICK. Default uses rfctl.ko\n" 49 | " -p, --protocol=PROTO NEXA, NEXA_L, SARTANO, CONRAD, ELRO, WAVEMAN, IKEA, RAW\n" 50 | " -r, --read Raw space/pulse read, only on supported interfaces\n" 51 | " -w, --write Send command (default)\n" 52 | " -g, --group=GROUP The group/house/system number or letter\n" 53 | " -c, --channel=CHAN The channel/unit number\n" 54 | " -s, --serialnumber=NO The serial/unique number used by NEXA L (self-learning)\n" 55 | " -l, --level=LEVEL Dimmer level, 0..100. All values above 0 will switch\n" 56 | " on non-dimmable devices\n" 57 | " -V, --verbose Enable verbose messages during operation\n" 58 | " -v, --version Show program version and exit\n" 59 | " -h, --help Show summary of command line options and exit\n" 60 | "\n" 61 | "NEXA, WAVEMAN protocol arguments:\n" 62 | " group : A..P\n" 63 | " channel : 1..16\n" 64 | " level : 0..1 (OFF/ON)\n" 65 | "\n" 66 | "SARTANO protocol arguments:\n" 67 | " channel : 0000000000..1111111111\n" 68 | " level : 0..1 (OFF/ON)\n" 69 | "\n" 70 | "CONRAD:\n" 71 | " group : 1..4 (house)\n" 72 | " channel : 1..4 (device)\n" 73 | " level : 0..1 (OFF/ON)\n" 74 | "\n" 75 | "IKEA protocol arguments:\n" 76 | " group : 1..16 (system)\n" 77 | " channel : 1..10 (device)\n" 78 | " level : 0..100\n" 79 | " dimstyle: 0..1 (N/A)\n" 80 | "\n" 81 | "Example:\n" 82 | " %s -p NEXA -g D -c 1 -l 1 (NEXA D1 on)\n" 83 | "\n" 84 | "Bug report address: https://github.com/troglobit/rfctl/issues\n" 85 | "\n", prognm, DEFAULT_DEVICE, prognm); 86 | 87 | return code; 88 | } 89 | 90 | static void sigterm_cb(int signo) 91 | { 92 | /* 93 | * This will force the exit handler to run 94 | */ 95 | PRINT("Signal handler for %d signal\n", signo); 96 | running = false; 97 | } 98 | 99 | static char *progname(char *arg0) 100 | { 101 | char *nm; 102 | 103 | nm = strrchr(arg0, '/'); 104 | if (nm) 105 | nm++; 106 | else 107 | nm = arg0; 108 | 109 | return nm; 110 | } 111 | 112 | int main(int argc, char **argv) 113 | { 114 | struct termios tio; 115 | int fd = -1; 116 | rf_interface_t iface = IFC_RFCTL; 117 | char default_dev[255] = DEFAULT_DEVICE; 118 | char *device = default_dev; /* -d option */ 119 | rf_mode_t mode = MODE_WRITE; /* read/write */ 120 | char *proto = NULL; 121 | rf_protocol_t protocol = PROT_NEXA; /* protocol */ 122 | const char *group = NULL; /* house/group/system option */ 123 | const char *channel = NULL; /* -c (channel/unit) option */ 124 | const char *level = NULL; /* level 0 - 100 % or on/off */ 125 | int32_t tx_bitstream[RF_MAX_TX_BITS]; 126 | int32_t rx_bitstream[RF_MAX_RX_BITS]; 127 | int32_t rx_val = 0; 128 | int rx_len = 0; 129 | int tx_len = 0; 130 | int repeat = 0; 131 | int i, c; 132 | char cmd[RF_MAX_TX_BITS * 6]; /* hex/ASCII representation is longer than bitstream */ 133 | int cmd_len = 0; 134 | const struct option opt[] = { 135 | { "device", required_argument, NULL, 'd' }, 136 | { "interface", required_argument, NULL, 'i' }, 137 | { "protocol", required_argument, NULL, 'p' }, 138 | { "read", no_argument, NULL, 'r' }, 139 | { "write", no_argument, NULL, 'w' }, 140 | { "group", required_argument, NULL, 'g' }, 141 | { "channel", required_argument, NULL, 'c' }, 142 | { "serialnumber", required_argument, NULL, 's' }, 143 | { "level", required_argument, NULL, 'l' }, 144 | { "version", no_argument, NULL, 'v' }, 145 | { "verbose", no_argument, NULL, 'V' }, 146 | { "help", no_argument, NULL, 'h' }, 147 | { NULL, no_argument, NULL, 0 } 148 | }; 149 | 150 | prognm = progname(argv[0]); 151 | while ((c = getopt_long(argc, argv, "d:i:p:rwg:c:l:vVh?", opt, &i)) != EOF) { 152 | switch (c) { 153 | case 'd': 154 | if (optarg) { 155 | device = optarg; 156 | } else { 157 | fprintf(stderr, "Error. Missing device path.\n"); 158 | return usage(1); 159 | } 160 | break; 161 | 162 | case 'i': 163 | if (optarg) { 164 | if (strcmp("RFCTL", optarg) == 0) { 165 | iface = IFC_RFCTL; 166 | } else if (strcmp("CUL", optarg) == 0) { 167 | iface = IFC_CUL; 168 | } else if (strcmp("TELLSTICK", optarg) == 0) { 169 | iface = IFC_TELLSTICK; 170 | } else { 171 | iface = IFC_UNKNOWN; 172 | fprintf(stderr, "Error. Unknown interface type: %s\n", optarg); 173 | return usage(1); 174 | } 175 | } else { 176 | fprintf(stderr, "Error. Missing interface type.\n"); 177 | return usage(1); 178 | } 179 | break; 180 | 181 | case 'r': 182 | mode = MODE_READ; 183 | break; 184 | 185 | case 'w': 186 | mode = MODE_WRITE; 187 | break; 188 | 189 | case 'p': 190 | if (optarg) { 191 | proto = optarg; 192 | if (strcmp("NEXA", proto) == 0) { 193 | protocol = PROT_NEXA; 194 | } else if (strcmp("PROOVE", proto) == 0) { 195 | protocol = PROT_NEXA; 196 | } else if (strcmp("WAVEMAN", proto) == 0) { 197 | protocol = PROT_WAVEMAN; 198 | } else if (strcmp("SARTANO", proto) == 0) { 199 | protocol = PROT_SARTANO; 200 | } else if (strcmp("ELRO", proto) == 0) { 201 | protocol = PROT_SARTANO; 202 | } else if (strcmp("IMPULS", proto) == 0) { 203 | protocol = PROT_IMPULS; 204 | } else if (strcmp("NEXA_L", proto) == 0) { 205 | protocol = PROT_NEXA_L; 206 | } else if (strcmp("CONRAD", proto) == 0) { 207 | protocol = PROT_CONRAD; 208 | } else if (strcmp("RAW", proto) == 0) { 209 | protocol = PROT_RAW; 210 | } else { 211 | fprintf(stderr, "Error. Unknown protocol: %s\n", proto); 212 | return usage(1); 213 | } 214 | } else { 215 | fprintf(stderr, "Error. Missing protocol\n"); 216 | return usage(1); 217 | } 218 | break; 219 | 220 | case 'g': 221 | if (optarg) { 222 | group = optarg; 223 | } else { 224 | fprintf(stderr, "Error. Missing group/house/system ID\n"); 225 | return usage(1); 226 | } 227 | break; 228 | 229 | case 'c': 230 | if (optarg) { 231 | channel = optarg; 232 | } else { 233 | fprintf(stderr, "Error. Missing channel number\n"); 234 | return usage(1); 235 | } 236 | break; 237 | 238 | case 'l': 239 | if (optarg) { 240 | level = optarg; 241 | } else { 242 | fprintf(stderr, "Error. Missing level\n"); 243 | return usage(1); 244 | } 245 | break; 246 | 247 | case 'v': 248 | puts(VERSION); 249 | return 0; 250 | 251 | case 'V': 252 | verbose = true; 253 | break; 254 | 255 | case 0: /* Long option without a short arg */ 256 | if (opt[i].flag != 0) 257 | break; 258 | 259 | printf("option %s", opt[i].name); 260 | if (optarg) 261 | printf(" with arg %s", optarg); 262 | printf("\n"); 263 | break; 264 | 265 | case 'h': /* Fall through by design */ 266 | case '?': 267 | return usage(0); 268 | 269 | default: 270 | return usage(1); 271 | } 272 | } 273 | 274 | /* Build generic transmit bitstream for the selected protocol */ 275 | if (mode == MODE_WRITE) { 276 | if ((protocol != PROT_SARTANO && !group) || !channel || !level) 277 | return usage(1); 278 | 279 | switch (protocol) { 280 | case PROT_NEXA: 281 | PRINT("NEXA protocol selected\n"); 282 | tx_len = nexa_bitstream(group, channel, level, tx_bitstream, &repeat); 283 | if (tx_len == 0) 284 | return usage(1); 285 | break; 286 | 287 | case PROT_WAVEMAN: 288 | PRINT("WAVEMAN protocol selected\n"); 289 | tx_len = waveman_bitstream(group, channel, level, tx_bitstream, &repeat); 290 | if (tx_len == 0) 291 | return usage(1); 292 | break; 293 | 294 | case PROT_SARTANO: 295 | PRINT("SARTANO protocol selected\n"); 296 | tx_len = sartano_bitstream(channel, level, tx_bitstream, &repeat); 297 | if (tx_len == 0) 298 | return usage(1); 299 | break; 300 | 301 | case PROT_CONRAD: 302 | PRINT("CONRAD protocol selected\n"); 303 | tx_len = conrad_bitstream(group, channel, level, tx_bitstream, &repeat); 304 | if (tx_len == 0) 305 | return usage(1); 306 | break; 307 | 308 | case PROT_IMPULS: 309 | PRINT("IMPULS protocol selected\n"); 310 | tx_len = impulse_bitstream(channel, level, tx_bitstream, &repeat); 311 | if (tx_len == 0) 312 | return usage(1); 313 | break; 314 | 315 | case PROT_IKEA: 316 | PRINT("IKEA protocol selected\n"); 317 | tx_len = ikea_bitstream(group, channel, level, "1", tx_bitstream, &repeat); 318 | if (tx_len == 0) 319 | return usage(1); 320 | break; 321 | 322 | default: 323 | fprintf(stderr, "Protocol: %s is currently not supported\n", proto); 324 | return usage(1); 325 | } 326 | } 327 | 328 | /* Transmit/read handling for each interface type */ 329 | switch (iface) { 330 | case IFC_RFCTL: 331 | PRINT("Selected /dev/rfctl interface\n"); 332 | 333 | if (0 > (fd = open(device, O_RDWR))) { 334 | fprintf(stderr, "%s - Error opening %s\n", prognm, device); 335 | return 1; 336 | } 337 | 338 | if (mode == MODE_WRITE) { 339 | PRINT("Writing %d pulse_space_items, (%d bytes) to %s\n", tx_len * repeat, 340 | tx_len * 4 * repeat, device); 341 | for (i = 0; i < repeat; i++) { 342 | if (write(fd, tx_bitstream, tx_len * 4) < 0) { 343 | perror("Error writing to /dev/rfctl"); 344 | break; 345 | } 346 | } 347 | sleep(1); 348 | } else if (mode == MODE_READ) { 349 | running = true; 350 | PRINT("Reading pulse_space_items\n"); 351 | 352 | /* 353 | * Set up signal handlers to act on CTRL-C events 354 | */ 355 | if (signal(SIGINT, sigterm_cb) == SIG_ERR) { 356 | perror("Can't register signal handler for CTRL-C et al: "); 357 | return -1; 358 | } 359 | 360 | while (running == true) { /* repeat until CTRL-C */ 361 | rx_len = read(fd, rx_bitstream, 4); 362 | if (rx_len == 4) { 363 | rx_val = (uint32_t)*&rx_bitstream[0]; 364 | if (LIRC_IS_TIMEOUT(rx_val)) 365 | printf("\nRX Timeout"); 366 | else if (LIRC_IS_PULSE(rx_val)) 367 | printf("\n1 - %05d us", LIRC_VALUE(rx_val)); 368 | else if (LIRC_IS_SPACE(rx_val)) 369 | printf("\n0 - %05d us", LIRC_VALUE(rx_val)); 370 | } else { 371 | if (rx_len == 0) { 372 | usleep(100 * 1000); /* 100 ms */ 373 | printf("."); 374 | fflush(stdout); 375 | } else { 376 | printf("Read %d bytes\n", rx_len); 377 | fflush(stdout); 378 | } 379 | } 380 | } 381 | } 382 | close(fd); 383 | break; 384 | 385 | case IFC_TELLSTICK: 386 | #if 0 387 | PRINT("Selected Tellstick interface\n"); 388 | if (0 > (fd = open(*(argv + 1), O_RDWR))) { 389 | fprintf(stderr, "%s - Error opening %s\n", prognm, *(argv + 1)); 390 | return 1; 391 | } 392 | 393 | /* adjust serial port parameters */ 394 | bzero(&tio, sizeof(tio)); /* clear struct for new port settings */ 395 | tio.c_cflag = B4800 | CS8 | CLOCAL | CREAD; /* CREAD not used yet */ 396 | tio.c_iflag = IGNPAR; 397 | tio.c_oflag = 0; 398 | tio.c_ispeed = 4800; 399 | tio.c_ospeed = 4800; 400 | tcflush(fd, TCIFLUSH); 401 | tcsetattr(fd, TCSANOW, &tio); 402 | if (write(fd, txStr, strlen(txStr)) < 0) 403 | perror("Error writing to Tellstick device"); 404 | 405 | sleep(1); /* one second sleep to avoid device 'choking' */ 406 | close(fd); 407 | #else 408 | fprintf(stderr, "Tellstick interface currently not available.\n"); 409 | #endif 410 | break; 411 | 412 | case IFC_CUL: 413 | PRINT("Selected CUL433 interface\n"); 414 | 415 | if (0 > (fd = open(device, O_RDWR))) { 416 | fprintf(stderr, "%s - Error opening %s\n", prognm, device); 417 | return 1; 418 | } 419 | 420 | /* adjust serial port parameters */ 421 | bzero(&tio, sizeof(tio)); /* clear struct for new port settings */ 422 | tio.c_cflag = B115200 | CS8 | CLOCAL | CREAD; /* CREAD not used yet */ 423 | tio.c_iflag = IGNPAR; 424 | tio.c_oflag = 0; 425 | tio.c_ispeed = 115200; 426 | tio.c_ospeed = 115200; 427 | tcflush(fd, TCIFLUSH); 428 | tcsetattr(fd, TCSANOW, &tio); 429 | 430 | printf("Mode : %d\n", mode); 431 | 432 | if (mode == MODE_WRITE) { 433 | /* CUL433 nethome format */ 434 | cmd_len = bitstream2cul443(tx_bitstream, tx_len, repeat, cmd); 435 | 436 | printf("CUL cmd: %s\n", cmd); 437 | 438 | if (write(fd, cmd, cmd_len) < 0) 439 | perror("Error writing to CUL device"); 440 | sleep(1); 441 | } else if (mode == MODE_READ) { 442 | running = true; 443 | PRINT("Reading pulse_space_items\n"); 444 | 445 | /* 446 | * Set up signal handlers to act on CTRL-C events 447 | */ 448 | if (signal(SIGINT, sigterm_cb) == SIG_ERR) { 449 | perror("Can't register signal handler for CTRL-C et al: "); 450 | return -1; 451 | } 452 | 453 | /* start rx */ 454 | if (write(fd, "\r\nX01\r\n", 7) < 0) { 455 | perror("Error issuing RX cmd to CUL device"); 456 | running = false; 457 | } 458 | 459 | while (running) { /* repeat until CTRL-C */ 460 | rx_len = read(fd, rx_bitstream, 5); 461 | if (rx_len == 5) { 462 | rx_val = (uint32_t)*&rx_bitstream[0]; 463 | printf("\n%08X: ", rx_val); 464 | if (rx_val & 0x8000) 465 | printf("1 - %05d us", rx_val & 0x7FFF); 466 | else 467 | printf("0 - %05d us", rx_val & 0x7FFF); 468 | 469 | if ((rx_val & 0x7FFF) == 0x7FFF) 470 | printf(" - Timeout"); 471 | } else { 472 | if (rx_len == 0) { 473 | usleep(100 * 1000); /* 100 ms */ 474 | printf("."); 475 | fflush(stdout); 476 | } else { 477 | printf("Read %d bytes\n", rx_len); 478 | fflush(stdout); 479 | } 480 | } 481 | } 482 | } 483 | close(fd); 484 | break; 485 | 486 | 487 | default: 488 | fprintf(stderr, "%s - Illegal interface type (%d)\n", prognm, iface); 489 | break; 490 | } 491 | 492 | return 0; 493 | } 494 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /kernel/COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /kernel/rfctl.c: -------------------------------------------------------------------------------- 1 | /* Transmit and record pulse and pause lengths using GPIO 2 | * 3 | * Based on rfbb.c by Tord Andersson, which in turn is based on 4 | * lirc_serial.c by Ralph Metzler et al. 5 | * 6 | * Copyright (C) 2010, 2012 Tord Andersson 7 | * Copyright (C) 2017 Joachim Nilsson 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License 11 | * as published by the Free Software Foundation; either version 2 12 | * of the License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, visit the Free Software Foundation 21 | * website at http://www.gnu.org/licenses/gpl-2.0.html or write to the 22 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 23 | * Boston, MA 02110-1301, USA. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #define DRIVER_VERSION "1.0" 38 | #define DRIVER_NAME "rfctl" 39 | 40 | #define HW_MODE_POWER_DOWN 0 /* Transceiver in power down mode */ 41 | #define HW_MODE_RX 1 42 | #define HW_MODE_TX 2 43 | 44 | /* Borrowed LIRC definitions */ 45 | #define LIRC_MODE2_SPACE 0x00000000 46 | #define LIRC_MODE2_PULSE 0x01000000 47 | #define LIRC_MODE2_TIMEOUT 0x03000000 48 | 49 | #define LIRC_VALUE_MASK 0x00FFFFFF 50 | #define LIRC_MODE2_MASK 0xFF000000 51 | 52 | /* 53 | * We export one device, /dev/rfctl 54 | */ 55 | static struct cdev rfctl_dev; 56 | 57 | #define NO_GPIO_PIN -1 58 | #define NO_RX_IRQ -1 59 | 60 | #define DEFAULT_GPIO_IN_PIN NO_GPIO_PIN // 27 61 | #define DEFAULT_GPIO_OUT_PIN 17 62 | 63 | static int dev_major = 0; /* use dynamic major number assignment */ 64 | 65 | static int share_irq = 0; 66 | static int interrupt_enabled = 0; 67 | static bool debug = false; 68 | static int device_open = 0; 69 | static int hw_mode = HW_MODE_POWER_DOWN; 70 | 71 | static DEFINE_MUTEX(read_lock); 72 | 73 | #define xstringify(s) stringify(s) 74 | #define stringify(s) #s 75 | 76 | #define errx(fmt, args...) \ 77 | printk(KERN_ERR DRIVER_NAME ": " fmt, ##args) 78 | #define warnx(fmt, args...) \ 79 | printk(KERN_WARNING DRIVER_NAME ": " fmt, ##args) 80 | #define info(fmt, args...) \ 81 | printk(KERN_INFO DRIVER_NAME ": " fmt, ##args) 82 | #define dbg(fmt, args...) \ 83 | if (debug) \ 84 | printk(KERN_DEBUG DRIVER_NAME ": %s() " fmt, __func__, ##args) 85 | 86 | /* forward declarations */ 87 | static void set_tx_mode(void); /* set up transceiver for transmission */ 88 | static void set_rx_mode(void); /* set up transceiver for reception */ 89 | static void on(void); /* TX signal on */ 90 | static void off(void); /* TX signal off */ 91 | static void rfctl_exit_module(void); 92 | 93 | static int gpio_out_pin = DEFAULT_GPIO_OUT_PIN; 94 | static int gpio_in_pin = DEFAULT_GPIO_IN_PIN; 95 | static int tx_ctrl_pin = NO_GPIO_PIN; /* not used */ 96 | static int rf_enable_pin = NO_GPIO_PIN; /* not used */ 97 | 98 | #define RS_ISR_PASS_LIMIT 256 99 | 100 | /* 101 | * A long pulse code from a remote might take up to 300 bytes. The 102 | * daemon should read the bytes as soon as they are generated, so take 103 | * the number of keys you think you can push before the daemon runs 104 | * and multiply by 300. The driver will warn you if you overrun this 105 | * buffer. If you have a slow computer or non-busmastering IDE disks, 106 | * maybe you will need to increase this. 107 | */ 108 | 109 | #define RBUF_LEN 4096 110 | #define WBUF_LEN 4096 111 | 112 | static int sense = 0; /* -1 = auto, 0 = active high, 1 = active low */ 113 | 114 | static int irq = NO_RX_IRQ; 115 | 116 | static struct timeval lasttv = { 0, 0 }; 117 | 118 | /* static struct lirc_buffer rbuf; */ 119 | 120 | /* Use FIFO to store received pulses */ 121 | static DEFINE_KFIFO(rxfifo, int32_t, RBUF_LEN); 122 | 123 | static int32_t wbuf[WBUF_LEN]; 124 | 125 | /* AUREL RTX-MID transceiver TX setup sequence 126 | will use rf_enable as well as tx_ctrl pins. 127 | Not used for simple TX modules */ 128 | static void set_tx_mode(void) 129 | { 130 | off(); 131 | switch (hw_mode) { 132 | case HW_MODE_POWER_DOWN: 133 | if (rf_enable_pin != NO_GPIO_PIN) { 134 | gpio_set_value(rf_enable_pin, 1); 135 | udelay(20); 136 | } 137 | if (tx_ctrl_pin != NO_GPIO_PIN) { 138 | gpio_set_value(tx_ctrl_pin, 1); 139 | udelay(400); /* let it settle */ 140 | } 141 | break; 142 | 143 | case HW_MODE_TX: 144 | /* do nothing */ 145 | break; 146 | 147 | case HW_MODE_RX: 148 | if (rf_enable_pin != NO_GPIO_PIN) { 149 | gpio_set_value(rf_enable_pin, 1); 150 | } 151 | if (tx_ctrl_pin != NO_GPIO_PIN) { 152 | gpio_set_value(tx_ctrl_pin, 1); 153 | udelay(400); /* let it settle */ 154 | } 155 | break; 156 | 157 | default: 158 | errx("%s: Illegal HW mode %d\n", __func__, hw_mode); 159 | break; 160 | } 161 | 162 | hw_mode = HW_MODE_TX; 163 | } 164 | 165 | /* AUREL RTX-MID transceiver RX setup sequence */ 166 | static void set_rx_mode(void) 167 | { 168 | off(); 169 | switch (hw_mode) { 170 | case HW_MODE_POWER_DOWN: 171 | /* Note this sequence is only needed for AUREL RTX-MID */ 172 | if (rf_enable_pin != NO_GPIO_PIN && tx_ctrl_pin != NO_GPIO_PIN) { 173 | gpio_set_value(rf_enable_pin, 1); 174 | gpio_set_value(tx_ctrl_pin, 0); 175 | udelay(20); 176 | gpio_set_value(tx_ctrl_pin, 1); 177 | udelay(200); 178 | gpio_set_value(tx_ctrl_pin, 0); 179 | udelay(40); 180 | gpio_set_value(rf_enable_pin, 0); 181 | udelay(20); 182 | gpio_set_value(rf_enable_pin, 1); 183 | udelay(200); 184 | } 185 | break; 186 | 187 | case HW_MODE_RX: 188 | /* do nothing */ 189 | break; 190 | 191 | case HW_MODE_TX: 192 | if (tx_ctrl_pin != NO_GPIO_PIN) { 193 | gpio_set_value(tx_ctrl_pin, 0); 194 | udelay(40); 195 | } 196 | if (rf_enable_pin != NO_GPIO_PIN) { 197 | gpio_set_value(rf_enable_pin, 0); 198 | udelay(20); 199 | gpio_set_value(rf_enable_pin, 1); 200 | udelay(200); 201 | } 202 | break; 203 | 204 | default: 205 | errx("set_rx_mode. Illegal HW mode %d\n", hw_mode); 206 | break; 207 | } 208 | 209 | hw_mode = HW_MODE_RX; 210 | } 211 | 212 | static void on(void) 213 | { 214 | gpio_set_value(gpio_out_pin, 1); 215 | } 216 | 217 | static void off(void) 218 | { 219 | gpio_set_value(gpio_out_pin, 0); 220 | } 221 | 222 | #ifndef MAX_UDELAY_MS 223 | #define MAX_UDELAY_US 5000 224 | #else 225 | #define MAX_UDELAY_US (MAX_UDELAY_MS*1000) 226 | #endif 227 | 228 | static void safe_udelay(unsigned long usecs) 229 | { 230 | while (usecs > MAX_UDELAY_US) { 231 | udelay(MAX_UDELAY_US); 232 | usecs -= MAX_UDELAY_US; 233 | } 234 | udelay(usecs); 235 | } 236 | 237 | static void send_pulse_gpio(unsigned long length) 238 | { 239 | on(); 240 | /* dbg("%ld us\n", length); */ 241 | safe_udelay(length); 242 | } 243 | 244 | static void send_space_gpio(unsigned long length) 245 | { 246 | off(); 247 | /* dbg("%ld us\n", length); */ 248 | safe_udelay(length); 249 | } 250 | 251 | static irqreturn_t irq_handler(int i, void *blah) 252 | { 253 | struct timeval tv; 254 | int status; 255 | long deltv; 256 | int32_t data = 0; 257 | static int old_status = -1; 258 | static int counter = 0; /* to find burst problems */ 259 | /* static int intCount = 0; */ 260 | 261 | status = gpio_get_value(gpio_in_pin); 262 | if (status == old_status) { 263 | /* could have been a spike */ 264 | counter++; 265 | if (counter > RS_ISR_PASS_LIMIT) { 266 | warnx("AIEEEE: " "We're caught!\n"); 267 | counter = 0; /* to avoid flooding warnings */ 268 | } 269 | 270 | goto leave; 271 | } 272 | 273 | counter = 0; 274 | 275 | /* get current time */ 276 | do_gettimeofday(&tv); 277 | 278 | /* New mode, written by Trent Piepho 279 | . */ 280 | 281 | /* 282 | * The old format was not very portable. We now use an int to 283 | * pass pulses and spaces to user space. 284 | * 285 | * If PULSE_BIT is set a pulse has been received, otherwise a 286 | * space has been received. The driver needs to know if your 287 | * receiver is active high or active low, or the space/pulse 288 | * sense could be inverted. The bits denoted by PULSE_MASK are 289 | * the length in microseconds. Lengths greater than or equal to 290 | * 16 seconds are clamped to PULSE_MASK. All other bits are 291 | * unused. This is a much simpler interface for user programs, 292 | * as well as eliminating "out of phase" errors with space/pulse 293 | * autodetection. 294 | */ 295 | 296 | /* calc time since last interrupt in microseconds */ 297 | deltv = tv.tv_sec - lasttv.tv_sec; 298 | if (tv.tv_sec < lasttv.tv_sec || (tv.tv_sec == lasttv.tv_sec && tv.tv_usec < lasttv.tv_usec)) { 299 | warnx("AIEEEE: your clock just jumped " "backwards\n"); 300 | warnx("%d %lx %lx %lx %lx\n", 301 | sense, tv.tv_sec, lasttv.tv_sec, tv.tv_usec, lasttv.tv_usec); 302 | data = status ? (data | LIRC_VALUE_MASK) : (data | LIRC_MODE2_PULSE | LIRC_VALUE_MASK); /* handle as too long time */ 303 | } else if (deltv > 15) { 304 | data = status ? (data | LIRC_VALUE_MASK) : (data | LIRC_MODE2_PULSE | LIRC_VALUE_MASK); /* really long time */ 305 | } else { 306 | data = (int32_t) (deltv * 1000000 + tv.tv_usec - lasttv.tv_usec); 307 | } 308 | 309 | /* frbwrite(status ? data : (data|PULSE_BIT)); */ 310 | lasttv = tv; 311 | old_status = status; 312 | data = status ? data : (data | LIRC_MODE2_PULSE); 313 | /* dbg("Nr: %d. Pin: %d time: %ld\n", ++intCount, status, (long)(data & PULSE_MASK)); */ 314 | kfifo_put(&rxfifo, data); 315 | /* wake_up_interruptible(&rbuf.wait_poll); */ 316 | 317 | leave: 318 | return IRQ_RETVAL(IRQ_HANDLED); 319 | } 320 | 321 | #define gpio_register(pin, io, nm) \ 322 | if (pin != NO_GPIO_PIN) { \ 323 | dbg("Registering %s, GPIO %d\n", nm, pin); \ 324 | err = gpio_request_one(pin, io, nm); \ 325 | if (err) { \ 326 | errx("Error %d requesting %s\n", err, nm); \ 327 | err = -EIO; \ 328 | goto leave; \ 329 | } \ 330 | } 331 | 332 | #define gpio_expose(pin, dir, nm) \ 333 | if (pin != NO_GPIO_PIN && debug) { \ 334 | dbg("Exporting %s, GPIO %d to sysfs\n", nm, pin); \ 335 | err = gpio_export(pin, dir); \ 336 | if (err) \ 337 | errx("Error %d exporting %s\n", err, nm); \ 338 | } 339 | 340 | #define gpio_direction(pin, io, nm) \ 341 | if (pin != NO_GPIO_PIN) { \ 342 | dbg("Setting %s, GPIO %d, dir %d\n", nm, pin, io); \ 343 | if (io) \ 344 | err = gpio_direction_input(pin); \ 345 | else \ 346 | err = gpio_direction_output(pin, 0); \ 347 | if (err) \ 348 | errx("Error %d setting %s dir\n", err, nm); \ 349 | } 350 | 351 | static int gpio_init(void) 352 | { 353 | unsigned long flags; 354 | int err = 0; 355 | 356 | /* First of all, disable all interrupts */ 357 | local_irq_save(flags); 358 | 359 | /* Setup all pins */ 360 | gpio_register(gpio_out_pin, GPIOF_OUT_INIT_LOW, "TX"); 361 | gpio_register(gpio_in_pin, GPIOF_IN, "RX"); 362 | gpio_register(tx_ctrl_pin, GPIOF_OUT_INIT_LOW, "TX_CTRL"); 363 | gpio_register(rf_enable_pin, GPIOF_OUT_INIT_LOW, "RF_ENABLE"); 364 | 365 | /* Set I/O direction */ 366 | gpio_direction(gpio_out_pin, 0, "TX"); 367 | gpio_direction(gpio_in_pin, 1, "RX"); 368 | gpio_direction(tx_ctrl_pin, 0, "TX_CTRL"); 369 | gpio_direction(rf_enable_pin, 0, "RF_ENABLE"); 370 | 371 | /* Get interrupt for RX */ 372 | if (gpio_in_pin != NO_GPIO_PIN) { 373 | irq = gpio_to_irq(gpio_in_pin); 374 | dbg("Interrupt %d for RX pin\n", irq); 375 | } 376 | 377 | /* Export pins and make them able to change from sysfs for troubleshooting */ 378 | gpio_expose(gpio_out_pin, 1, "TX"); 379 | gpio_expose(gpio_in_pin, 0, "RX"); 380 | gpio_expose(tx_ctrl_pin, 1, "TX_CTRL"); 381 | gpio_expose(rf_enable_pin, 1, "RF_ENABLE"); 382 | 383 | /* Start in TX mode, avoid interrupts */ 384 | set_tx_mode(); 385 | 386 | leave: 387 | local_irq_restore(flags); 388 | return 0; 389 | } 390 | 391 | static ssize_t rfctl_read(struct file *filp, char *buf, size_t length, loff_t *offset) 392 | { 393 | int ret = 0; 394 | unsigned int copied = 0; 395 | 396 | set_rx_mode(); 397 | if (!interrupt_enabled) { 398 | //enable_irq(irq); 399 | interrupt_enabled = 1; 400 | } 401 | 402 | /* might need mutex */ 403 | ret = kfifo_to_user(&rxfifo, buf, length, &copied); 404 | 405 | dbg("request %zd bytes, result %d, copied bytes %u\n", length, ret, copied); 406 | 407 | return (ssize_t)(ret ? ret : copied); 408 | } 409 | 410 | static ssize_t rfctl_write(struct file *file, const char *buf, size_t n, loff_t *ppos) 411 | { 412 | int i, err, count; 413 | unsigned long flags; 414 | 415 | if (interrupt_enabled) { 416 | //disable_irq(irq); 417 | interrupt_enabled = 0; 418 | } 419 | set_tx_mode(); 420 | 421 | /* Workaround, TX pin gets reset to input in long-time test */ 422 | gpio_direction(gpio_out_pin, 0, "TX"); 423 | 424 | dbg("%zd bytes\n", n); 425 | 426 | if (n % sizeof(int32_t)) 427 | return -EINVAL; 428 | 429 | count = n / sizeof(int32_t); 430 | if (count > WBUF_LEN) { 431 | errx("Too many elements (%d) in TX buffer, max %d\n", count, WBUF_LEN); 432 | return -EINVAL; 433 | } 434 | 435 | err = copy_from_user(wbuf, buf, n); 436 | if (err) { 437 | errx("Failed copy_from_user() TX buffer, err %d\n", err); 438 | return -EFAULT; 439 | } 440 | 441 | local_irq_save(flags); 442 | for (i = 0; i < count; i++) { 443 | if (wbuf[i] & LIRC_MODE2_PULSE) 444 | send_pulse_gpio(wbuf[i] & LIRC_VALUE_MASK); 445 | else 446 | send_space_gpio(wbuf[i] & LIRC_VALUE_MASK); 447 | } 448 | off(); 449 | local_irq_restore(flags); 450 | 451 | return n; 452 | } 453 | 454 | static long rfctl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) 455 | { 456 | switch (cmd) { 457 | default: 458 | return -ENOIOCTLCMD; 459 | } 460 | 461 | return 0; 462 | } 463 | 464 | static int rfctl_open(struct inode *ino, struct file *filep) 465 | { 466 | int result; 467 | unsigned long flags; 468 | 469 | if (device_open) { 470 | errx("Already opened\n"); 471 | return -EBUSY; 472 | } 473 | 474 | /* initialize timestamp */ 475 | do_gettimeofday(&lasttv); 476 | 477 | if (irq != NO_RX_IRQ) { 478 | local_irq_save(flags); 479 | result = request_irq(irq, irq_handler, 480 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 481 | DRIVER_NAME, NULL); 482 | 483 | switch (result) { 484 | case -EBUSY: 485 | errx("IRQ %d busy\n", irq); 486 | break; 487 | 488 | case -EINVAL: 489 | errx("Bad irq number or handler\n"); 490 | break; 491 | 492 | default: 493 | dbg("Interrupt %d obtained\n", irq); 494 | result = 0; 495 | break; 496 | }; 497 | 498 | local_irq_restore(flags); 499 | if (result) 500 | return result; 501 | } 502 | 503 | if (interrupt_enabled) { 504 | //disable_irq(irq); 505 | interrupt_enabled = 0; 506 | } 507 | 508 | try_module_get(THIS_MODULE); 509 | device_open++; 510 | 511 | return 0; 512 | } 513 | 514 | static int rfctl_close(struct inode *node, struct file *file) 515 | { 516 | off(); 517 | 518 | if (interrupt_enabled) { 519 | //disable_irq(irq); 520 | interrupt_enabled = 0; 521 | } 522 | 523 | /* remove the RX interrupt */ 524 | if (irq != NO_RX_IRQ) { 525 | free_irq(irq, NULL); 526 | dbg("Freed RX IRQ %d\n", irq); 527 | } 528 | 529 | /* lirc_buffer_free(&rbuf); */ 530 | 531 | device_open--; /* We're now ready for our next caller */ 532 | module_put(THIS_MODULE); 533 | 534 | return 0; 535 | } 536 | 537 | static struct file_operations rfctl_fops = { 538 | .owner = THIS_MODULE, 539 | .open = rfctl_open, 540 | .release = rfctl_close, 541 | .write = rfctl_write, 542 | .read = rfctl_read, 543 | .unlocked_ioctl = rfctl_ioctl, 544 | }; 545 | 546 | /* 547 | * Set up the cdev structure for a device. 548 | */ 549 | static int rfctl_setup_cdev(struct cdev *dev, int minor, struct file_operations *fops) 550 | { 551 | int err, devno = MKDEV(dev_major, minor); 552 | struct class *class; 553 | struct device *device; 554 | 555 | class = class_create(THIS_MODULE, DRIVER_NAME); 556 | if (IS_ERR(class)) { 557 | err = PTR_ERR(class); 558 | pr_warn("Unable to create %s class; errno %d\n", DRIVER_NAME, err); 559 | return err; 560 | } 561 | 562 | cdev_init(dev, fops); 563 | dev->owner = THIS_MODULE; 564 | dev->ops = fops; 565 | err = cdev_add(dev, devno, 1); 566 | if (err) { 567 | warnx("Error %d adding /dev/rfctl %d", err, minor); 568 | return err; 569 | } 570 | 571 | device = device_create(class, NULL, /* no parent device */ 572 | devno, NULL, /* no additional data */ 573 | DRIVER_NAME); 574 | if (IS_ERR(device)) { 575 | err = PTR_ERR(device); 576 | pr_warn("Failed creating /dev/%s, errno %d", DRIVER_NAME, err); 577 | cdev_del(dev); 578 | return err; 579 | } 580 | 581 | return 0; 582 | } 583 | 584 | static int rfctl_init(void) 585 | { 586 | int result; 587 | dev_t dev = 0; 588 | 589 | /* 590 | * Dynamic major if not set otherwise. 591 | */ 592 | if (dev_major) { 593 | dev = MKDEV(dev_major, 0); 594 | result = register_chrdev_region(dev, 1, DRIVER_NAME); 595 | } else { 596 | result = alloc_chrdev_region(&dev, 0, 1, DRIVER_NAME); 597 | dev_major = MAJOR(dev); 598 | } 599 | 600 | if (result < 0) { 601 | warnx("Failed allocating character device, major %d\n", dev_major); 602 | return result; 603 | } 604 | 605 | return rfctl_setup_cdev(&rfctl_dev, 0, &rfctl_fops); 606 | } 607 | 608 | static int rfctl_init_module(void) 609 | { 610 | int result; 611 | 612 | result = rfctl_init(); 613 | if (result) 614 | goto leave; 615 | 616 | result = gpio_init(); 617 | if (result < 0) 618 | goto leave; 619 | 620 | info("%s %s registered\n", DRIVER_NAME, DRIVER_VERSION); 621 | dbg("dev major = %d\n", dev_major); 622 | dbg("IRQ = %d\n", irq); 623 | dbg("share_irq = %d\n", share_irq); 624 | 625 | return 0; 626 | 627 | leave: 628 | rfctl_exit_module(); 629 | return result; 630 | } 631 | 632 | static void rfctl_exit_module(void) 633 | { 634 | cdev_del(&rfctl_dev); 635 | unregister_chrdev_region(MKDEV(dev_major, 0), 1); 636 | 637 | if (gpio_out_pin != NO_GPIO_PIN) { 638 | gpio_unexport(gpio_out_pin); 639 | gpio_free(gpio_out_pin); 640 | } 641 | 642 | if (tx_ctrl_pin != NO_GPIO_PIN) { 643 | gpio_unexport(tx_ctrl_pin); 644 | gpio_free(tx_ctrl_pin); 645 | } 646 | 647 | if (gpio_in_pin != NO_GPIO_PIN) { 648 | gpio_unexport(gpio_in_pin); 649 | gpio_free(gpio_in_pin); 650 | } 651 | 652 | info("%s %s unregistered\n", DRIVER_NAME, DRIVER_VERSION); 653 | } 654 | 655 | module_init(rfctl_init_module); 656 | module_exit(rfctl_exit_module); 657 | 658 | MODULE_DESCRIPTION("RF Tx/Rx driver for Raspberry Pi GPIO"); 659 | MODULE_AUTHOR("Tord Andersson, Joachim Nilsson"); 660 | MODULE_LICENSE("GPL"); 661 | 662 | module_param(debug, bool, S_IRUGO | S_IWUSR); 663 | MODULE_PARM_DESC(debug, "Enable debugging messages"); 664 | 665 | module_param(gpio_out_pin, int, S_IRUGO); 666 | MODULE_PARM_DESC(gpio_out_pin, "GPIO output (Tx) pin of the BCM" 667 | " processor. (default " xstringify(DEFAULT_GPIO_OUT_PIN) ")"); 668 | 669 | module_param(gpio_in_pin, int, S_IRUGO); 670 | MODULE_PARM_DESC(gpio_in_pin, "GPIO input (Rx) pin number of the BCM processor." 671 | " (default " xstringify(DEFAULT_GPIO_IN_PIN) ")"); 672 | --------------------------------------------------------------------------------