Source file: /~heha/mb-iwp/Kleinkram/Sandkasten.zip/rf12/rf12.cpp

/* 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>
#define RF12_CPP
#include "rf12.h"

#include <util/crc16.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)                        ___
!SEL  \__________________________   __________/   \____
            ___     ___     ___        ___
SCK _______/   \___/   \___/   \_   __/   \____________
      _________ _______ _______ _                     _
SDO --_________X_______X_______X_   __________-----__/ IRQ
    ____ _______ _______ _______    ___________________
SDI ____X__↑____X__↑____X__↑____X   __↑________________
*/

#define USEHAM

#ifdef USEHAM
PROGMEM const byte hamminge[16]={	// Kodierung
  0x15,0x02,0x49,0x5E,0x64,0x73,0x38,0x2F,0xD0,0xC7,0x8C,0x9B,0xA1,0xB6,0xFD,0xEA};
PROGMEM const byte 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

PROGMEM const word 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)
};

namespace rf12{

byte channel=WIRELESS_ID;

void setfreq() {
  xfer(0xA000+1237+58*(channel-1));
}

void init() {
  for (size_t i=0; i<elemof(inittab); i++) {
    xfer(pgm_read_word(inittab+i));
  }
  setfreq();
}

void startrx() {
  xfer(0xCA81);		// set FIFO mode
  xfer(0xCA83);		// enable FIFO: sync word search
}

static void ready() {
#ifdef PERBYTE_HOOK
  PERBYTE_HOOK;
#endif
  while (!(data()));
}

static void txbyte(byte b) {
  ready();
  xfer(0xB800|b);
}

static byte rxbyte() {
  ready();
  return 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;
}

packet_t buf NOINIT;

// ungeniert sofort lossenden, eingebaute ACK-Auswertung
// Voraussetzung: Quarz muss laufen
// Hinterlässt RFM12 im Empfangsmodus mit "scharfer" Mustererkennung
void txdata(const byte *txdata) {
  xfer(0xB8AA);	// TX-Puffer füllen
  xfer(0xB8AA);
  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)
  ready();
  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 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);
  startrx();
  return b^s;		// CRC-Fehlerbits liefern (also 0 wenn OK)
}

byte poll() {
  if (data()) {		// Status abfragen
    return !rxdata(buf);	// empfangen
  }
  return 0;
}

}//namespace rf12
Detected encoding: UTF-80