Raspberry pi & Raspberry Pico 433MHZ: transmit, receive, relay

This commit is contained in:
aixiao 2023-04-12 14:56:55 +08:00
parent d3f887d658
commit 295f4e8a66
40 changed files with 3493 additions and 0 deletions

22
433/433Utils/.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
# Mac stuff
.DS_Store
# Compiled Object files
*.slo
*.lo
*.o
# Compiled Dynamic libraries
*.so
*.dylib
# Compiled Static libraries
*.lai
*.la
*.a
# Compiled executables
RPi_utils/RFSniffer
RPi_utils/codesend
RPi_utils/send

3
433/433Utils/.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "rc-switch"]
path = rc-switch
url = https://github.com/sui77/rc-switch.git

21
433/433Utils/LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014-2016 Ninja Blocks Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

67
433/433Utils/README.md Normal file
View File

@ -0,0 +1,67 @@
# About 433Utils
433Utils is a collection of code and documentation designed to assist you in the connection and usage of RF 433MHz transmit and receive modules to/with your Arduino and Rapberry Pi.
It consists of two main sections- Arduino sketches and Raspberry Pi command line utilities. You'll find those in appropriately named folders.
Despite the name, 433Utils also works with 315MHz transmit and receive modules (tested).
## Requirements
1. An Arduino (two is ideal)
2. A Raspberry Pi
3. The git commandline tool, on both your Arduino IDE machine and your RPi
4. RF 433MHz modules; a transmitter and receiver
5. A Ninja Block and account
## Installation
### Arduino\_Sketches
Place the Sketches in your normal Arduino Sketches location. Install any required libraries:
1. Servo motor library (Should be included in the Arduino IDE)
2. _Arduino_ [rc_switch](http://code.google.com/p/rc-switch/) library
### RPi\_utils
From your RPi, clone this archive:
1. ```git clone --recursive git://github.com/ninjablocks/433Utils.git``` (recursive ensure that the rc-switch submodule gets populated which is needed by RPi\_utils)
2. ```cd 433Utils/RPi_utils```
3. (As per the original rc_switch distribution) Follow the instructions to install the [wiringpi](https://projects.drogon.net/raspberry-pi/wiringpi/download-and-install/) library.
After that you can compile the example programs by executing *make*.
## Usage
### send
```sudo ./send systemCode unitCode command```
This command is unaltered from the original rc\_switch distribution.
### codesend
```sudo ./codesend decimalcode```
This command uses a single Ninja Blocks compatible decimal code. Sniff out codes using the RF\_Sniffer.ino Arduino sketch, included in this distribution.
You can use codesend to control the wireless servo on your Arduino.
(The sketch is Servo\_Receive\_Demo.ino)
I've implemented the most bare-bones of controls here. Try:
```sudo ./codesend 500000 # to move the servo up```
```sudo ./codesend 500001 # to move the servo down```
```sudo ./codesend 500002 # to move the servo left```
```sudo ./codesend 500003 # to move the servo right```
```sudo ./codesend 500004 # to move the servo home```
## Issues
Due to limitiations in the implementation of interrupt-driven routines in the underlying RCSwitch library, it is currently not possible to use both the send and receive functionality within the one program.

View File

@ -0,0 +1,20 @@
# Defines the RPI variable which is needed by rc-switch/RCSwitch.h
CXXFLAGS=-DRPI
CFLAGS += -Wall -Os -g
all: send codesend RFSniffer
send: ../rc-switch/RCSwitch.o send.o
$(CXX) $(CFLAGS) $(CXXFLAGS) $(LDFLAGS) $+ -o $@ -lwiringPi -lwiringPiDev -lcrypt
codesend: ../rc-switch/RCSwitch.o codesend.o
$(CXX) $(CFLAGS) $(CXXFLAGS) $(LDFLAGS) $+ -o $@ -lwiringPi -lwiringPiDev -lcrypt
RFSniffer: ../rc-switch/RCSwitch.o RFSniffer.o
$(CXX) $(CFLAGS) $(CXXFLAGS) $(LDFLAGS) $+ -o $@ -lwiringPi -lwiringPiDev -lcrypt
clean:
$(RM) ../rc-switch/*.o *.o send codesend servo RFSniffer

View File

@ -0,0 +1,17 @@
# About
rcswitch-pi is for controlling rc remote controlled power sockets
with the raspberry pi. Kudos to the projects [rc-switch](http://code.google.com/p/rc-switch)
and [wiringpi](https://projects.drogon.net/raspberry-pi/wiringpi).
I just adapted the rc-switch code to use the wiringpi library instead of
the library provided by the arduino.
## Usage
First you have to install the [wiringpi](https://projects.drogon.net/raspberry-pi/wiringpi/download-and-install/) library.
After that you can compile the example program *send* by executing *make*.
It uses wiringPi pin no 2 by default. You may want to change the used GPIO pin before compilation of the codesend.cpp source file. (Good Resource for Pin Details https://pinout.xyz/pinout/wiringpi)
## Note
The 'RF\_Sniffer' code is as yet untested. It _should_ work, but it is still being tested thoroughly. It's provided to allow you to start playing with it now.

View File

@ -0,0 +1,102 @@
/*
RFSniffer
Usage: ./RFSniffer [<pulseLength>]
[] = optional
Hacked from http://code.google.com/p/rc-switch/
by @justy to provide a handy RF code sniffer
*/
#include "../rc-switch/RCSwitch.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
RCSwitch mySwitch;
void light()
{
digitalWrite(25, LOW);
usleep(200000);
digitalWrite(25, HIGH);
//printf("%d\n", digitalRead(25));
}
int main(int argc, char *argv[]) {
// This pin is not the first pin on the RPi GPIO header!
// Consult https://projects.drogon.net/raspberry-pi/wiringpi/pins/
// for more information.
int PIN = 7;
if(wiringPiSetup() == -1) {
printf("wiringPiSetup failed, exiting...");
return 0;
}
int pulseLength = 0;
if (argv[1] != NULL) pulseLength = atoi(argv[1]);
mySwitch = RCSwitch();
if (pulseLength != 0) mySwitch.setPulseLength(pulseLength);
mySwitch.enableReceive(PIN); // Receiver on interrupt 0 => that is pin #2
pinMode(25, OUTPUT);
#define LIVE 1
static int i=0;
unsigned long value = 0;
static int values[LIVE] = {0};
while(1) {
while(1) {
if (mySwitch.available()) {
value = mySwitch.getReceivedValue();
values[i] = value;
if (value == 0)
{
printf("Unknown encoding\n");
}
else
{
light();
printf("i=%d, Received %lu\n", i, values[i] );
}
fflush(stdout);
mySwitch.resetAvailable();
if (i != 0) {
if (values[1] == values[0]+1)
printf("有我的按钮发来数据\n");
}
if (i != 1) {
if (values[0] == values[1]+1)
printf("有我的按钮发来数据\n");
}
if (i==LIVE) {
i=0;
break;
}
i=i+1;
}
}
usleep(100);
}
return 0;
}

View File

@ -0,0 +1,67 @@
/*
Usage: ./codesend decimalcode [protocol] [pulselength]
decimalcode - As decoded by RFSniffer
protocol - According to rc-switch definitions
pulselength - pulselength in microseconds
'codesend' hacked from 'send' by @justy
- The provided rc_switch 'send' command uses the form systemCode, unitCode, command
which is not suitable for our purposes. Instead, we call
send(code, length); // where length is always 24 and code is simply the code
we find using the RF_sniffer.ino Arduino sketch.
(Use RF_Sniffer.ino to check that RF signals are being produced by the RPi's transmitter
or your remote control)
*/
#include "../rc-switch/RCSwitch.h"
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
// This pin is not the first pin on the RPi GPIO header!
// Consult https://projects.drogon.net/raspberry-pi/wiringpi/pins/
// for more information.
int PIN = 7;
// Parse the first parameter to this command as an integer
int protocol = 0; // A value of 0 will use rc-switch's default value
int pulseLength = 0;
int bitLength = 24;
// If no command line argument is given, print the help text
if (argc == 1) {
printf("Usage: %s decimalcode [protocol] [pulselength] [bitlength]\n", argv[0]);
printf("decimalcode\t- As decoded by RFSniffer\n");
printf("protocol\t- According to rc-switch definitions\n");
printf("pulselength\t- pulselength in microseconds\n");
printf("bitlength\t- bit length\n");
return -1;
}
// Change protocol and pulse length accroding to parameters
char *eptr;
unsigned long code = strtoul(argv[1], &eptr, 10);
if (argc >= 3)
protocol = atoi(argv[2]);
if (argc >= 4)
pulseLength = atoi(argv[3]);
if (argc >= 5)
bitLength = atoi(argv[4]);
if (wiringPiSetup() == -1)
return 1;
printf("sending code[%lu]\n", code);
RCSwitch mySwitch = RCSwitch();
if (protocol != 0)
mySwitch.setProtocol(protocol);
if (pulseLength != 0)
mySwitch.setPulseLength(pulseLength);
mySwitch.enableTransmit(PIN);
mySwitch.send(code, bitLength);
return 0;
}

View File

@ -0,0 +1,62 @@
/*
Usage: ./send <systemCode> <unitCode> <command>
Command is 0 for OFF and 1 for ON
*/
#include "../rc-switch/RCSwitch.h"
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
/*
output PIN is hardcoded for testing purposes
see https://projects.drogon.net/raspberry-pi/wiringpi/pins/
for pin mapping of the raspberry pi GPIO connector
*/
int PIN = 7;
const char *code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
if (argc < 4) {
printf("Sending 433 MHz remote plug control codes, hardcoded on wiringpi pin %d.\n", PIN);
printf("Usage: %s <systemCode> <unitCode> <command> [pulseLength]\n", argv[0]);
printf("systemCode - First five settings of Type A 10 pole DIP switch, e.g. 11111\n");
printf("unitCode - Switch number [1 .. 5] or [10000 .. 00001]\n");
printf("command - 0 for OFF and 1 for ON\n");
printf("pulseLength - optional pulse length\n");
return -1;
}
char *systemCode = argv[1];
const char *unitCode;
if (strlen(argv[2]) == 5) {
unitCode = argv[2];
} else if (atoi(argv[2]) > 0 and atoi(argv[2]) < 6) {
unitCode = code[atoi(argv[2])];
} else {
return -1;
}
int command = atoi(argv[3]);
if (wiringPiSetup() == -1)
return 1;
printf("sending systemCode[%s] unitCode[%s] command[%i]\n", systemCode, unitCode, command);
RCSwitch mySwitch = RCSwitch();
if (argv[4] != NULL)
mySwitch.setPulseLength(atoi(argv[4]));
mySwitch.enableTransmit(PIN);
switch (command) {
case 1:
mySwitch.switchOn(systemCode, unitCode);
break;
case 0:
mySwitch.switchOff(systemCode, unitCode);
break;
default:
printf("command[%i] is unsupported\n", command);
return -1;
}
return 0;
}

17
433/433Utils/rc-switch/.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
# Mac stuff
.DS_Store
# Compiled Object files
*.slo
*.lo
*.o
# Compiled Dynamic libraries
*.so
*.dylib
# Compiled Static libraries
*.lai
*.la
*.a

View File

