123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- MODULE SCC; (*NW 13.11.87 / 22.8.90 Ceres-2; nRF24L01+ version PR 21.7.13 / 23.12.13*)
- IMPORT SYSTEM, Kernel;
- CONST
- swi = -60; spiData = -48; spiCtrl = -44;
- netSelect = 1; spiFast = 2; netEnable = 3;
- HdrSize = 8; MaxPayload = 512; SubPacket = 32; Wait = 50; SendTries = 50;
- MaxPacket = (HdrSize + MaxPayload + SubPacket-1) DIV SubPacket *
- SubPacket;
- TYPE Header* =
- RECORD valid*: BOOLEAN;
- dadr*, sadr*, typ*: BYTE;
- len*: INTEGER (*of data following header*)
- END ;
- VAR
- filter*: BOOLEAN; Adr*: BYTE; rcvd: INTEGER;
- rx: RECORD
- hd: Header;
- dat: ARRAY MaxPacket-HdrSize OF BYTE
- END;
- PROCEDURE SPICtrl(s: SET);
- BEGIN SYSTEM.PUT(spiCtrl, s);
- IF netEnable IN s THEN LED(55H) ELSE LED(0) END
- END SPICtrl;
- PROCEDURE SPI(n: INTEGER);
- BEGIN (*send (& rcv into shift reg) one byte or word, at current speed*)
- SYSTEM.PUT(spiData, n); REPEAT UNTIL SYSTEM.BIT(spiCtrl, 0) (*wait until done*)
- END SPI;
- PROCEDURE StartCmd(cmd: INTEGER);
- BEGIN SPICtrl({netSelect}); SPI(cmd)
- END StartCmd;
- PROCEDURE WriteReg1(reg, dat: INTEGER); (*disables radio!*)
- BEGIN StartCmd(reg + 20H); SPI(dat); SPICtrl({}) (*W_REGISTER*)
- END WriteReg1;
- PROCEDURE SubRcv(dst: INTEGER);
- VAR i, dat: INTEGER;
- BEGIN
- StartCmd(061H); (*R_RX_PAYLOAD, disables radio*)
- SPICtrl({netSelect, spiFast});
- FOR i := 0 TO SubPacket-4 BY 4 DO
- SPI(-1); SYSTEM.GET(spiData, dat); SYSTEM.PUT(dst+i, dat)
- END;
- SPICtrl({}); WriteReg1(7, 40H); (*done; STATUS <= clear RX_DR*)
- SPICtrl({netEnable}) (*enable radio*)
- END SubRcv;
- PROCEDURE SubSnd(src: INTEGER; VAR timeout: BOOLEAN);
- VAR i, dat, res, t1, try: INTEGER; x, status: BYTE;
- BEGIN (*already in xmit mode*)
- StartCmd(0A0H); (*W_TX_PAYLOAD*)
- SPICtrl({netSelect, spiFast});
- FOR i := 0 TO SubPacket-4 BY 4 DO
- SYSTEM.GET(src+i, dat); SPI(dat)
- END;
- SPICtrl({}); (*end W_TX_PAYLOAD command*)
- try := 0;
- SPICtrl({netEnable, netSelect}); (*start xmit pulse, start NOP cmd*)
- REPEAT
- t1 := Kernel.Time() + Wait;
- REPEAT (*wait for sent or retransmits exceeded*);
- SPI(0FFH); SYSTEM.GET(spiData, status); (*NOP*)
- res := status DIV 10H MOD 4;
- SPICtrl({}); SPICtrl({netSelect}) (*end & restart NOP cmd, end =10us pulse on enable*)
- UNTIL res # 0;
- IF res = 2 THEN WriteReg1(7, 20H) (*TX_DS: sent, ack received; reset it*)
- ELSIF res = 1 THEN WriteReg1(7, 10H); INC(try); (*MAX_RT: retransmits exceeded; reset it*)
- IF try = SendTries THEN res := 0
- ELSE REPEAT UNTIL Kernel.Time() >= t1;
- SPICtrl({netEnable, netSelect}); (*start xmit pulse, start NOP cmd again*)
- END
- END
- UNTIL res # 1;
- timeout := (res # 2)
- END SubSnd;
- PROCEDURE Flush();
- BEGIN StartCmd(0E1H); SPICtrl({}); StartCmd(0E2H); SPICtrl({})
- (*FLUSH_TX, FLUSH_RX*)
- END Flush;
- PROCEDURE ResetRcv;
- BEGIN SYSTEM.PUT(SYSTEM.ADR(rx), 0); rx.hd.len := 0; rcvd := 0
- END ResetRcv;
- PROCEDURE Listen(b: BOOLEAN);
- BEGIN
- WriteReg1(0, 07EH + ORD(b)); (*CONFIG <= mask ints; EN_CRC(2 byte), PWR_UP, PRX/PTX*)
- WriteReg1(7, 70H); (*STATUS <= clear ints*)
- IF b THEN SPICtrl({netEnable}) END (*turn radio on*)
- END Listen;
- PROCEDURE Start*(filt: BOOLEAN);
- VAR n: INTEGER;
- BEGIN filter := filt; Adr := 0;
- SYSTEM.GET(swi, n); n := n DIV 4 MOD 10H * 10 + 5;
- WriteReg1(5, n); (*RF_CH <= channel: 5, 15, 25...*)
- WriteReg1(6, 07H); (*RF_SETUP <= 1Mb for better range, 0dBm*)
- WriteReg1(11H, SubPacket); (*RX_PW_P0 <= pipe 0 payload width*)
- Flush(); Listen(TRUE); ResetRcv
- END Start;
- PROCEDURE SendPacket*(VAR head: Header; dat: ARRAY OF BYTE);
- VAR len, i, off: INTEGER; timeout: BOOLEAN; payload: ARRAY SubPacket
- OF BYTE;
- BEGIN (*let any receive ack finish before turning radio off*)
- i := Kernel.Time() + Wait;
- REPEAT SPICtrl({netEnable, netSelect}); SPI(0FFH); SPICtrl({netEnable}) (*NOP*)
- UNTIL Kernel.Time() >= i;
- IF Adr = 0 THEN Adr := i MOD 100H END;
- Listen(FALSE);
- head.sadr := Adr; head.valid := TRUE;
- SYSTEM.COPY(SYSTEM.ADR(head), SYSTEM.ADR(payload), HdrSize DIV 4);
- i := HdrSize; off := 0; len := head.len;
- WHILE (len > 0) & (i < SubPacket) DO payload[i] := dat[off]; INC(i); INC(off); DEC(len) END;
- WHILE i < SubPacket DO payload[i] := 0; INC(i) END;
- SubSnd(SYSTEM.ADR(payload), timeout);
- WHILE ~timeout & (len # 0) DO i := 0; (*send the rest*)
- WHILE (len > 0) & (i < SubPacket) DO payload[i] := dat[off]; INC(i); INC(off); DEC(len) END;
- WHILE i < SubPacket DO payload[i] := 0; INC(i) END;
- SubSnd(SYSTEM.ADR(payload), timeout)
- END;
- Listen(TRUE)
- END SendPacket;
- PROCEDURE Available*(): INTEGER;
- BEGIN (*packet already rcvd*)
- RETURN rx.hd.len - rcvd
- END Available;
- PROCEDURE Receive*(VAR x: BYTE);
- BEGIN (*packet already rcvd*)
- IF rcvd < rx.hd.len THEN x := rx.dat[rcvd]; INC(rcvd) ELSE x := 0 END
- END Receive;
- PROCEDURE Rcvd(time: INTEGER): BOOLEAN;
- VAR status, fifoStatus: BYTE; rcvd: BOOLEAN;
- BEGIN time := time + Kernel.Time();
- REPEAT
- SPICtrl({netEnable, netSelect}); SPI(17H); (*R_REGISTER FIFO_STATUS*)
- SYSTEM.GET(spiData, status); SPI(-1); SYSTEM.GET(spiData, fifoStatus); SPICtrl({netEnable});
- rcvd := ODD(status DIV 40H) OR ~ODD(fifoStatus) (*RX_DR (data ready) or RX FIFO not empty*)
- UNTIL rcvd OR (Kernel.Time() >= time);
- RETURN rcvd
- END Rcvd;
- PROCEDURE ReceiveHead*(VAR head: Header); (*actually, recv whole packet*)
- VAR adr, n: INTEGER;
- BEGIN head.valid := FALSE;
- IF Rcvd(0) THEN
- ResetRcv; adr := SYSTEM.ADR(rx); SubRcv(adr);
- n := (rx.hd.len + HdrSize - 1) DIV SubPacket;
- IF (rx.hd.len <= MaxPayload)
- & ((rx.hd.dadr = 0FFH) OR ~filter OR (Adr = 0) OR (rx.hd.dadr = Adr)) THEN
- WHILE (n > 0) & Rcvd(Wait) DO
- INC(adr, SubPacket); SubRcv(adr); DEC(n)
- END;
- rx.hd.valid := (n = 0)
- ELSE WHILE Rcvd(Wait) DO SubRcv(adr) END; ResetRcv (*discard packet*)
- END;
- head := rx.hd
- END
- END ReceiveHead;
- PROCEDURE Skip*(m: INTEGER);
- VAR dmy: BYTE;
- BEGIN WHILE m # 0 DO Receive(dmy); DEC(m) END
- END Skip;
- PROCEDURE Stop*;
- BEGIN SPICtrl({}); Flush(); ResetRcv
- END Stop;
- BEGIN Start(TRUE)
- END SCC.
|