NETMF_Autopilot/Hardware/RFM22b.cs

663 lines
22 KiB
C#
Raw Normal View History

2018-12-05 09:50:00 +00:00
//Nach dem c-Code von Ulrich Radig (http://www.ulrichradig.de)
using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using System.Threading;
namespace PlaneOnBoardSoftware
{
class RFM22b
{
public class CycleByteBuffer
{
private byte[] byteBuffer;
private int rInd = 0;
private int wInd = 0;
private bool isFull = false;
public CycleByteBuffer(int BufferSize)
{
byteBuffer = new Byte[BufferSize];
}
public int GetBytesToRead()
{
if (isFull && wInd == rInd)
return byteBuffer.Length;
else
return (byteBuffer.Length + wInd - rInd) % byteBuffer.Length;
}
public int GetFreeByteCount()
{
if (!isFull && wInd == rInd)
return byteBuffer.Length;
else
return (byteBuffer.Length + rInd - wInd) % byteBuffer.Length;
}
public int WriteBytes(byte[] Data, int OffSet, int Lenght)
{
int len = Lenght;
int freeLen = GetFreeByteCount();
if (len >= freeLen)
{
len = freeLen;
isFull = true;
}
addToBuffer(Data, OffSet, byteBuffer, wInd, len);
wInd = (wInd + len) % byteBuffer.Length;
return len;
}
public int ReadBytes(byte[] Data, int OffSet, int Lenght)
{
return ReadBytes(Data, OffSet, Lenght, false);
}
public int ReadBytes(byte[] Data, int OffSet, int Lenght, bool KeepInBuffer)
{
int len = Lenght;
int bytesLen = GetBytesToRead();
if (len >= bytesLen)
{
len = bytesLen;
if (!KeepInBuffer) isFull = false;
}
getFromBuffer(byteBuffer, rInd, Data, OffSet, len);
if (!KeepInBuffer) rInd = (rInd + len) % byteBuffer.Length;
return len;
}
public int GetNextLineBr()
{
int rPos = rInd;
int lastrPos;
int count = GetBytesToRead();
for (int i = 0; i < count - 1; i++)
{
lastrPos = rPos;
rPos++;
if (rPos == byteBuffer.Length) rPos = 0;
if (byteBuffer[lastrPos] == 13 && byteBuffer[rPos] == 10) return i;
}
return 0;
}
public int DropBytes(int ByteCount)
{
int bytesToRemove = GetBytesToRead();
if (ByteCount < bytesToRemove)
bytesToRemove = ByteCount;
else
isFull = false;
rInd = (rInd + bytesToRemove) % byteBuffer.Length;
return bytesToRemove;
}
public void ClearBuffer()
{
wInd = 0;
rInd = 0;
isFull = false;
}
private void addToBuffer(byte[] Data, int srcOffSet, byte[] Buffer, int destOffSet, int Lenght)
{
if (destOffSet + Lenght > Buffer.Length)
{
int pLen = Buffer.Length - destOffSet;
Array.Copy(Data, srcOffSet, Buffer, destOffSet, pLen);
Array.Copy(Data, srcOffSet + pLen, Buffer, 0, Lenght - pLen);
}
else
{
Array.Copy(Data, srcOffSet, Buffer, destOffSet, Lenght);
}
}
private void getFromBuffer(byte[] Buffer, int srcOffSet, byte[] Data, int destOffSet, int Lenght)
{
if (srcOffSet + Lenght > Buffer.Length)
{
int pLen = Buffer.Length - srcOffSet;
Array.Copy(Buffer, srcOffSet, Data, destOffSet, pLen);
Array.Copy(Buffer, 0, Data, destOffSet + pLen, Lenght - pLen);
}
else
{
Array.Copy(Buffer, srcOffSet, Data, destOffSet, Lenght);
}
}
}
public class Channel
{
public byte chanID;
public RFM22b rfMod;
private CycleByteBuffer TxBuffer;
private CycleByteBuffer RxBuffer;
public byte Priority = 0;
public int BytesToRead
{
get { return RxBuffer.GetBytesToRead(); }
}
public int BytesToSend
{
get { return TxBuffer.GetBytesToRead(); }
}
public Channel(RFM22b RFModul, byte ChannelID, int RxBufferSize, int TxBufferSize)
{
TxBuffer = new CycleByteBuffer(TxBufferSize);
RxBuffer = new CycleByteBuffer(RxBufferSize);
chanID = ChannelID;
rfMod = RFModul;
rfMod.addChannel(this, chanID);
}
public int Send(byte[] Data, int OffSet, int Lenght)
{
int retVal = TxBuffer.WriteBytes(Data, OffSet, Lenght);
rfMod.sendNextPacket();
return retVal;
}
public int Send(string Text)
{
byte[] txtData = System.Text.UTF8Encoding.UTF8.GetBytes(Text);
int retVal = TxBuffer.WriteBytes(txtData, 0, txtData.Length);
rfMod.sendNextPacket();
return retVal;
}
public int SendLine(string Text)
{
return Send(Text + "\r\n");
}
public int Recv(byte[] Data, int OffSet, int Lenght)
{
return RxBuffer.ReadBytes(Data, OffSet, Lenght, false);
}
public string RecvLine()
{
int byteCount = RxBuffer.GetNextLineBr();
byte[] Data = new byte[byteCount];
if (byteCount > 0)
{
RxBuffer.ReadBytes(Data, 0, byteCount);
RxBuffer.DropBytes(2);
return new string(System.Text.UTF8Encoding.UTF8.GetChars(Data));
}
else
{
return "";
}
}
public int AddBytesToRxBuffer(byte[] Data, int OffSet, int Lenght)
{
return RxBuffer.WriteBytes(Data, OffSet, Lenght);
}
public int GetBytesFromTxBuffer(byte[] Data, int OffSet, int Lenght)
{
return TxBuffer.ReadBytes(Data, OffSet, Lenght, true);
}
public void RemoveBytesFromTxBuffer(int ByteCount)
{
TxBuffer.DropBytes(ByteCount);
}
public void ClearTxBuffer()
{
TxBuffer.ClearBuffer();
rfMod.CancelPacketFlag = true;
}
public void ClearRxBuffer()
{
RxBuffer.ClearBuffer();
}
}
public enum ModemState
{
Init,
Ready,
Transmitting,
Receving,
Error
};
private enum PacketAttrib
{
Normal,
ClearRecvBuffer
};
SPI.Configuration SpiConfig;
SPI SpiBus;
InterruptPort IRQn;
Channel[] ChannelList = new Channel[8];
Timer TimeOutTimer;
public ModemState State = ModemState.Init;
public int RSSI;
public int LostPackets = 0;
private int rxPackNr = 0;
private int txPackNr = 0;
private Channel lastTxChan;
private int lastTxPackLen = 60;
private int lastRxPackLen = 0;
private bool CancelPacketFlag = false;
private byte InterruptStatus1 = 0;
private double _frequency = 869.545;
public double Frequency
{
get
{
return _frequency;
}
set
{
rf22_setfreq((byte)((value - 860.0) * 3200));
}
}
public RFM22b(SPI.SPI_module SpiMmodule, Cpu.Pin ChipSelectPort, Cpu.Pin IRQPort, double FrequInHz)
{
SpiConfig = new SPI.Configuration(ChipSelectPort, false, 0, 0, false, true, 1000, SpiMmodule);
SpiBus = new SPI(SpiConfig);
IRQn = new InterruptPort(IRQPort, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
IRQn.OnInterrupt += new NativeEventHandler(IRQn_OnInterrupt);
rf22_init();
rf22_setfreq((byte)((_frequency - 860.0) * 3200));
rf22_rxmode();
TimeOutTimer = new Timer(new TimerCallback(RecvTimeOut), null, 500, Timeout.Infinite);
State = ModemState.Receving;
}
public Channel NewChannel(byte ChannelID, int RxBufferSize, int TxBufferSize)
{
return new Channel(this, ChannelID, RxBufferSize, TxBufferSize);
}
private void addChannel(Channel chanToAdd, byte chanID)
{
ChannelList[chanID] = chanToAdd;
}
private void sendNextPacket()
{
int hcIndex = -1;
int prio = -1;
//Debug.Print("--> Send State" + State + " <--");
if (State == ModemState.Ready)
{
for (int i = 0; i < ChannelList.Length; i++)
{
if (ChannelList[i] != null)
{
if (ChannelList[i].BytesToSend > 0 && ChannelList[i].Priority > prio)
{
hcIndex = i;
prio = ChannelList[i].Priority;
}
}
}
int byteCount;
byte[] Buffer = new byte[64];
Buffer[0] = (byte)rxPackNr;
Buffer[1] = (byte)txPackNr;
Buffer[2] = (byte)hcIndex;
Buffer[3] = CancelPacketFlag ? (byte)PacketAttrib.ClearRecvBuffer : (byte)PacketAttrib.Normal;
//Debug.Print("--> Send hcIndex" + hcIndex + " <--");
if (hcIndex > -1)
{
byteCount = ChannelList[hcIndex].GetBytesFromTxBuffer(Buffer, 4, lastTxPackLen);
//Debug.Print("** Send " + byteCount + " **");
State = ModemState.Transmitting;
rf22_sendpacket(Buffer, 0, byteCount + 4);
lastTxChan = ChannelList[hcIndex];
lastTxPackLen = byteCount;
}
else if (lastRxPackLen > 4)
{
//Debug.Print("** Send Empty **");
lastRxPackLen = 0;
State = ModemState.Transmitting;
rf22_sendpacket(Buffer, 0, 4);
}
else
{
rf22_rxmode();
}
}
}
private void readPacket()
{
byte[] Buffer = new byte[64];
int cInd;
int packetLen;
int newRxPacketNr;
packetLen = rf22_getpacket(Buffer, 0);
lastRxPackLen = packetLen;
//Debug.Print("** Receve " + packetLen + " **");
if (packetLen > 3)
{
newRxPacketNr = Buffer[1];
cInd = Buffer[2]; //Channel ID
if (Buffer[0] == txPackNr && lastTxChan != null)
{
lastTxChan.RemoveBytesFromTxBuffer(lastTxPackLen);
lastTxPackLen = 60;
txPackNr++;
if (txPackNr > 255) txPackNr = 0;
}
if (cInd < ChannelList.Length)
{
if (ChannelList[cInd] != null && rxPackNr != newRxPacketNr && packetLen > 4)
{
if (Buffer[3] == (byte)PacketAttrib.ClearRecvBuffer) ChannelList[cInd].ClearRxBuffer();
ChannelList[cInd].AddBytesToRxBuffer(Buffer, 4, packetLen - 4);
rxPackNr = newRxPacketNr;
}
}
}
}
private void RecvTimeOut(object nullObj)
{
if (State == ModemState.Receving)
{
State = ModemState.Ready;
RSSI = -1;
if (LostPackets == int.MaxValue) LostPackets = 0;
LostPackets++;
sendNextPacket();
}
}
private void IRQn_OnInterrupt(uint port, uint state, DateTime time)
{
InterruptStatus1 = rf22_read(0x03);
if (State == ModemState.Transmitting)
{
// All Data Transmitted
rf22_write(0x07, 0x01); // switch to ready mode
rf22_rxmode();
TimeOutTimer.Dispose();
TimeOutTimer = new Timer(new TimerCallback(RecvTimeOut), null, 500, Timeout.Infinite);
State = ModemState.Receving;
}
else if (State == ModemState.Receving || State == ModemState.Ready)
{
RSSI = rf22_read(0x26);
State = ModemState.Ready;
readPacket();
sendNextPacket();
}
}
#region Hardware Commands
private void rf22_write(byte addr, byte data)
{
byte[] addrArray = new byte[2];
addrArray[0] = (byte)(128 | addr);
addrArray[1] = data;
SpiBus.Write(addrArray);
}
private byte rf22_read(byte addr)
{
byte[] ret = new byte[2];
SpiBus.WriteRead(new byte[] { (byte)(addr & 127), 0xFF }, ret);
return ret[1];
}
private void rf22_burstread(byte addr, byte[] data, int OffSet, int Lenght)
{
byte[] arg = new byte[Lenght + 1];
arg[0] = (byte)(addr & 127);
SpiBus.WriteRead(arg, 0, Lenght + 1, data, OffSet, Lenght, 1);
}
private void rf22_init()
{
Thread.Sleep(20);
rf22_write(0x07, 0x80); // software reset
Thread.Sleep(20);
rf22_write(0x05, 0x06); // valid packed received and packet send interrupt on
rf22_write(0x06, 0x00); // all interrupts off
rf22_write(0x07, 0x01); // operating mode: ready mode
rf22_write(0x09, 0x7f); // xtal load capacitance
rf22_write(0x0A, 0x02); // uC CLK: 10MHz
rf22_write(0x0b, 0xf2); // GPIO0: TX_ANT - f2
rf22_write(0x0c, 0xf5); // GPIO1: RX ANT - f5
rf22_write(0x0d, 0x00); // GPIO2: uC Clock out
rf22_write(0x0e, 0x00);
rf22_write(0x0f, 0x70); // ADC Input: GND
rf22_write(0x10, 0x00); // ADC offset: 0
rf22_write(0x12, 0x00); // temp sensor calibration off
rf22_write(0x13, 0x00); // temp sensor offset: 0
rf22_write(0x1d, 0x40); // enable AFC
rf22_write(0x1e, 0x0A); // afc timing
rf22_write(0x1f, 0x03); // afc timing
rf22_write(0x1C, 0x05); // IF bandwidth
rf22_write(0x20, 0x83); // Clock Recovery Oversampling Rate
rf22_write(0x21, 0xC0); // Clock Recovery Offset 2
rf22_write(0x22, 0x13); // Clock Recovery Offset 1
rf22_write(0x23, 0xA9); // Clock Recovery Offset 0
rf22_write(0x24, 0x00); // Clock Recovery Timing Loop Gain 1
rf22_write(0x25, 0x04); // Clock Recovery Timing Loop Gain 0
rf22_write(0x2A, 0x24);
rf22_write(0x27, 0x10); // RSSI Threashold: -120dB
rf22_write(0x30, 0x8c); // data access: RX/TX packet handling, enable crc: CCIT
rf22_write(0x32, 0xff); // header check enable
rf22_write(0x33, 0x42); // 2 word synchronisation
rf22_write(0x34, 0x10); // preamble length: 16 nibbles, = 64bits
rf22_write(0x35, 0x30); // preamble detection control: 6 nibbles = 24bits
rf22_write(0x36, 0x2d); // sync word 3
rf22_write(0x37, 0xd4); // sync word 2
rf22_write(0x38, 0xAA); // sync word 1
rf22_write(0x39, 0xAA); // sync word 0
rf22_write(0x3a, 101); // transmit header 3
rf22_write(0x3b, 108); // transmit header 2
rf22_write(0x3c, 103); // transmit header 1
rf22_write(0x3d, 106); // transmit header 0
rf22_write(0x3e, 17); // packet length
rf22_write(0x3f, 101); // check header 3
rf22_write(0x40, 108); // check header 2
rf22_write(0x41, 103); // check header 1
rf22_write(0x42, 106); // check header 0
rf22_write(0x43, 0xff); // header enable mask 3
rf22_write(0x44, 0xff); // header enable mask 2
rf22_write(0x45, 0xff); // header enable mask 1
rf22_write(0x46, 0xff); // header enable mask 0
rf22_write(0x69, 0x60); // AGC on
rf22_write(0x6a, 0x0b); // agc override 2
//rf22_write(0x6d, 0x08); // tx power: +1dBm
rf22_write(0x6d, 0x0F); // tx power: +17dBm (nicht 20dbm??)
//baud rate: 2,39 kBit/s = val("&H13A9")/2^(16+5)*1000 kHz
rf22_write(0x6E, 0x13); // set baud high
rf22_write(0x6F, 0xA9); // set baud low
rf22_write(0x70, 0x2C); // modulation control
rf22_write(0x71, 0x22); // modulation control 2: FIFO mode, OOK //0x21 / 0x00
rf22_write(0x72, 0x50); // frequency deviation: 45kHz
rf22_write(0x73, 0x00); // offset: 0
rf22_write(0x74, 0x00); // offset: 0
rf22_write(0x79, 0x0); // frequency hopping off
rf22_write(0x7a, 0x0); // frequency hopping off
rf22_write(0x75, 0x73); // 860-880MHz range
//rf22_write(0x75, 0x53); // 430-440MHz range
rf22_write(0x08, 0x00); // clear fifo, disable multi packet
}
public void rf22_rxmode()
{
rf22_read(0x03); // clear interrupt status
rf22_read(0x04); // clear interrupt status
rf22_write(0x07, 0x01); // to_ready_mode();
rf22_write(0x07, 0x01); // to_ready_mode();
rf22_write(0x7e, 0x40); // threshold for rx almost full, interrupt when 64 bytes received
rf22_write(0x08, 0x03); // clear RX fifo
rf22_write(0x08, 0x00); // clear RX fifo
rf22_write(0x07, 0x05); // RX on
rf22_read(0x03); // clear interrupt status
rf22_read(0x04); // clear interrupt status
}
private void rf22_setfreq(UInt16 freq)
{
rf22_write(0x76, (byte)((freq & 0xFF00) >> 8));
rf22_write(0x77, (byte)(freq & 0x00FF));
}
private void rf22_sendpacket(byte[] data, int offset, int lenght)
{
//Debug.Print("---> " + lenght);
byte i;
byte size = (byte)lenght;
if (size > 64) size = 64;
rf22_write(0x07, 0x03); // switch to ready mode
rf22_read(0x03); // clear interrupt status
rf22_read(0x04); // clear interrupt status
rf22_write(0x08, 0x01); // clear TX fifo
rf22_write(0x08, 0x00); // clear TX fifo
//rf22_write(0x34, 32); // premable length: 32 nibbles -> 128 Bits
rf22_write(0x3e, size); // packet length
for (i = 0; i < size; i++)
{
rf22_write(0x7f, data[i + offset]);
}
rf22_write(0x07, 0x09); // TX on
}
private int rf22_getpacket(byte[] data, int offset)
{
byte cnt;
//if ((rf22_read(0x31) & 0x1A) > 0) // receiving a packet
//{
if ((InterruptStatus1 & 2) > 0) // packet received & not read && ((rf22_read(0x02) & 32) == 0)
{
cnt = rf22_read(0x4B); // packet length
//Debug.Print(cnt + " " + data[cnt-2].ToString());
/*for (int i = 0; i < cnt; i++) // Daten (cnt - 2 f<>r CRC)
{
data[i + offset] = rf22_read(0x7f);
}*/
rf22_burstread(0x7f, data, offset, cnt);
/*try
{
byte[] Test = new byte[cnt - 4];
Array.Copy(data, 4, Test, 0, cnt - 4);
string tmpCa = (new string(System.Text.UTF8Encoding.UTF8.GetChars(Test)));
Debug.Print(tmpCa);
}
catch
{
Debug.Print("Error");
}*/
return (cnt);
}
return 0;
//}
//return 0;
}
#endregion
}
}