@ -0,0 +1,70 @@
language: c
python:
- "2.7"
# Cache PlatformIO packages using Travis CI container-based infrastructure
cache:
pip: true
directories:
- "~/.platformio"
env:
- >
PLATFORMIO_CI_SRC=$PWD/examples/Webserver
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/Webserver.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
- >
PLATFORMIO_CI_SRC=$PWD/examples/ReceiveDemo_Simple
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/ReceiveDemo_Simple.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
- >
PLATFORMIO_CI_SRC=$PWD/examples/TypeC_Intertechno
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeC_Intertechno.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
- >
PLATFORMIO_CI_SRC=$PWD/examples/TypeD_REV
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeD_REV.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
- >
PLATFORMIO_CI_SRC=$PWD/examples/TypeA_WithDIPSwitches
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeA_WithDIPSwitches.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
- >
PLATFORMIO_CI_SRC=$PWD/examples/TypeA_WithDIPSwitches_Lightweight
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeA_WithDIPSwitches_Lightweight.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
- >
PLATFORMIO_CI_SRC=$PWD/examples/TypeB_WithRotaryOrSlidingSwitches
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeB_WithRotaryOrSlidingSwitches.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
- >
PLATFORMIO_CI_SRC=$PWD/examples/SendDemo
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/SendDemo.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
- >
PLATFORMIO_CI_SRC=$PWD/examples/ReceiveDemo_Advanced
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/ReceiveDemo_Advanced.ino
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
before_install:
# Arduino IDE
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16"
- sleep 3
- export DISPLAY=:1.0
- wget http://downloads.arduino.cc/arduino-1.8.10-linux64.tar.xz
- tar xf arduino-1.8.10-linux64.tar.xz
- sudo mv arduino-1.8.10 /usr/local/share/arduino
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
install:
# Arduino IDE
- ln -s $PWD /usr/local/share/arduino/libraries/rc-switch
# PlatformIO
# - pip install -U platformio
# - platformio update
script:
# Arduino IDE
- arduino --verify --board arduino:avr:uno ${ARDUINOIDE_CI_SRC}
# PlatformIO
# - platformio run --lib="." ${BOARDS}

View File

