/* Kommunikationsroutinen für RFM12, für kurze Pakete (max. 17 Nutzbytes)
* Basierend auf <benedikt> einfaches RX/TX
* tabsize = 8, encoding = utf-8?, lineends = LF
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "rf12.h"
#include <util/crc16.h>
#include "rf12if.h"
/* Empirisches Kanalraster (12 Kanäle im Abstand 145 kHz, ∆F = 58)
theoretisch ausreichend für ± 60 kHz Hub und 25 kBit/s Datenrate
oder (naja) ± 45 kHz Hub und 40 kBit/s Datenrate.
Die überfüllte Bandmittenfrequenz (433,92 MHz) wird nicht benutzt
Kanal F Anfang Ende Mitte
1 1237 433,05 433,195 433,1225
2 1295 433,195 433,34 433,2675 // für 3-fache Bandbreite
3 1353 433,34 433,485 433,4125
4 1411 433,485 433,63 433,5575
5 1469 433,63 433,775 433,7025 // für 3-fache Bandbreite
6 1527 433,775 433,92 433,8475
7 1585 433,92 434,065 433,9925
8 1643 434,065 434,21 434,1375 // für 3-fache Bandbreite
9 1701 434,21 434,355 434,2825
10 1759 434,355 434,50 434,4275
11 1817 434,50 434,645 434,5725 // für 3-fache Bandbreite
12 1991 434,645 434,79 434,7175
SPI __ (CPOL=CPHA=0) ___
!SS \__________________________ __________/
___ ___ ___ ___
SCK _______/ \___/ \___/ \_ __/ \_______
___ _______ _______ _______ _ ______________
MOSI___X_______X_______X_______X_ ______________
____ _______ _______ _______ ______________
MISO____X__↑____X__↑____X__↑____X __↑___________
*/
#define USEHAM
#ifdef USEHAM
prog_uint8_t hamminge[16]={ // Kodierung
0x15,0x02,0x49,0x5E,0x64,0x73,0x38,0x2F,0xD0,0xC7,0x8C,0x9B,0xA1,0xB6,0xFD,0xEA};
prog_uint8_t hammingdn[128]={ // Dekodierung
0x01,0x11,0x00,0x11,0x22,0x31,0x2A,0x73,0x00,0x11,0x00,0x01,0x26,0xB3,0x02,0x33,
0xC4,0x51,0x44,0x75,0x66,0x77,0x76,0x77,0x46,0x55,0x04,0x5D,0x66,0x76,0x66,0x77,
0x20,0x11,0x04,0x91,0x22,0x23,0x22,0x33,0x08,0x51,0x00,0x13,0x22,0x33,0x23,0x33,
0x44,0x55,0x44,0x54,0x26,0x7F,0x64,0x77,0x54,0x55,0x44,0x55,0x66,0x57,0xE6,0x73,
0xC8,0x91,0x8A,0x99,0xAA,0xBB,0xAA,0xBA,0x88,0xB9,0x08,0x9D,0xBA,0xBB,0xAA,0xBB,
0xCC,0xCD,0xCC,0xDD,0xCE,0xFF,0xEA,0x7F,0xCC,0xDD,0xCD,0xDD,0xE6,0xBF,0xEE,0xFD,
0x88,0x99,0x98,0x99,0x2A,0xBF,0xAA,0x9B,0x88,0x98,0x88,0x99,0xA8,0xBB,0xEA,0xB3,
0xCC,0xDF,0xC4,0x9D,0xEF,0xFF,0xEE,0xFF,0xC8,0x5D,0xEC,0xDD,0xEE,0xFF,0xEE,0xEF};
#endif
prog_uint16_t rf_inittab[]={
0x80D7, // (1) FIFO benutzen, 433-MHz-Band, 12 pF Ballastkapazität
0xC2AC, // (6) Datenfilter: Auto-Lock setzen
0xCA81, // (7) FIFO-Modus: Empfänger-FIFO rücksetzen, kein sensitives Reset
0x94C1, // (5) VDI-Ausgang, Bandbreite 67 kHz, maximale Empfindlichkeit, RSSI = -97 dB
0x9820, // (10) Hub ∆f = ± 45 kHz, Ausgangsleistung = 0 dB (maximal)
0xC62A, // (4) Datenrate ≈ 8 kbit/s (η = 11,25)
0xE000, // (12) kein WakeUpTimer (ist sowieso aus!)
0xC800, // (13) kein LowDutyCycle (ist sowieso aus!)
0xC4F7, // (9) AFC
// 0xA000+1237, // (3) Mittenfrequenz (Kanal 1)
};
BYTE rf12_channel=WIRELESS_ID;
void rf12_setfreq() {
rf12_xfer(0xA000+1237+58*(rf12_channel-1));
}
void rf12_init() {
int i;
for (i=0; i<elemof(rf_inittab); i++) {
rf12_xfer(pgm_read_word(rf_inittab+i));
}
rf12_setfreq();
}
void rf12_startrx() {
rf12_xfer(0xCA81); // set FIFO mode
rf12_xfer(0xCA83); // enable FIFO: sync word search
}
static void rf12_ready() {
#ifdef PERBYTE_HOOK
PERBYTE_HOOK;
#endif
while (!(rf12_data()));
}
static void txbyte(BYTE b) {
rf12_ready();
rf12_xfer(0xB800|b);
}
static BYTE rxbyte() {
rf12_ready();
return rf12_xfer(0xB000)&0xFF;
}
static BYTE crc;
static void crc_update(BYTE b) {
crc=_crc_ibutton_update(crc,b);
}
static void txhambyte(BYTE b) {
crc_update(b);
#ifdef USEHAM
txbyte(pgm_read_byte(&hamminge[b>>4]));
txbyte(pgm_read_byte(&hamminge[b&0x0F]));
#else
txbyte(b);
#endif
}
#ifdef USEHAM
// Nibble-Adressierung
static BYTE hammingd(BYTE b) {
BYTE ret=pgm_read_byte(&hammingdn[b>>1]);
if (b&1) ret>>=4;
return ret&0x0F;
}
#endif
static BYTE rxhambyte() {
BYTE b;
#ifdef USEHAM
b =hammingd(rxbyte())<<4;
b|=hammingd(rxbyte());
#else
b=rxbyte();
#endif
crc_update(b);
return b;
}
rf12dat rf12buf __attribute__((section(".noinit")));
// ungeniert sofort lossenden, eingebaute ACK-Auswertung
// Voraussetzung: Quarz muss laufen
// Hinterlässt RFM12 im Empfangsmodus mit "scharfer" Mustererkennung
void rf12_txdata(const BYTE *txdata) {
rf12_xfer(0xB8AA); // TX-Puffer füllen
rf12_xfer(0xB8AA);
rf12_txmode(); // umschalten Sendebetrieb
txbyte(0xAA); // wartet 2 Bytezeiten - mit nur 2x AA schlechter Empfang!
txbyte(0x2D);
txbyte(0xD4); // wartet 1 Bytezeit
crc=0;
BYTE len=(*txdata&0x0F)+2;
do{
txhambyte(*txdata++);
}while(--len);
txhambyte(crc);
txbyte(0xAA); // Dummy (nur zum Ausschieben der CRC)
rf12_ready();
rf12_rxmode(); // auf RX umschalten
}
// Empfang; TimeOut muss vorher gesetzt sein! RFM12 auf Empfang gesetzt
// Erwartet und hinterlässt Empfänger mit "scharfer" Mustererkennung,
// auch bei Fehler (falsche CRC-Bits)
BYTE rf12_rxdata(BYTE *rxdata) {
crc=0;
BYTE b=rxhambyte();
BYTE len=(b&0x0F)+2; // Compiler ist doof! Übersetzt hier Grütze!
BYTE s;
do{
*rxdata++=b;
s=crc; // für nachher CRC retten (rxhambyte verändert crc)
b=rxhambyte(); // in der letzten Runde gesendete CRC lesen
}while (--len);
rf12_startrx();
return b^s; // CRC-Fehlerbits liefern (also 0 wenn OK)
}
BYTE rf12_poll() {
if (rf12_data()) { // Status abfragen
return !rf12_rxdata(rf12buf.all); // empfangen
}
return 0;
}
Vorgefundene Kodierung: UTF-8 | 0
|