Quelltext /~heha/mb-iwp/FlyStick/Firmware.zip/rf12/rf12.c

/* 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-80