@ -0,0 +1,744 @@
/*
RCSwitch - Arduino libary for remote control outlet switches
Copyright (c) 2011 Suat Özgür. All right reserved.
Contributors:
- Andre Koehler / info(at)tomate-online(dot)de
- Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
- Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
- Dominik Fischer / dom_fischer(at)web(dot)de
- Frank Oltmanns / <first name>.<last name>(at)gmail(dot)com
- Andreas Steinel / A.<lastname>(at)gmail(dot)com
- Max Horn / max(at)quendi(dot)de
- Robert ter Vehn / <first name>.<last name>(at)gmail(dot)com
- Johann Richard / <first name>.<last name>(at)gmail(dot)com
- Vlad Gheorghe / <first name>.<last name>(at)gmail(dot)com https://github.com/vgheo
- Matias Cuenca-Acuna
Project home: https://github.com/sui77/rc-switch/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "RCSwitch.h"
#ifdef RaspberryPi
// PROGMEM and _P functions are for AVR based microprocessors,
// so we must normalize these for the ARM processor:
#define PROGMEM
#define memcpy_P(dest, src, num) memcpy((dest), (src), (num))
#endif
#if defined(ESP8266)
// interrupt handler and related code must be in RAM on ESP8266,
// according to issue #46.
#define RECEIVE_ATTR ICACHE_RAM_ATTR
#define VAR_ISR_ATTR
#elif defined(ESP32)
#define RECEIVE_ATTR IRAM_ATTR
#define VAR_ISR_ATTR DRAM_ATTR
#else
#define RECEIVE_ATTR
#define VAR_ISR_ATTR
#endif
/* Format for protocol definitions:
* {pulselength, Sync bit, "0" bit, "1" bit, invertedSignal}
*
* pulselength: pulse length in microseconds, e.g. 350
* Sync bit: {1, 31} means 1 high pulse and 31 low pulses
* (perceived as a 31*pulselength long pulse, total length of sync bit is
* 32*pulselength microseconds), i.e:
* _
* | |_______________________________ (don't count the vertical bars)
* "0" bit: waveform for a data bit of value "0", {1, 3} means 1 high pulse
* and 3 low pulses, total length (1+3)*pulselength, i.e:
* _
* | |___
* "1" bit: waveform for a data bit of value "1", e.g. {3,1}:
* ___
* | |_
*
* These are combined to form Tri-State bits when sending or receiving codes.
*/
#if defined(ESP8266) || defined(ESP32)
static const VAR_ISR_ATTR RCSwitch::Protocol proto[] = {
#else
static const RCSwitch::Protocol PROGMEM proto[] = {
#endif
{ 350, { 1, 31}, { 1, 3}, { 3, 1}, false }, // protocol 1
{ 650, { 1, 10}, { 1, 2}, { 2, 1}, false }, // protocol 2
{ 100, { 30, 71}, { 4, 11}, { 9, 6}, false }, // protocol 3
{ 380, { 1, 6}, { 1, 3}, { 3, 1}, false }, // protocol 4
{ 500, { 6, 14}, { 1, 2}, { 2, 1}, false }, // protocol 5
{ 450, { 23, 1}, { 1, 2}, { 2, 1}, true }, // protocol 6 (HT6P20B)
{ 150, { 2, 62}, { 1, 6}, { 6, 1}, false }, // protocol 7 (HS2303-PT, i. e. used in AUKEY Remote)
{ 200, { 3, 130}, { 7, 16}, { 3, 16}, false }, // protocol 8 Conrad RS-200 RX
{ 200, { 130, 7}, { 16, 7}, { 16, 3}, true }, // protocol 9 Conrad RS-200 TX
{ 365, { 18, 1}, { 3, 1}, { 1, 3}, true }, // protocol 10 (1ByOne Doorbell)
{ 270, { 36, 1}, { 1, 2}, { 2, 1}, true }, // protocol 11 (HT12E)
{ 320, { 36, 1}, { 1, 2}, { 2, 1}, true } // protocol 12 (SM5212)
};
enum {
numProto = sizeof(proto) / sizeof(proto[0])
};
#if not defined( RCSwitchDisableReceiving )
volatile unsigned long RCSwitch::nReceivedValue = 0;
volatile unsigned int RCSwitch::nReceivedBitlength = 0;
volatile unsigned int RCSwitch::nReceivedDelay = 0;
volatile unsigned int RCSwitch::nReceivedProtocol = 0;
int RCSwitch::nReceiveTolerance = 60;
const unsigned int VAR_ISR_ATTR RCSwitch::nSeparationLimit = 4300;
// separationLimit: minimum microseconds between received codes, closer codes are ignored.
// according to discussion on issue #14 it might be more suitable to set the separation
// limit to the same time as the 'low' part of the sync signal for the current protocol.
unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES];
#endif
RCSwitch::RCSwitch()
{
this->nTransmitterPin = -1;
this->setRepeatTransmit(10);
this->setProtocol(1);
#if not defined( RCSwitchDisableReceiving )
this->nReceiverInterrupt = -1;
this->setReceiveTolerance(60);
RCSwitch::nReceivedValue = 0;
#endif
}
/**
* Sets the protocol to send.
*/
void RCSwitch::setProtocol(Protocol protocol)
{
this->protocol = protocol;
}
/**
* Sets the protocol to send, from a list of predefined protocols
*/
void RCSwitch::setProtocol(int nProtocol)
{
if (nProtocol < 1 || nProtocol > numProto) {
nProtocol = 1; // TODO: trigger an error, e.g. "bad protocol" ???
}
#if defined(ESP8266) || defined(ESP32)
this->protocol = proto[nProtocol - 1];
#else
memcpy_P(&this->protocol, &proto[nProtocol - 1], sizeof(Protocol));
#endif
}
/**
* Sets the protocol to send with pulse length in microseconds.
*/
void RCSwitch::setProtocol(int nProtocol, int nPulseLength)
{
setProtocol(nProtocol);
this->setPulseLength(nPulseLength);
}
/**
* Sets pulse length in microseconds
*/
void RCSwitch::setPulseLength(int nPulseLength)
{
this->protocol.pulseLength = nPulseLength;
}
/**
* Sets Repeat Transmits
*/
void RCSwitch::setRepeatTransmit(int nRepeatTransmit)
{
this->nRepeatTransmit = nRepeatTransmit;
}
/**
* Set Receiving Tolerance
*/
#if not defined( RCSwitchDisableReceiving )
void RCSwitch::setReceiveTolerance(int nPercent)
{
RCSwitch::nReceiveTolerance = nPercent;
}
#endif
/**
* Enable transmissions
*
* @param nTransmitterPin Arduino Pin to which the sender is connected to
*/
void RCSwitch::enableTransmit(int nTransmitterPin)
{
this->nTransmitterPin = nTransmitterPin;
pinMode(this->nTransmitterPin, OUTPUT);
}
/**
* Disable transmissions
*/
void RCSwitch::disableTransmit()
{
this->nTransmitterPin = -1;
}
/**
* Switch a remote switch on (Type D REV)
*
* @param sGroup Code of the switch group (A,B,C,D)
* @param nDevice Number of the switch itself (1..3)
*/
void RCSwitch::switchOn(char sGroup, int nDevice)
{
this->sendTriState(this->getCodeWordD(sGroup, nDevice, true));
}
/**
* Switch a remote switch off (Type D REV)
*
* @param sGroup Code of the switch group (A,B,C,D)
* @param nDevice Number of the switch itself (1..3)
*/
void RCSwitch::switchOff(char sGroup, int nDevice)
{
this->sendTriState(this->getCodeWordD(sGroup, nDevice, false));
}
/**
* Switch a remote switch on (Type C Intertechno)
*
* @param sFamily Familycode (a..f)
* @param nGroup Number of group (1..4)
* @param nDevice Number of device (1..4)
*/
void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice)
{
this->sendTriState(this->getCodeWordC(sFamily, nGroup, nDevice, true));
}
/**
* Switch a remote switch off (Type C Intertechno)
*
* @param sFamily Familycode (a..f)
* @param nGroup Number of group (1..4)
* @param nDevice Number of device (1..4)
*/
void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice)
{
this->sendTriState(this->getCodeWordC(sFamily, nGroup, nDevice, false));
}
/**
* Switch a remote switch on (Type B with two rotary/sliding switches)
*
* @param nAddressCode Number of the switch group (1..4)
* @param nChannelCode Number of the switch itself (1..4)
*/
void RCSwitch::switchOn(int nAddressCode, int nChannelCode)
{
this->sendTriState(this->getCodeWordB(nAddressCode, nChannelCode, true));
}
/**
* Switch a remote switch off (Type B with two rotary/sliding switches)
*
* @param nAddressCode Number of the switch group (1..4)
* @param nChannelCode Number of the switch itself (1..4)
*/
void RCSwitch::switchOff(int nAddressCode, int nChannelCode)
{
this->sendTriState(this->getCodeWordB(nAddressCode, nChannelCode, false));
}
/**
* Deprecated, use switchOn(const char* sGroup, const char* sDevice) instead!
* Switch a remote switch on (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param nChannelCode Number of the switch itself (1..5)
*/
void RCSwitch::switchOn(const char *sGroup, int nChannel)
{
const char *code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
this->switchOn(sGroup, code[nChannel]);
}
/**
* Deprecated, use switchOff(const char* sGroup, const char* sDevice) instead!
* Switch a remote switch off (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param nChannelCode Number of the switch itself (1..5)
*/
void RCSwitch::switchOff(const char *sGroup, int nChannel)
{
const char *code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
this->switchOff(sGroup, code[nChannel]);
}
/**
* Switch a remote switch on (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
*/
void RCSwitch::switchOn(const char *sGroup, const char *sDevice)
{
this->sendTriState(this->getCodeWordA(sGroup, sDevice, true));
}
/**
* Switch a remote switch off (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
*/
void RCSwitch::switchOff(const char *sGroup, const char *sDevice)
{
this->sendTriState(this->getCodeWordA(sGroup, sDevice, false));
}
/**
* Returns a char[13], representing the code word to be send.
*
*/
char *RCSwitch::getCodeWordA(const char *sGroup, const char *sDevice, bool bStatus)
{
static char sReturn[13];
int nReturnPos = 0;
for (int i = 0; i < 5; i++) {
sReturn[nReturnPos++] = (sGroup[i] == '0') ? 'F' : '0';
}
for (int i = 0; i < 5; i++) {
sReturn[nReturnPos++] = (sDevice[i] == '0') ? 'F' : '0';
}
sReturn[nReturnPos++] = bStatus ? '0' : 'F';
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* Encoding for type B switches with two rotary/sliding switches.
*
* The code word is a tristate word and with following bit pattern:
*
* +-----------------------------+-----------------------------+----------+------------+
* | 4 bits address | 4 bits address | 3 bits | 1 bit |
* | switch group | switch number | not used | on / off |
* | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | FFF | on=F off=0 |
* +-----------------------------+-----------------------------+----------+------------+
*
* @param nAddressCode Number of the switch group (1..4)
* @param nChannelCode Number of the switch itself (1..4)
* @param bStatus Whether to switch on (true) or off (false)
*
* @return char[13], representing a tristate code word of length 12
*/
char *RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus)
{
static char sReturn[13];
int nReturnPos = 0;
if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) {
return 0;
}
for (int i = 1; i <= 4; i++) {
sReturn[nReturnPos++] = (nAddressCode == i) ? '0' : 'F';
}
for (int i = 1; i <= 4; i++) {
sReturn[nReturnPos++] = (nChannelCode == i) ? '0' : 'F';
}
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* Like getCodeWord (Type C = Intertechno)
*/
char *RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus)
{
static char sReturn[13];
int nReturnPos = 0;
int nFamily = (int)sFamily - 'a';
if (nFamily < 0 || nFamily > 15 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) {
return 0;
}
// encode the family into four bits
sReturn[nReturnPos++] = (nFamily & 1) ? 'F' : '0';
sReturn[nReturnPos++] = (nFamily & 2) ? 'F' : '0';
sReturn[nReturnPos++] = (nFamily & 4) ? 'F' : '0';
sReturn[nReturnPos++] = (nFamily & 8) ? 'F' : '0';
// encode the device and group
sReturn[nReturnPos++] = ((nDevice - 1) & 1) ? 'F' : '0';
sReturn[nReturnPos++] = ((nDevice - 1) & 2) ? 'F' : '0';
sReturn[nReturnPos++] = ((nGroup - 1) & 1) ? 'F' : '0';
sReturn[nReturnPos++] = ((nGroup - 1) & 2) ? 'F' : '0';
// encode the status code
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* Encoding for the REV Switch Type
*
* The code word is a tristate word and with following bit pattern:
*
* +-----------------------------+-------------------+----------+--------------+
* | 4 bits address | 3 bits address | 3 bits | 2 bits |
* | switch group | device number | not used | on / off |
* | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FF 2=F0F 3=FF0 | 000 | on=10 off=01 |
* +-----------------------------+-------------------+----------+--------------+
*
* Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/
*
* @param sGroup Name of the switch group (A..D, resp. a..d)
* @param nDevice Number of the switch itself (1..3)
* @param bStatus Whether to switch on (true) or off (false)
*
* @return char[13], representing a tristate code word of length 12
*/
char *RCSwitch::getCodeWordD(char sGroup, int nDevice, bool bStatus)
{
static char sReturn[13];
int nReturnPos = 0;
// sGroup must be one of the letters in "abcdABCD"
int nGroup = (sGroup >= 'a') ? (int)sGroup - 'a' : (int)sGroup - 'A';
if (nGroup < 0 || nGroup > 3 || nDevice < 1 || nDevice > 3) {
return 0;
}
for (int i = 0; i < 4; i++) {
sReturn[nReturnPos++] = (nGroup == i) ? '1' : 'F';
}
for (int i = 1; i <= 3; i++) {
sReturn[nReturnPos++] = (nDevice == i) ? '1' : 'F';
}
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = bStatus ? '1' : '0';
sReturn[nReturnPos++] = bStatus ? '0' : '1';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* @param sCodeWord a tristate code word consisting of the letter 0, 1, F
*/
void RCSwitch::sendTriState(const char *sCodeWord)
{
// turn the tristate code word into the corresponding bit pattern, then send it
unsigned long code = 0;
unsigned int length = 0;
for (const char *p = sCodeWord; *p; p++) {
code <<= 2L;
switch (*p) {
case '0':
// bit pattern 00
break;
case 'F':
// bit pattern 01
code |= 1L;
break;
case '1':
// bit pattern 11
code |= 3L;
break;
}
length += 2;
}
this->send(code, length);
}
/**
* @param sCodeWord a binary code word consisting of the letter 0, 1
*/
void RCSwitch::send(const char *sCodeWord)
{
// turn the tristate code word into the corresponding bit pattern, then send it
unsigned long code = 0;
unsigned int length = 0;
for (const char *p = sCodeWord; *p; p++) {
code <<= 1L;
if (*p != '0')
code |= 1L;
length++;
}
this->send(code, length);
}
/**
* Transmit the first 'length' bits of the integer 'code'. The
* bits are sent from MSB to LSB, i.e., first the bit at position length-1,
* then the bit at position length-2, and so on, till finally the bit at position 0.
*/
void RCSwitch::send(unsigned long code, unsigned int length)
{
if (this->nTransmitterPin == -1)
return;
#if not defined( RCSwitchDisableReceiving )
// make sure the receiver is disabled while we transmit
int nReceiverInterrupt_backup = nReceiverInterrupt;
if (nReceiverInterrupt_backup != -1) {
this->disableReceive();
}
#endif
for (int nRepeat = 0; nRepeat < nRepeatTransmit; nRepeat++) {
for (int i = length - 1; i >= 0; i--) {
if (code & (1L << i))
this->transmit(protocol.one);
else
this->transmit(protocol.zero);
}
this->transmit(protocol.syncFactor);
}
// Disable transmit after sending (i.e., for inverted protocols)
digitalWrite(this->nTransmitterPin, LOW);
#if not defined( RCSwitchDisableReceiving )
// enable receiver again if we just disabled it
if (nReceiverInterrupt_backup != -1) {
this->enableReceive(nReceiverInterrupt_backup);
}
#endif
}
/**
* Transmit a single high-low pulse.
*/
void RCSwitch::transmit(HighLow pulses)
{
uint8_t firstLogicLevel = (this->protocol.invertedSignal) ? LOW : HIGH;
uint8_t secondLogicLevel = (this->protocol.invertedSignal) ? HIGH : LOW;
digitalWrite(this->nTransmitterPin, firstLogicLevel);
delayMicroseconds(this->protocol.pulseLength * pulses.high);
digitalWrite(this->nTransmitterPin, secondLogicLevel);
delayMicroseconds(this->protocol.pulseLength * pulses.low);
}
#if not defined( RCSwitchDisableReceiving )
/**
* Enable receiving data
*/
void RCSwitch::enableReceive(int interrupt)
{
this->nReceiverInterrupt = interrupt;
this->enableReceive();
}
void RCSwitch::enableReceive()
{
if (this->nReceiverInterrupt != -1) {
RCSwitch::nReceivedValue = 0;
RCSwitch::nReceivedBitlength = 0;
#if defined(RaspberryPi) // Raspberry Pi
wiringPiISR(this->nReceiverInterrupt, INT_EDGE_BOTH, &handleInterrupt);
#else // Arduino
attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE);
#endif
}
}
/**
* Disable receiving data
*/
void RCSwitch::disableReceive()
{
#if not defined(RaspberryPi) // Arduino
detachInterrupt(this->nReceiverInterrupt);
#endif // For Raspberry Pi (wiringPi) you can't unregister the ISR
this->nReceiverInterrupt = -1;
}
bool RCSwitch::available()
{
return RCSwitch::nReceivedValue != 0;
}
void RCSwitch::resetAvailable()
{
RCSwitch::nReceivedValue = 0;
}
unsigned long RCSwitch::getReceivedValue()
{
return RCSwitch::nReceivedValue;
}
unsigned int RCSwitch::getReceivedBitlength()
{
return RCSwitch::nReceivedBitlength;
}
unsigned int RCSwitch::getReceivedDelay()
{
return RCSwitch::nReceivedDelay;
}
unsigned int RCSwitch::getReceivedProtocol()
{
return RCSwitch::nReceivedProtocol;
}
unsigned int *RCSwitch::getReceivedRawdata()
{
return RCSwitch::timings;
}
/* helper function for the receiveProtocol method */
static inline unsigned int diff(int A, int B)
{
return abs(A - B);
}
/**
*
*/
bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCount)
{
#if defined(ESP8266) || defined(ESP32)
const Protocol & pro = proto[p - 1];
#else
Protocol pro;
memcpy_P(&pro, &proto[p - 1], sizeof(Protocol));
#endif
unsigned long code = 0;
//Assuming the longer pulse length is the pulse captured in timings[0]
const unsigned int syncLengthInPulses = ((pro.syncFactor.low) > (pro.syncFactor.high)) ? (pro.syncFactor.low) : (pro.syncFactor.high);
const unsigned int delay = RCSwitch::timings[0] / syncLengthInPulses;
const unsigned int delayTolerance = delay * RCSwitch::nReceiveTolerance / 100;
/* For protocols that start low, the sync period looks like
* _________
* _____________| |XXXXXXXXXXXX|
*
* |--1st dur--|-2nd dur-|-Start data-|
*
* The 3rd saved duration starts the data.
*
* For protocols that start high, the sync period looks like
*
* ______________
* | |____________|XXXXXXXXXXXXX|
*
* |-filtered out-|--1st dur--|--Start data--|
*
* The 2nd saved duration starts the data
*/
const unsigned int firstDataTiming = (pro.invertedSignal) ? (2) : (1);
for (unsigned int i = firstDataTiming; i < changeCount - 1; i += 2) {
code <<= 1;
if (diff(RCSwitch::timings[i], delay * pro.zero.high) < delayTolerance && diff(RCSwitch::timings[i + 1], delay * pro.zero.low) < delayTolerance) {
// zero
} else if (diff(RCSwitch::timings[i], delay * pro.one.high) < delayTolerance && diff(RCSwitch::timings[i + 1], delay * pro.one.low) < delayTolerance) {
// one
code |= 1;
} else {
// Failed
return false;
}
}
if (changeCount > 7) { // ignore very short transmissions: no device sends them, so this must be noise
RCSwitch::nReceivedValue = code;
RCSwitch::nReceivedBitlength = (changeCount - 1) / 2;
RCSwitch::nReceivedDelay = delay;
RCSwitch::nReceivedProtocol = p;
return true;
}
return false;
}
void RECEIVE_ATTR RCSwitch::handleInterrupt()
{
static unsigned int changeCount = 0;
static unsigned long lastTime = 0;
static unsigned int repeatCount = 0;
const long time = micros();
const unsigned int duration = time - lastTime;
if (duration > RCSwitch::nSeparationLimit) {
// A long stretch without signal level change occurred. This could
// be the gap between two transmission.
if ((repeatCount == 0) || (diff(duration, RCSwitch::timings[0]) < 200)) {
// This long signal is close in length to the long signal which
// started the previously recorded timings; this suggests that
// it may indeed by a a gap between two transmissions (we assume
// here that a sender will send the signal multiple times,
// with roughly the same gap between them).
repeatCount++;
if (repeatCount == 2) {
for (unsigned int i = 1; i <= numProto; i++) {
if (receiveProtocol(i, changeCount)) {
// receive succeeded for protocol i
break;
}
}
repeatCount = 0;
}
}
changeCount = 0;
}
// detect overflow
if (changeCount >= RCSWITCH_MAX_CHANGES) {
changeCount = 0;
repeatCount = 0;
}
RCSwitch::timings[changeCount++] = duration;
lastTime = time;
}
#endif

View File

@ -0,0 +1,182 @@
/*
RCSwitch - Arduino libary for remote control outlet switches
Copyright (c) 2011 Suat Özgür. All right reserved.
Contributors:
- Andre Koehler / info(at)tomate-online(dot)de
- Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
- Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
- Dominik Fischer / dom_fischer(at)web(dot)de
- Frank Oltmanns / <first name>.<last name>(at)gmail(dot)com
- Max Horn / max(at)quendi(dot)de
- Robert ter Vehn / <first name>.<last name>(at)gmail(dot)com
Project home: https://github.com/sui77/rc-switch/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _RCSwitch_h
#define _RCSwitch_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#elif defined(ENERGIA) // LaunchPad, FraunchPad and StellarPad specific
#include "Energia.h"
#elif defined(RPI) // Raspberry Pi
#define RaspberryPi
// Include libraries for RPi:
#include <string.h> /* memcpy */
#include <stdlib.h> /* abs */
#include <wiringPi.h>
#elif defined(SPARK)
#include "application.h"
#else
#include "WProgram.h"
#endif
#include <stdint.h>
// At least for the ATTiny X4/X5, receiving has to be disabled due to
// missing libm depencies (udivmodhi4)
#if defined( __AVR_ATtinyX5__ ) or defined ( __AVR_ATtinyX4__ )
#define RCSwitchDisableReceiving
#endif
// Number of maximum high/Low changes per packet.
// We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync
#define RCSWITCH_MAX_CHANGES 67
class RCSwitch {
public:
RCSwitch();
void switchOn(int nGroupNumber, int nSwitchNumber);
void switchOff(int nGroupNumber, int nSwitchNumber);
void switchOn(const char *sGroup, int nSwitchNumber);
void switchOff(const char *sGroup, int nSwitchNumber);
void switchOn(char sFamily, int nGroup, int nDevice);
void switchOff(char sFamily, int nGroup, int nDevice);
void switchOn(const char *sGroup, const char *sDevice);
void switchOff(const char *sGroup, const char *sDevice);
void switchOn(char sGroup, int nDevice);
void switchOff(char sGroup, int nDevice);
void sendTriState(const char *sCodeWord);
void send(unsigned long code, unsigned int length);
void send(const char *sCodeWord);
#if not defined( RCSwitchDisableReceiving )
void enableReceive(int interrupt);
void enableReceive();
void disableReceive();
bool available();
void resetAvailable();
unsigned long getReceivedValue();
unsigned int getReceivedBitlength();
unsigned int getReceivedDelay();
unsigned int getReceivedProtocol();
unsigned int *getReceivedRawdata();
#endif
void enableTransmit(int nTransmitterPin);
void disableTransmit();
void setPulseLength(int nPulseLength);
void setRepeatTransmit(int nRepeatTransmit);
#if not defined( RCSwitchDisableReceiving )
void setReceiveTolerance(int nPercent);
#endif
/**
* Description of a single pule, which consists of a high signal
* whose duration is "high" times the base pulse length, followed
* by a low signal lasting "low" times the base pulse length.
* Thus, the pulse overall lasts (high+low)*pulseLength
*/
struct HighLow {
uint8_t high;
uint8_t low;
};
/**
* A "protocol" describes how zero and one bits are encoded into high/low
* pulses.
*/
struct Protocol {
/** base pulse length in microseconds, e.g. 350 */
uint16_t pulseLength;
HighLow syncFactor;
HighLow zero;
HighLow one;
/**
* If true, interchange high and low logic levels in all transmissions.
*
* By default, RCSwitch assumes that any signals it sends or receives
* can be broken down into pulses which start with a high signal level,
* followed by a a low signal level. This is e.g. the case for the
* popular PT 2260 encoder chip, and thus many switches out there.
*
* But some devices do it the other way around, and start with a low
* signal level, followed by a high signal level, e.g. the HT6P20B. To
* accommodate this, one can set invertedSignal to true, which causes
* RCSwitch to change how it interprets any HighLow struct FOO: It will
* then assume transmissions start with a low signal lasting
* FOO.high*pulseLength microseconds, followed by a high signal lasting
* FOO.low*pulseLength microseconds.
*/
bool invertedSignal;
};
void setProtocol(Protocol protocol);
void setProtocol(int nProtocol);
void setProtocol(int nProtocol, int nPulseLength);
private:
char *getCodeWordA(const char *sGroup, const char *sDevice, bool bStatus);
char *getCodeWordB(int nGroupNumber, int nSwitchNumber, bool bStatus);
char *getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus);
char *getCodeWordD(char group, int nDevice, bool bStatus);
void transmit(HighLow pulses);
#if not defined( RCSwitchDisableReceiving )
static void handleInterrupt();
static bool receiveProtocol(const int p, unsigned int changeCount);
int nReceiverInterrupt;
#endif
int nTransmitterPin;
int nRepeatTransmit;
Protocol protocol;
#if not defined( RCSwitchDisableReceiving )
static int nReceiveTolerance;
volatile static unsigned long nReceivedValue;
volatile static unsigned int nReceivedBitlength;
volatile static unsigned int nReceivedDelay;
volatile static unsigned int nReceivedProtocol;
const static unsigned int nSeparationLimit;
/*
* timings[0] contains sync timing, followed by a number of bits
*/
static unsigned int timings[RCSWITCH_MAX_CHANGES];
#endif
};
#endif

View File

@ -0,0 +1,42 @@
# rc-switch
[![arduino-library-badge](https://www.ardu-badge.com/badge/rc-switch.svg?)](https://www.ardu-badge.com/rc-switch)
[![Build Status](https://travis-ci.org/sui77/rc-switch.svg?branch=master)](https://travis-ci.org/sui77/rc-switch)
Use your Arduino or [Raspberry Pi](https://github.com/r10r/rcswitch-pi) to operate remote radio controlled devices
## Download
https://github.com/sui77/rc-switch/releases/latest
rc-switch is also listed in the arduino library manager.
## Wiki
https://github.com/sui77/rc-switch/wiki
## Info
### Send RC codes
Use your Arduino or Raspberry Pi to operate remote radio controlled devices.
This will most likely work with all popular low cost power outlet sockets. If
yours doesn't work, you might need to adjust the pulse length.
All you need is a Arduino or Raspberry Pi, a 315/433MHz AM transmitter and one
or more devices with one of the supported chipsets:
- SC5262 / SC5272
- HX2262 / HX2272
- PT2262 / PT2272
- EV1527 / RT1527 / FP1527 / HS1527
- Intertechno outlets
- HT6P20X
### Receive and decode RC codes
Find out what codes your remote is sending. Use your remote to control your
Arduino.
All you need is an Arduino, a 315/433MHz AM receiver (altough there is no
instruction yet, yes it is possible to hack an existing device) and a remote
hand set.
For the Raspberry Pi, clone the https://github.com/ninjablocks/433Utils project to
compile a sniffer tool and transmission commands.

View File

@ -0,0 +1,24 @@
/*
Example for receiving
https://github.com/sui77/rc-switch/
If you want to visualize a telegram copy the raw data and
paste it into http://test.sui.li/oszi/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
Serial.begin(9600);
mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
}
void loop() {
if (mySwitch.available()) {
output(mySwitch.getReceivedValue(), mySwitch.getReceivedBitlength(), mySwitch.getReceivedDelay(), mySwitch.getReceivedRawdata(),mySwitch.getReceivedProtocol());
mySwitch.resetAvailable();
}
}

View File

@ -0,0 +1,70 @@
static const char* bin2tristate(const char* bin);
static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength);
void output(unsigned long decimal, unsigned int length, unsigned int delay, unsigned int* raw, unsigned int protocol) {
const char* b = dec2binWzerofill(decimal, length);
Serial.print("Decimal: ");
Serial.print(decimal);
Serial.print(" (");
Serial.print( length );
Serial.print("Bit) Binary: ");
Serial.print( b );
Serial.print(" Tri-State: ");
Serial.print( bin2tristate( b) );
Serial.print(" PulseLength: ");
Serial.print(delay);
Serial.print(" microseconds");
Serial.print(" Protocol: ");
Serial.println(protocol);
Serial.print("Raw data: ");
for (unsigned int i=0; i<= length*2; i++) {
Serial.print(raw[i]);
Serial.print(",");
}
Serial.println();
Serial.println();
}
static const char* bin2tristate(const char* bin) {
static char returnValue[50];
int pos = 0;
int pos2 = 0;
while (bin[pos]!='\0' && bin[pos+1]!='\0') {
if (bin[pos]=='0' && bin[pos+1]=='0') {
returnValue[pos2] = '0';
} else if (bin[pos]=='1' && bin[pos+1]=='1') {
returnValue[pos2] = '1';
} else if (bin[pos]=='0' && bin[pos+1]=='1') {
returnValue[pos2] = 'F';
} else {
return "not applicable";
}
pos = pos+2;
pos2++;
}
returnValue[pos2] = '\0';
return returnValue;
}
static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength) {
static char bin[64];
unsigned int i=0;
while (Dec > 0) {
bin[32+i++] = ((Dec & 1) > 0) ? '1' : '0';
Dec = Dec >> 1;
}
for (unsigned int j = 0; j< bitLength; j++) {
if (j >= bitLength - i) {
bin[j] = bin[ 31 + i - (j - (bitLength - i)) ];
} else {
bin[j] = '0';
}
}
bin[bitLength] = '\0';
return bin;
}

View File

@ -0,0 +1,29 @@
/*
Simple example for receiving
https://github.com/sui77/rc-switch/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
Serial.begin(9600);
mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
}
void loop() {
if (mySwitch.available()) {
Serial.print("Received ");
Serial.print( mySwitch.getReceivedValue() );
Serial.print(" / ");
Serial.print( mySwitch.getReceivedBitlength() );
Serial.print("bit ");
Serial.print("Protocol: ");
Serial.println( mySwitch.getReceivedProtocol() );
mySwitch.resetAvailable();
}
}

View File

@ -0,0 +1,57 @@
/*
Example for different sending methods
https://github.com/sui77/rc-switch/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
Serial.begin(9600);
// Transmitter is connected to Arduino Pin #10
mySwitch.enableTransmit(10);
// Optional set protocol (default is 1, will work for most outlets)
// mySwitch.setProtocol(2);
// Optional set pulse length.
// mySwitch.setPulseLength(320);
// Optional set number of transmission repetitions.
// mySwitch.setRepeatTransmit(15);
}
void loop() {
/* See Example: TypeA_WithDIPSwitches */
mySwitch.switchOn("11111", "00010");
delay(1000);
mySwitch.switchOff("11111", "00010");
delay(1000);
/* Same switch as above, but using decimal code */
mySwitch.send(5393, 24);
delay(1000);
mySwitch.send(5396, 24);
delay(1000);
/* Same switch as above, but using binary code */
mySwitch.send("000000000001010100010001");
delay(1000);
mySwitch.send("000000000001010100010100");
delay(1000);
/* Same switch as above, but tri-state code */
mySwitch.sendTriState("00000FFF0F0F");
delay(1000);
mySwitch.sendTriState("00000FFF0FF0");
delay(1000);
delay(20000);
}

View File

@ -0,0 +1,40 @@
/*
Example for outlets which are configured with a 10 pole DIP switch.
https://github.com/sui77/rc-switch/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
// Transmitter is connected to Arduino Pin #10
mySwitch.enableTransmit(10);
// Optional set pulse length.
// mySwitch.setPulseLength(320);
}
void loop() {
// Switch on:
// The first parameter represents the setting of the first 5 DIP switches.
// In this example it's ON-ON-OFF-OFF-ON.
//
// The second parameter represents the setting of the last 5 DIP switches.
// In this example the last 5 DIP switches are OFF-ON-OFF-ON-OFF.
mySwitch.switchOn("11001", "01010");
// Wait a second
delay(1000);
// Switch off
mySwitch.switchOff("11001", "01010");
// Wait another second
delay(1000);
}

View File

@ -0,0 +1,43 @@
/*
This is a minimal sketch without using the library at all but only works for
the 10 pole dip switch sockets. It saves a lot of memory and thus might be
very useful to use with ATTinys :)
https://github.com/sui77/rc-switch/
*/
int RCLpin = 7;
void setup() {
pinMode(RCLpin, OUTPUT);
}
void loop() {
RCLswitch(0b010001000001); // DIPs an Steckdose: 0100010000 An:01
delay(2000);
RCLswitch(0b010001000010); // DIPs an Steckdose: 0100010000 Aus:10
delay(2000);
}
void RCLswitch(uint16_t code) {
for (int nRepeat=0; nRepeat<6; nRepeat++) {
for (int i=4; i<16; i++) {
RCLtransmit(1,3);
if (((code << (i-4)) & 2048) > 0) {
RCLtransmit(1,3);
} else {
RCLtransmit(3,1);
}
}
RCLtransmit(1,31);
}
}
void RCLtransmit(int nHighPulses, int nLowPulses) {
digitalWrite(RCLpin, HIGH);
delayMicroseconds( 350 * nHighPulses);
digitalWrite(RCLpin, LOW);
delayMicroseconds( 350 * nLowPulses);
}

View File

@ -0,0 +1,40 @@
/*
Example for outlets which are configured with two rotary/sliding switches.
https://github.com/sui77/rc-switch/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
// Transmitter is connected to Arduino Pin #10
mySwitch.enableTransmit(10);
// Optional set pulse length.
// mySwitch.setPulseLength(320);
}
void loop() {
// Switch on:
// The first parameter represents the setting of the first rotary switch.
// In this example it's switched to "1" or "A" or "I".
//
// The second parameter represents the setting of the second rotary switch.
// In this example it's switched to "4" or "D" or "IV".
mySwitch.switchOn(1, 4);
// Wait a second
delay(1000);
// Switch off
mySwitch.switchOff(1, 4);
// Wait another second
delay(1000);
}

View File

@ -0,0 +1,40 @@
/*
Example for Intertechno outlets
https://github.com/sui77/rc-switch/
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
// Transmitter is connected to Arduino Pin #10
mySwitch.enableTransmit(10);
// Optional set pulse length.
// mySwitch.setPulseLength(320);
}
void loop() {
// Switch on:
// The first parameter represents the familycode (a, b, c, ... f)
// The second parameter represents the group number
// The third parameter represents the device number
//
// In this example it's family 'b', group #3, device #2
mySwitch.switchOn('b', 3, 2);
// Wait a second
delay(1000);
// Switch off
mySwitch.switchOff('b', 3, 2);
// Wait another second
delay(1000);
}

View File

@ -0,0 +1,41 @@
/*
Example for REV outlets (e.g. 8342L)
https://github.com/sui77/rc-switch/
Need help? http://forum.ardumote.com
*/
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
void setup() {
// Transmitter is connected to Arduino Pin #10
mySwitch.enableTransmit(10);
// set pulse length.
mySwitch.setPulseLength(360);
}
void loop() {
// Switch on:
// The first parameter represents the channel (a, b, c, d)
// The second parameter represents the device number
//
// In this example it's family 'd', device #2
mySwitch.switchOn('d', 2);
// Wait a second
delay(1000);
// Switch off
mySwitch.switchOff('d', 2);
// Wait another second
delay(1000);
}

View File

@ -0,0 +1,154 @@
/*
A simple RCSwitch/Ethernet/Webserver demo
https://github.com/sui77/rc-switch/
*/
#include <SPI.h>
#include <Ethernet.h>
#include <RCSwitch.h>
// Ethernet configuration
uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // MAC Address
uint8_t ip[] = { 192,168,0, 2 }; // IP Address
EthernetServer server(80); // Server Port 80
// RCSwitch configuration
RCSwitch mySwitch = RCSwitch();
int RCTransmissionPin = 7;
// More to do...
// You should also modify the processCommand() and
// httpResponseHome() functions to fit your needs.
/**
* Setup
*/
void setup() {
Ethernet.begin(mac, ip);
server.begin();
mySwitch.enableTransmit( RCTransmissionPin );
}
/**
* Loop
*/
void loop() {
char* command = httpServer();
}
/**
* Command dispatcher
*/
void processCommand(char* command) {
if (strcmp(command, "1-on") == 0) {
mySwitch.switchOn(1,1);
} else if (strcmp(command, "1-off") == 0) {
mySwitch.switchOff(1,1);
} else if (strcmp(command, "2-on") == 0) {
mySwitch.switchOn(1,2);
} else if (strcmp(command, "2-off") == 0) {
mySwitch.switchOff(1,2);
}
}
/**
* HTTP Response with homepage
*/
void httpResponseHome(EthernetClient c) {
c.println("HTTP/1.1 200 OK");
c.println("Content-Type: text/html");
c.println();
c.println("<html>");
c.println("<head>");
c.println( "<title>RCSwitch Webserver Demo</title>");
c.println( "<style>");
c.println( "body { font-family: Arial, sans-serif; font-size:12px; }");
c.println( "</style>");
c.println("</head>");
c.println("<body>");
c.println( "<h1>RCSwitch Webserver Demo</h1>");
c.println( "<ul>");
c.println( "<li><a href=\"./?1-on\">Switch #1 on</a></li>");
c.println( "<li><a href=\"./?1-off\">Switch #1 off</a></li>");
c.println( "</ul>");
c.println( "<ul>");
c.println( "<li><a href=\"./?2-on\">Switch #2 on</a></li>");
c.println( "<li><a href=\"./?2-off\">Switch #2 off</a></li>");
c.println( "</ul>");
c.println( "<hr>");
c.println( "<a href=\"https://github.com/sui77/rc-switch/\">https://github.com/sui77/rc-switch/</a>");
c.println("</body>");
c.println("</html>");
}
/**
* HTTP Redirect to homepage
*/
void httpResponseRedirect(EthernetClient c) {
c.println("HTTP/1.1 301 Found");
c.println("Location: /");
c.println();
}
/**
* HTTP Response 414 error
* Command must not be longer than 30 characters
**/
void httpResponse414(EthernetClient c) {
c.println("HTTP/1.1 414 Request URI too long");
c.println("Content-Type: text/plain");
c.println();
c.println("414 Request URI too long");
}
/**
* Process HTTP requests, parse first request header line and
* call processCommand with GET query string (everything after
* the ? question mark in the URL).
*/
char* httpServer() {
EthernetClient client = server.available();
if (client) {
char sReturnCommand[32];
int nCommandPos=-1;
sReturnCommand[0] = '\0';
while (client.connected()) {
if (client.available()) {
char c = client.read();
if ((c == '\n') || (c == ' ' && nCommandPos>-1)) {
sReturnCommand[nCommandPos] = '\0';
if (strcmp(sReturnCommand, "\0") == 0) {
httpResponseHome(client);
} else {
processCommand(sReturnCommand);
httpResponseRedirect(client);
}
break;
}
if (nCommandPos>-1) {
sReturnCommand[nCommandPos++] = c;
}
if (c == '?' && nCommandPos == -1) {
nCommandPos = 0;
}
}
if (nCommandPos > 30) {
httpResponse414(client);
sReturnCommand[0] = '\0';
break;
}
}
if (nCommandPos!=-1) {
sReturnCommand[nCommandPos] = '\0';
}
// give the web browser time to receive the data
delay(1);
client.stop();
return sReturnCommand;
}
return '\0';
}

View File

@ -0,0 +1,57 @@
#######################################
# Syntax Coloring Map For RCSwitch
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
RCSwitch KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
##########
#SENDS Begin
##########
switchOn KEYWORD2
switchOff KEYWORD2
sendTriState KEYWORD2
send KEYWORD2
##########
#SENDS End
##########
##########
#RECEIVE Begin
##########
enableReceive KEYWORD2
disableReceive KEYWORD2
available KEYWORD2
resetAvailable KEYWORD2
setReceiveTolerance KEYWORD2
getReceivedValue KEYWORD2
getReceivedBitlength KEYWORD2
getReceivedDelay KEYWORD2
getReceivedProtocol KEYWORD2
getReceivedRawdata KEYWORD2
##########
#RECEIVE End
##########
##########
#OTHERS Begin
##########
enableTransmit KEYWORD2
disableTransmit KEYWORD2
setPulseLength KEYWORD2
setProtocol KEYWORD2
setRepeatTransmit KEYWORD2
##########
#OTHERS End
##########
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,21 @@
{
"name": "rc-switch",
"description": "Use your Arduino or Raspberry Pi to operate remote radio controlled devices",
"keywords": "rf, radio, wireless",
"authors":
{
"name": "Suat Ozgur"
},
"repository":
{
"type": "git",
"url": "https://github.com/sui77/rc-switch.git"
},
"version": "2.6.4",
"frameworks": [
"arduino",
"energia",
"wiringpi"
],
"platforms": "*"
}

View File

@ -0,0 +1,10 @@
name=rc-switch
version=2.6.4
author=sui77
maintainer=sui77,fingolfin <noreply@sui.li>
sentence=Operate 433/315Mhz devices.
paragraph=Use your Arduino, ESP8266/ESP32 or Raspberry Pi to operate remote radio controlled devices. This will most likely work with all popular low cost power outlet sockets.
category=Device Control
url=https://github.com/sui77/rc-switch
architectures=avr,esp8266,esp32,stm32,megaavr
includes=RCSwitch.h

16
433/rc-switch-pico/.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
.DS_Store
CMakeFiles/
elf2uf2/
generated/
pico-sdk/
CMakeCache.txt
CMakeDoxyfile.in
CMakeDoxygenDefaults.cmake
Makefile
cmake_install.cmake
*.bin
*.dis
*.elf
*.elf.map
*.hex
*.uf2

View File

@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.12)
# Pull in SDK (must be before project)
include(pico_sdk_import.cmake)
project(pico_examples C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(PICO_EXAMPLES_PATH ${PROJECT_SOURCE_DIR})
# Initialize the SDK
pico_sdk_init()
# Add blink example
add_subdirectory(examples/Transmit)
add_subdirectory(examples/Receive)

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 oshawa-connection
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,31 @@
add_executable(receive
Receive.cc
../../radio-switch.cc
)
add_compile_options(-Wall
-Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int
-Wno-unused-function # we have some for the docs that aren't called
-Wno-maybe-uninitialized
)
# Pull in our pico_stdlib which pulls in commonly used features
target_link_libraries(receive
pico_stdlib
hardware_adc
pico_multicore)
# enable usb output, disable uart output
pico_enable_stdio_usb(receive 1)
pico_enable_stdio_uart(receive 0)
# create map/bin/hex file etc.
pico_add_extra_outputs(receive)

View File

@ -0,0 +1,235 @@
#include <iostream>
#include "pico/stdlib.h"
#include "../../radio-switch.h"
#include "pico/stdio.h"
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/multicore.h"
//#include "hardware/adc.h"
//#include <stdio.h>
#include <time.h>
#define BUFFER_SIZ 1024
// 闪烁LED
void light()
{
const uint LED_PIN = PICO_DEFAULT_LED_PIN;
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
gpio_put(LED_PIN, 1);
sleep_ms(100);
gpio_put(LED_PIN, 0);
sleep_ms(100);
}
/*
int temperature() {
// 数模转换器为 0~3.3v 最大值为 12bit
const float conversion_factor = 3.3f / (1 << 12);
float v;
float t;
stdio_init_all();
printf("Use adc channel 4, measuring temptutre\n");
// ADC初始化
adc_init();
adc_set_temp_sensor_enabled(true);
adc_select_input(4);
// 数字转换为电压
v = adc_read() * conversion_factor;
t = 27 - (v - 0.706) / 0.001721;
printf("t:%.2f v:%.2f\n", t, v);
sleep_ms(100);
return 0;
}
*/
static char pool[] = {
'1', '2', '3', '4', '5', '6', '7', '8', '9'
};
// 随即数
static int RAND()
{
int PASSWD_LEN = 3;
char password[BUFFER_SIZ];
int i = 0;
FILE *fp;
memset(password, 0, BUFFER_SIZ);
srand(time(NULL));
while (i != PASSWD_LEN) {
password[i++] = pool[rand() % sizeof(pool)];
}
//printf("%d\n", atoi(password));
return atoi(password);
}
static void SEND(const int ID)
{
const uint RADIO_TRANSMIT_PIN = 16; // 433发射模块引脚
const uint BUTTON = 21; // 按钮发射
const uint PULSE_LENGTH = 169; // set this to PULSELENGTH RECIEVED
const uint REPEAT_TRANSMIT = 4; // set this to whatever works best for you. // 重复发送
const uint PROTOCOL = 1; // set this to PROTOCOL RECIEVED
const uint BIT_LENGTH = 24; // set this to BIT LENGTH RECIEVED
gpio_init(RADIO_TRANSMIT_PIN);
RCSwitch mySwitch = RCSwitch();
mySwitch.enableTransmit(RADIO_TRANSMIT_PIN);
mySwitch.setProtocol(PROTOCOL);
mySwitch.setPulseLength(PULSE_LENGTH);
mySwitch.setRepeatTransmit(REPEAT_TRANSMIT);
int RANDOM = 500;
int LOOP_NUM = 1; // 循环发送次数
for (int i = 0; i <= LOOP_NUM; i++) {
RANDOM = RAND();
light(); // 灯闪烁
sleep_ms(RANDOM * 2 / 3); // 等待随机时间
mySwitch.send(ID, BIT_LENGTH); // 第一次发射
sleep_ms(130);
mySwitch.send(ID + 1, BIT_LENGTH); // 第二次发射
sleep_ms(130);
}
}
int int_string(int val, char *string, int string_len, int *str_len, char *dest, int *dest_len)
{
char s[] = "55";
char d = '2';
snprintf(string, string_len, "%d", val);
*str_len = strlen(string);
if (0 == strncasecmp(string, s, 2)) {
dest[0] = d;
dest[1] = d;
strncpy(dest + 2, string + 2, (*str_len) - 2);
*dest_len = strlen(dest);
}
return 0;
}
// 核心0发送数据到核心1, 核心1判断是否有数据到来, 然后打印.
void core1_main()
{
const uint RADIO_RECEIVER_PIN = 17;
gpio_init(RADIO_RECEIVER_PIN);
RCSwitch rcSwitch = RCSwitch();
rcSwitch.enableReceive(RADIO_RECEIVER_PIN);
char str[270];
char dest[270];
int str_len;
int dest_len;
memset(str, 0, 270);
memset(dest, 0, 270);
while (true) {
if (rcSwitch.available()) {
light();
uint32_t val = rcSwitch.getReceivedValue();
//printf("核心1接收到的433MHZ数值%u\n", val);
int_string(val, str, 270, &str_len, dest, &dest_len);
if (val != 0) {
if (str[0] == '5' && str[1] == '5')
{
multicore_fifo_push_blocking(atoi(dest));
}
else
{
rcSwitch.resetAvailable();
val = 0;
continue;
}
}
rcSwitch.resetAvailable();
val = 0;
}
/*
if (multicore_fifo_rvalid()) {
uint32_t i = multicore_fifo_pop_blocking();
printf("核心1接收到核心0的数值%u\n", i);
}
*/
sleep_ms(130);
}
return ;
}
int main()
{
stdio_init_all();
multicore_reset_core1();
multicore_launch_core1(core1_main);
while (1) {
if (multicore_fifo_rvalid()) {
uint32_t i = multicore_fifo_pop_blocking(); // 读取核心1发送来的数据
//printf("核心0接收到核心1的数值%u\n", i);
//multicore_reset_core1(); // 关闭核心1
//SEND(i); // 433MHZ发送
//multicore_launch_core1(core1_main); // 开启核心1
//multicore_fifo_push_blocking(i); // 给核心1发送数据
SEND(i);
printf("核心0转发433MHZ %u\n", i);
}
sleep_ms(130);
}
return 0;
}

View File

@ -0,0 +1,21 @@
add_executable(transmit
Transmit.cc
../../radio-switch.cc
)
add_compile_options(-Wall
-Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int
-Wno-unused-function # we have some for the docs that aren't called
-Wno-maybe-uninitialized
)
# Pull in our pico_stdlib which pulls in commonly used features
target_link_libraries(transmit pico_stdlib)
# enable usb output, disable uart output
pico_enable_stdio_usb(transmit 1)
pico_enable_stdio_uart(transmit 0)
# create map/bin/hex file etc.
pico_add_extra_outputs(transmit)

View File

@ -0,0 +1,101 @@
#include <iostream>
#include "pico/stdlib.h"
#include "../../radio-switch.h"
#include <time.h>
#define BUFFER_SIZ 1024
// 闪烁LED
static void light()
{
const uint LED_PIN = PICO_DEFAULT_LED_PIN;
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);
gpio_put(LED_PIN, 1);
sleep_ms(100);
gpio_put(LED_PIN, 0);
sleep_ms(100);
}
static char pool[] = {
'1', '2', '3', '4', '5', '6', '7', '8', '9'
};
// 随即数
static int RAND()
{
int PASSWD_LEN = 3;
char password[BUFFER_SIZ];
int i = 0;
FILE *fp;
memset(password, 0, BUFFER_SIZ);
srand(time(NULL));
while (i != PASSWD_LEN) {
password[i++] = pool[rand() % sizeof(pool)];
}
printf("%d\n", atoi(password));
return atoi(password);
}
int main(void) {
const uint RADIO_TRANSMIT_PIN = 16; // 433发射模块引脚
const uint BUTTON = 17; // 按钮发射
const uint PULSE_LENGTH = 169; // set this to PULSELENGTH RECIEVED
const uint REPEAT_TRANSMIT = 4; // set this to whatever works best for you. // 重复发送
const uint PROTOCOL = 1; // set this to PROTOCOL RECIEVED
const uint BIT_LENGTH = 24; // set this to BIT LENGTH RECIEVED
stdio_init_all();
gpio_init(RADIO_TRANSMIT_PIN);
RCSwitch mySwitch = RCSwitch();
mySwitch.enableTransmit(RADIO_TRANSMIT_PIN);
mySwitch.setProtocol(PROTOCOL);
mySwitch.setPulseLength(PULSE_LENGTH);
mySwitch.setRepeatTransmit(REPEAT_TRANSMIT);
int RANDOM = 30;
int LOOP_NUM = 2; // 循环发送次数
const int but = 55001;
while(1)
{
//if (1 == gpio_get(BUTTON)) { // 按钮按下
for (int i=0; i<=LOOP_NUM; i++) {
RANDOM = RAND();
light(); // 灯闪烁
sleep_ms(RANDOM * 2 / 3); // 等待随机时间
mySwitch.send(but, BIT_LENGTH); // 第一次发射
sleep_ms(130);
//mySwitch.send(but+1, BIT_LENGTH); // 第二次发射
//sleep_ms(130);
}
//}
sleep_ms(3000);
}
return 0;
}

View File

@ -0,0 +1,62 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})

Binary file not shown.

View File

@ -0,0 +1,728 @@
/*
RCSwitch - Arduino libary for remote control outlet switches
Copyright (c) 2011 Suat Özgür. All right reserved.
Contributors:
- Andre Koehler / info(at)tomate-online(dot)de
- Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
- Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
- Dominik Fischer / dom_fischer(at)web(dot)de
- Frank Oltmanns / <first name>.<last name>(at)gmail(dot)com
- Andreas Steinel / A.<lastname>(at)gmail(dot)com
- Max Horn / max(at)quendi(dot)de
- Robert ter Vehn / <first name>.<last name>(at)gmail(dot)com
- Johann Richard / <first name>.<last name>(at)gmail(dot)com
- Vlad Gheorghe / <first name>.<last name>(at)gmail(dot)com https://github.com/vgheo
- Matias Cuenca-Acuna
Project home: https://github.com/sui77/rc-switch/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "radio-switch.h"
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/uart.h"
#ifdef _PICO_STDLIB_H
#define HIGH 1
#define LOW 0
#endif
#define PROGMEM
#define memcpy_P(dest, src, num) memcpy((dest), (src), (num))
#if defined(ESP8266)
// interrupt handler and related code must be in RAM on ESP8266,
// according to issue #46.
#define RECEIVE_ATTR ICACHE_RAM_ATTR
#define VAR_ISR_ATTR
#elif defined(ESP32)
#define RECEIVE_ATTR IRAM_ATTR
#define VAR_ISR_ATTR DRAM_ATTR
#else
#define RECEIVE_ATTR
#define VAR_ISR_ATTR
#endif
/* Format for protocol definitions:
* {pulselength, Sync bit, "0" bit, "1" bit, invertedSignal}
*
* pulselength: pulse length in microseconds, e.g. 350
* Sync bit: {1, 31} means 1 high pulse and 31 low pulses
* (perceived as a 31*pulselength long pulse, total length of sync bit is
* 32*pulselength microseconds), i.e:
* _
* | |_______________________________ (don't count the vertical bars)
* "0" bit: waveform for a data bit of value "0", {1, 3} means 1 high pulse
* and 3 low pulses, total length (1+3)*pulselength, i.e:
* _
* | |___
* "1" bit: waveform for a data bit of value "1", e.g. {3,1}:
* ___
* | |_
*
* These are combined to form Tri-State bits when sending or receiving codes.
*/
#if defined(ESP8266) || defined(ESP32)
static const VAR_ISR_ATTR RCSwitch::Protocol proto[] = {
#else
static const RCSwitch::Protocol PROGMEM proto[] = {
#endif
{ 350, { 1, 31 }, { 1, 3 }, { 3, 1 }, false }, // protocol 1
{ 650, { 1, 10 }, { 1, 2 }, { 2, 1 }, false }, // protocol 2
{ 100, { 30, 71 }, { 4, 11 }, { 9, 6 }, false }, // protocol 3
{ 380, { 1, 6 }, { 1, 3 }, { 3, 1 }, false }, // protocol 4
{ 500, { 6, 14 }, { 1, 2 }, { 2, 1 }, false }, // protocol 5
{ 450, { 23, 1 }, { 1, 2 }, { 2, 1 }, true }, // protocol 6 (HT6P20B)
{ 150, { 2, 62 }, { 1, 6 }, { 6, 1 }, false }, // protocol 7 (HS2303-PT, i. e. used in AUKEY Remote)
{ 200, { 3, 130}, { 7, 16 }, { 3, 16}, false}, // protocol 8 Conrad RS-200 RX
{ 200, { 130, 7 }, { 16, 7 }, { 16, 3 }, true}, // protocol 9 Conrad RS-200 TX
{ 365, { 18, 1 }, { 3, 1 }, { 1, 3 }, true }, // protocol 10 (1ByOne Doorbell)
{ 270, { 36, 1 }, { 1, 2 }, { 2, 1 }, true }, // protocol 11 (HT12E)
{ 320, { 36, 1 }, { 1, 2 }, { 2, 1 }, true } // protocol 12 (SM5212)
};
void RCSwitch::gpio_callback(unsigned int gpio, uint32_t events) {
RCSwitch::handleInterrupt();
}
enum {
numProto = sizeof(proto) / sizeof(proto[0])
};
#if not defined( RCSwitchDisableReceiving )
volatile unsigned long RCSwitch::nReceivedValue = 0;
volatile unsigned int RCSwitch::nReceivedBitlength = 0;
volatile unsigned int RCSwitch::nReceivedDelay = 0;
volatile unsigned int RCSwitch::nReceivedProtocol = 0;
int RCSwitch::nReceiveTolerance = 60;
const unsigned int VAR_ISR_ATTR RCSwitch::nSeparationLimit = 4300;
// separationLimit: minimum microseconds between received codes, closer codes are ignored.
// according to discussion on issue #14 it might be more suitable to set the separation
// limit to the same time as the 'low' part of the sync signal for the current protocol.
unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES];
#endif
RCSwitch::RCSwitch() {
this->nTransmitterPin = -1;
this->setRepeatTransmit(10);
this->setProtocol(1);
#if not defined( RCSwitchDisableReceiving )
this->nReceiverInterrupt = -1;
this->setReceiveTolerance(60);
RCSwitch::nReceivedValue = 0;
#endif
}
/**
* Sets the protocol to send.
*/
void RCSwitch::setProtocol(Protocol protocol) {
this->protocol = protocol;
}
/**
* Sets the protocol to send, from a list of predefined protocols
*/
void RCSwitch::setProtocol(int nProtocol) {
if (nProtocol < 1 || nProtocol > numProto) {
nProtocol = 1; // TODO: trigger an error, e.g. "bad protocol" ???
}
#if defined(ESP8266) || defined(ESP32)
this->protocol = proto[nProtocol-1];
#else
memcpy_P(&this->protocol, &proto[nProtocol-1], sizeof(Protocol));
#endif
}
/**
* Sets the protocol to send with pulse length in microseconds.
*/
void RCSwitch::setProtocol(int nProtocol, int nPulseLength) {
setProtocol(nProtocol);
this->setPulseLength(nPulseLength);
}
/**
* Sets pulse length in microseconds
*/
void RCSwitch::setPulseLength(int nPulseLength) {
this->protocol.pulseLength = nPulseLength;
}
/**
* Sets Repeat Transmits
*/
void RCSwitch::setRepeatTransmit(int nRepeatTransmit) {
this->nRepeatTransmit = nRepeatTransmit;
}
/**
* Set Receiving Tolerance
*/
#if not defined( RCSwitchDisableReceiving )
void RCSwitch::setReceiveTolerance(int nPercent) {
RCSwitch::nReceiveTolerance = nPercent;
}
#endif
/**
* Enable transmissions
*
* @param nTransmitterPin Arduino Pin to which the sender is connected to
*/
void RCSwitch::enableTransmit(int nTransmitterPin) {
this->nTransmitterPin = nTransmitterPin;
// pinMode(this->nTransmitterPin, OUTPUT);
gpio_set_dir(this->nTransmitterPin,GPIO_OUT);
}
/**
* Disable transmissions
*/
void RCSwitch::disableTransmit() {
this->nTransmitterPin = -1;
}
/**
* Switch a remote switch on (Type D REV)
*
* @param sGroup Code of the switch group (A,B,C,D)
* @param nDevice Number of the switch itself (1..3)
*/
void RCSwitch::switchOn(char sGroup, int nDevice) {
this->sendTriState( this->getCodeWordD(sGroup, nDevice, true) );
}
/**
* Switch a remote switch off (Type D REV)
*
* @param sGroup Code of the switch group (A,B,C,D)
* @param nDevice Number of the switch itself (1..3)
*/
void RCSwitch::switchOff(char sGroup, int nDevice) {
this->sendTriState( this->getCodeWordD(sGroup, nDevice, false) );
}
/**
* Switch a remote switch on (Type C Intertechno)
*
* @param sFamily Familycode (a..f)
* @param nGroup Number of group (1..4)
* @param nDevice Number of device (1..4)
*/
void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice) {
this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, true) );
}
/**
* Switch a remote switch off (Type C Intertechno)
*
* @param sFamily Familycode (a..f)
* @param nGroup Number of group (1..4)
* @param nDevice Number of device (1..4)
*/
void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice) {
this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, false) );
}
/**
* Switch a remote switch on (Type B with two rotary/sliding switches)
*
* @param nAddressCode Number of the switch group (1..4)
* @param nChannelCode Number of the switch itself (1..4)
*/
void RCSwitch::switchOn(int nAddressCode, int nChannelCode) {
this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, true) );
}
/**
* Switch a remote switch off (Type B with two rotary/sliding switches)
*
* @param nAddressCode Number of the switch group (1..4)
* @param nChannelCode Number of the switch itself (1..4)
*/
void RCSwitch::switchOff(int nAddressCode, int nChannelCode) {
this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, false) );
}
/**
* Deprecated, use switchOn(const char* sGroup, const char* sDevice) instead!
* Switch a remote switch on (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param nChannelCode Number of the switch itself (1..5)
*/
void RCSwitch::switchOn(const char* sGroup, int nChannel) {
const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
this->switchOn(sGroup, code[nChannel]);
}
/**
* Deprecated, use switchOff(const char* sGroup, const char* sDevice) instead!
* Switch a remote switch off (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param nChannelCode Number of the switch itself (1..5)
*/
void RCSwitch::switchOff(const char* sGroup, int nChannel) {
const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
this->switchOff(sGroup, code[nChannel]);
}
/**
* Switch a remote switch on (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
*/
void RCSwitch::switchOn(const char* sGroup, const char* sDevice) {
this->sendTriState( this->getCodeWordA(sGroup, sDevice, true) );
}
/**
* Switch a remote switch off (Type A with 10 pole DIP switches)
*
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
* @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
*/
void RCSwitch::switchOff(const char* sGroup, const char* sDevice) {
this->sendTriState( this->getCodeWordA(sGroup, sDevice, false) );
}
/**
* Returns a char[13], representing the code word to be send.
*
*/
char* RCSwitch::getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus) {
static char sReturn[13];
int nReturnPos = 0;
for (int i = 0; i < 5; i++) {
sReturn[nReturnPos++] = (sGroup[i] == '0') ? 'F' : '0';
}
for (int i = 0; i < 5; i++) {
sReturn[nReturnPos++] = (sDevice[i] == '0') ? 'F' : '0';
}
sReturn[nReturnPos++] = bStatus ? '0' : 'F';
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* Encoding for type B switches with two rotary/sliding switches.
*
* The code word is a tristate word and with following bit pattern:
*
* +-----------------------------+-----------------------------+----------+------------+
* | 4 bits address | 4 bits address | 3 bits | 1 bit |
* | switch group | switch number | not used | on / off |
* | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | FFF | on=F off=0 |
* +-----------------------------+-----------------------------+----------+------------+
*
* @param nAddressCode Number of the switch group (1..4)
* @param nChannelCode Number of the switch itself (1..4)
* @param bStatus Whether to switch on (true) or off (false)
*
* @return char[13], representing a tristate code word of length 12
*/
char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) {
static char sReturn[13];
int nReturnPos = 0;
if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) {
return 0;
}
for (int i = 1; i <= 4; i++) {
sReturn[nReturnPos++] = (nAddressCode == i) ? '0' : 'F';
}
for (int i = 1; i <= 4; i++) {
sReturn[nReturnPos++] = (nChannelCode == i) ? '0' : 'F';
}
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* Like getCodeWord (Type C = Intertechno)
*/
char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) {
static char sReturn[13];
int nReturnPos = 0;
int nFamily = (int)sFamily - 'a';
if ( nFamily < 0 || nFamily > 15 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) {
return 0;
}
// encode the family into four bits
sReturn[nReturnPos++] = (nFamily & 1) ? 'F' : '0';
sReturn[nReturnPos++] = (nFamily & 2) ? 'F' : '0';
sReturn[nReturnPos++] = (nFamily & 4) ? 'F' : '0';
sReturn[nReturnPos++] = (nFamily & 8) ? 'F' : '0';
// encode the device and group
sReturn[nReturnPos++] = ((nDevice-1) & 1) ? 'F' : '0';
sReturn[nReturnPos++] = ((nDevice-1) & 2) ? 'F' : '0';
sReturn[nReturnPos++] = ((nGroup-1) & 1) ? 'F' : '0';
sReturn[nReturnPos++] = ((nGroup-1) & 2) ? 'F' : '0';
// encode the status code
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = 'F';
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* Encoding for the REV Switch Type
*
* The code word is a tristate word and with following bit pattern:
*
* +-----------------------------+-------------------+----------+--------------+
* | 4 bits address | 3 bits address | 3 bits | 2 bits |
* | switch group | device number | not used | on / off |
* | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FF 2=F0F 3=FF0 | 000 | on=10 off=01 |
* +-----------------------------+-------------------+----------+--------------+
*
* Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/
*
* @param sGroup Name of the switch group (A..D, resp. a..d)
* @param nDevice Number of the switch itself (1..3)
* @param bStatus Whether to switch on (true) or off (false)
*
* @return char[13], representing a tristate code word of length 12
*/
char* RCSwitch::getCodeWordD(char sGroup, int nDevice, bool bStatus) {
static char sReturn[13];
int nReturnPos = 0;
// sGroup must be one of the letters in "abcdABCD"
int nGroup = (sGroup >= 'a') ? (int)sGroup - 'a' : (int)sGroup - 'A';
if ( nGroup < 0 || nGroup > 3 || nDevice < 1 || nDevice > 3) {
return 0;
}
for (int i = 0; i < 4; i++) {
sReturn[nReturnPos++] = (nGroup == i) ? '1' : 'F';
}
for (int i = 1; i <= 3; i++) {
sReturn[nReturnPos++] = (nDevice == i) ? '1' : 'F';
}
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = '0';
sReturn[nReturnPos++] = bStatus ? '1' : '0';
sReturn[nReturnPos++] = bStatus ? '0' : '1';
sReturn[nReturnPos] = '\0';
return sReturn;
}
/**
* @param sCodeWord a tristate code word consisting of the letter 0, 1, F
*/
void RCSwitch::sendTriState(const char* sCodeWord) {
// turn the tristate code word into the corresponding bit pattern, then send it
unsigned long code = 0;
unsigned int length = 0;
for (const char* p = sCodeWord; *p; p++) {
code <<= 2L;
switch (*p) {
case '0':
// bit pattern 00
break;
case 'F':
// bit pattern 01
code |= 1L;
break;
case '1':
// bit pattern 11
code |= 3L;
break;
}
length += 2;
}
this->send(code, length);
}
/**
* @param sCodeWord a binary code word consisting of the letter 0, 1
*/
void RCSwitch::send(const char* sCodeWord) {
// turn the tristate code word into the corresponding bit pattern, then send it
unsigned long code = 0;
unsigned int length = 0;
for (const char* p = sCodeWord; *p; p++) {
code <<= 1L;
if (*p != '0')
code |= 1L;
length++;
}
this->send(code, length);
}
/**
* Transmit the first 'length' bits of the integer 'code'. The
* bits are sent from MSB to LSB, i.e., first the bit at position length-1,
* then the bit at position length-2, and so on, till finally the bit at position 0.
*/
void RCSwitch::send(unsigned long code, unsigned int length) {
if (this->nTransmitterPin == -1)
return;
#if not defined( RCSwitchDisableReceiving )
// make sure the receiver is disabled while we transmit
int nReceiverInterrupt_backup = nReceiverInterrupt;
if (nReceiverInterrupt_backup != -1) {
this->disableReceive();
}
#endif
for (int nRepeat = 0; nRepeat < nRepeatTransmit; nRepeat++) {
for (int i = length-1; i >= 0; i--) {
if (code & (1L << i))
this->transmit(protocol.one);
else
this->transmit(protocol.zero);
}
this->transmit(protocol.syncFactor);
}
// Disable transmit after sending (i.e., for inverted protocols)
// digitalWrite(this->nTransmitterPin, LOW);
gpio_put(this->nTransmitterPin, LOW);
#if not defined( RCSwitchDisableReceiving )
// enable receiver again if we just disabled it
if (nReceiverInterrupt_backup != -1) {
this->enableReceive(nReceiverInterrupt_backup);
}
#endif
}
/**
* Transmit a single high-low pulse.
*/
void RCSwitch::transmit(HighLow pulses) {
uint8_t firstLogicLevel = (this->protocol.invertedSignal) ? LOW : HIGH;
uint8_t secondLogicLevel = (this->protocol.invertedSignal) ? HIGH : LOW;
// digitalWrite(this->nTransmitterPin, firstLogicLevel);
// delayMicroseconds( this->protocol.pulseLength * pulses.high);
// digitalWrite(this->nTransmitterPin, secondLogicLevel);
// delayMicroseconds( this->protocol.pulseLength * pulses.low);
gpio_put(this->nTransmitterPin, firstLogicLevel);
sleep_us(this->protocol.pulseLength * pulses.high);
gpio_put(this->nTransmitterPin, secondLogicLevel);
sleep_us(this->protocol.pulseLength * pulses.low);
}
#if not defined( RCSwitchDisableReceiving )
/**
* Enable receiving data
*/
void RCSwitch::enableReceive(int interrupt) {
this->nReceiverInterrupt = interrupt;
this->enableReceive();
}
void RCSwitch::enableReceive() {
if (this->nReceiverInterrupt != -1) {
RCSwitch::nReceivedValue = 0;
RCSwitch::nReceivedBitlength = 0;
gpio_set_irq_enabled_with_callback(this->nReceiverInterrupt, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
// attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE);
}
}
/**
* Disable receiving data
*/
void RCSwitch::disableReceive() {
#if not defined(RaspberryPi) // Arduino
// detachInterrupt(this->nReceiverInterrupt);
#endif // For Raspberry Pi (wiringPi) you can't unregister the ISR
this->nReceiverInterrupt = -1;
}
bool RCSwitch::available() {
return RCSwitch::nReceivedValue != 0;
}
void RCSwitch::resetAvailable() {
RCSwitch::nReceivedValue = 0;
}
unsigned long RCSwitch::getReceivedValue() {
return RCSwitch::nReceivedValue;
}
unsigned int RCSwitch::getReceivedBitlength() {
return RCSwitch::nReceivedBitlength;
}
unsigned int RCSwitch::getReceivedDelay() {
return RCSwitch::nReceivedDelay;
}
unsigned int RCSwitch::getReceivedProtocol() {
return RCSwitch::nReceivedProtocol;
}
unsigned int* RCSwitch::getReceivedRawdata() {
return RCSwitch::timings;
}
/* helper function for the receiveProtocol method */
static inline unsigned int diff(int A, int B) {
return abs(A - B);
}
/**
*
*/
bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCount) {
#if defined(ESP8266) || defined(ESP32)
const Protocol &pro = proto[p-1];
#else
Protocol pro;
memcpy_P(&pro, &proto[p-1], sizeof(Protocol));
#endif
unsigned long code = 0;
//Assuming the longer pulse length is the pulse captured in timings[0]
const unsigned int syncLengthInPulses = ((pro.syncFactor.low) > (pro.syncFactor.high)) ? (pro.syncFactor.low) : (pro.syncFactor.high);
const unsigned int delay = RCSwitch::timings[0] / syncLengthInPulses;
const unsigned int delayTolerance = delay * RCSwitch::nReceiveTolerance / 100;
/* For protocols that start low, the sync period looks like
* _________
* _____________| |XXXXXXXXXXXX|
*
* |--1st dur--|-2nd dur-|-Start data-|
*
* The 3rd saved duration starts the data.
*
* For protocols that start high, the sync period looks like
*
* ______________
* | |____________|XXXXXXXXXXXXX|
*
* |-filtered out-|--1st dur--|--Start data--|
*
* The 2nd saved duration starts the data
*/
const unsigned int firstDataTiming = (pro.invertedSignal) ? (2) : (1);
for (unsigned int i = firstDataTiming; i < changeCount - 1; i += 2) {
code <<= 1;
if (diff(RCSwitch::timings[i], delay * pro.zero.high) < delayTolerance &&
diff(RCSwitch::timings[i + 1], delay * pro.zero.low) < delayTolerance) {
// zero
} else if (diff(RCSwitch::timings[i], delay * pro.one.high) < delayTolerance &&
diff(RCSwitch::timings[i + 1], delay * pro.one.low) < delayTolerance) {
// one
code |= 1;
} else {
// Failed
return false;
}
}
if (changeCount > 7) { // ignore very short transmissions: no device sends them, so this must be noise
RCSwitch::nReceivedValue = code;
RCSwitch::nReceivedBitlength = (changeCount - 1) / 2;
RCSwitch::nReceivedDelay = delay;
RCSwitch::nReceivedProtocol = p;
return true;
}
return false;
}
void RECEIVE_ATTR RCSwitch::handleInterrupt() {
static unsigned int changeCount = 0;
static unsigned long lastTime = 0;
static unsigned int repeatCount = 0;
// const long time = micros();
const long time = to_us_since_boot(get_absolute_time());
const unsigned int duration = time - lastTime;
if (duration > RCSwitch::nSeparationLimit) {
// A long stretch without signal level change occurred. This could
// be the gap between two transmission.
if ((repeatCount==0) || (diff(duration, RCSwitch::timings[0]) < 200)) {
// This long signal is close in length to the long signal which
// started the previously recorded timings; this suggests that
// it may indeed by a a gap between two transmissions (we assume
// here that a sender will send the signal multiple times,
// with roughly the same gap between them).
repeatCount++;
if (repeatCount == 2) {
for(unsigned int i = 1; i <= numProto; i++) {
if (receiveProtocol(i, changeCount)) {
// receive succeeded for protocol i
break;
}
}
repeatCount = 0;
}
}
changeCount = 0;
}
// detect overflow
if (changeCount >= RCSWITCH_MAX_CHANGES) {
changeCount = 0;
repeatCount = 0;
}
RCSwitch::timings[changeCount++] = duration;
lastTime = time;
}
#endif

View File

@ -0,0 +1,170 @@
/*
RCSwitch - Arduino libary for remote control outlet switches
Copyright (c) 2011 Suat Özgür. All right reserved.
Contributors:
- Andre Koehler / info(at)tomate-online(dot)de
- Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
- Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
- Dominik Fischer / dom_fischer(at)web(dot)de
- Frank Oltmanns / <first name>.<last name>(at)gmail(dot)com
- Max Horn / max(at)quendi(dot)de
- Robert ter Vehn / <first name>.<last name>(at)gmail(dot)com
Project home: https://github.com/sui77/rc-switch/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _RCSwitch_h
#define _RCSwitch_h
// #define RaspberryPi
// Include libraries for RPi:
#include <string.h> /* memcpy */
#include <stdlib.h> /* abs */
#include <stdint.h>
// Number of maximum high/Low changes per packet.
// We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync
#define RCSWITCH_MAX_CHANGES 67
class RCSwitch {
public:
RCSwitch();
void switchOn(int nGroupNumber, int nSwitchNumber);
void switchOff(int nGroupNumber, int nSwitchNumber);
void switchOn(const char* sGroup, int nSwitchNumber);
void switchOff(const char* sGroup, int nSwitchNumber);
void switchOn(char sFamily, int nGroup, int nDevice);
void switchOff(char sFamily, int nGroup, int nDevice);
void switchOn(const char* sGroup, const char* sDevice);
void switchOff(const char* sGroup, const char* sDevice);
void switchOn(char sGroup, int nDevice);
void switchOff(char sGroup, int nDevice);
void sendTriState(const char* sCodeWord);
void send(unsigned long code, unsigned int length);
void send(const char* sCodeWord);
#if not defined( RCSwitchDisableReceiving )
void enableReceive(int interrupt);
void enableReceive();
void disableReceive();
bool available();
void resetAvailable();
unsigned long getReceivedValue();
unsigned int getReceivedBitlength();
unsigned int getReceivedDelay();
unsigned int getReceivedProtocol();
unsigned int* getReceivedRawdata();
#endif
void enableTransmit(int nTransmitterPin);
void disableTransmit();
void setPulseLength(int nPulseLength);
void setRepeatTransmit(int nRepeatTransmit);
#if not defined( RCSwitchDisableReceiving )
void setReceiveTolerance(int nPercent);
#endif
/**
* Description of a single pule, which consists of a high signal
* whose duration is "high" times the base pulse length, followed
* by a low signal lasting "low" times the base pulse length.
* Thus, the pulse overall lasts (high+low)*pulseLength
*/
struct HighLow {
uint8_t high;
uint8_t low;
};
/**
* A "protocol" describes how zero and one bits are encoded into high/low
* pulses.
*/
struct Protocol {
/** base pulse length in microseconds, e.g. 350 */
uint16_t pulseLength;
HighLow syncFactor;
HighLow zero;
HighLow one;
/**
* If true, interchange high and low logic levels in all transmissions.
*
* By default, RCSwitch assumes that any signals it sends or receives
* can be broken down into pulses which start with a high signal level,
* followed by a a low signal level. This is e.g. the case for the
* popular PT 2260 encoder chip, and thus many switches out there.
*
* But some devices do it the other way around, and start with a low
* signal level, followed by a high signal level, e.g. the HT6P20B. To
* accommodate this, one can set invertedSignal to true, which causes
* RCSwitch to change how it interprets any HighLow struct FOO: It will
* then assume transmissions start with a low signal lasting
* FOO.high*pulseLength microseconds, followed by a high signal lasting
* FOO.low*pulseLength microseconds.
*/
bool invertedSignal;
};
void setProtocol(Protocol protocol);
void setProtocol(int nProtocol);
void setProtocol(int nProtocol, int nPulseLength);
private:
static void gpio_callback(unsigned int gpio, uint32_t events);
char* getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus);
char* getCodeWordB(int nGroupNumber, int nSwitchNumber, bool bStatus);
char* getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus);
char* getCodeWordD(char group, int nDevice, bool bStatus);
void transmit(HighLow pulses);
#if not defined( RCSwitchDisableReceiving )
static void handleInterrupt();
static bool receiveProtocol(const int p, unsigned int changeCount);
int nReceiverInterrupt;
#endif
int nTransmitterPin;
int nRepeatTransmit;
Protocol protocol;
#if not defined( RCSwitchDisableReceiving )
static int nReceiveTolerance;
volatile static unsigned long nReceivedValue;
volatile static unsigned int nReceivedBitlength;
volatile static unsigned int nReceivedDelay;
volatile static unsigned int nReceivedProtocol;
const static unsigned int nSeparationLimit;
/*
* timings[0] contains sync timing, followed by a number of bits
*/
static unsigned int timings[RCSWITCH_MAX_CHANGES];
#endif
};
#endif

View File

@ -0,0 +1,23 @@
# RcSwitch
A port of the brilliant [RC-Switch](https://github.com/sui77/rc-switch) library to the raspberry pi pico.
It allows you to send and recieve radio signals from 433/315Mhz devices like radio controlled power sockets, using cheap radio modules.
This works for both recieving and transmitting. Check out the examples for code for both of these.
## Building
This library can be developed on any platform that the pico-sdk works on, through cmake.
In the root directory, make sure that the pico-sdk is on your path and run
```bash
cmake .
```
then change directory into `examples/recieve`, then run
```bash
make
```
which will spit out your uf2 file.
## Issues
If you experience an error while using this library, please raise an issue here on Github and I'll try to help out. Pull requests are also very welcome!

Binary file not shown.