SCC.Mod.txt 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. MODULE SCC; (*NW 13.11.87 / 22.8.90 Ceres-2; nRF24L01+ version PR 21.7.13 / 23.12.13*)
  2. IMPORT SYSTEM, Kernel;
  3. CONST
  4. swi = -60; spiData = -48; spiCtrl = -44;
  5. netSelect = 1; spiFast = 2; netEnable = 3;
  6. HdrSize = 8; MaxPayload = 512; SubPacket = 32; Wait = 50; SendTries = 50;
  7. MaxPacket = (HdrSize + MaxPayload + SubPacket-1) DIV SubPacket *
  8. SubPacket;
  9. TYPE Header* =
  10. RECORD valid*: BOOLEAN;
  11. dadr*, sadr*, typ*: BYTE;
  12. len*: INTEGER (*of data following header*)
  13. END ;
  14. VAR
  15. filter*: BOOLEAN; Adr*: BYTE; rcvd: INTEGER;
  16. rx: RECORD
  17. hd: Header;
  18. dat: ARRAY MaxPacket-HdrSize OF BYTE
  19. END;
  20. PROCEDURE SPICtrl(s: SET);
  21. BEGIN SYSTEM.PUT(spiCtrl, s);
  22. IF netEnable IN s THEN LED(55H) ELSE LED(0) END
  23. END SPICtrl;
  24. PROCEDURE SPI(n: INTEGER);
  25. BEGIN (*send (& rcv into shift reg) one byte or word, at current speed*)
  26. SYSTEM.PUT(spiData, n); REPEAT UNTIL SYSTEM.BIT(spiCtrl, 0) (*wait until done*)
  27. END SPI;
  28. PROCEDURE StartCmd(cmd: INTEGER);
  29. BEGIN SPICtrl({netSelect}); SPI(cmd)
  30. END StartCmd;
  31. PROCEDURE WriteReg1(reg, dat: INTEGER); (*disables radio!*)
  32. BEGIN StartCmd(reg + 20H); SPI(dat); SPICtrl({}) (*W_REGISTER*)
  33. END WriteReg1;
  34. PROCEDURE SubRcv(dst: INTEGER);
  35. VAR i, dat: INTEGER;
  36. BEGIN
  37. StartCmd(061H); (*R_RX_PAYLOAD, disables radio*)
  38. SPICtrl({netSelect, spiFast});
  39. FOR i := 0 TO SubPacket-4 BY 4 DO
  40. SPI(-1); SYSTEM.GET(spiData, dat); SYSTEM.PUT(dst+i, dat)
  41. END;
  42. SPICtrl({}); WriteReg1(7, 40H); (*done; STATUS <= clear RX_DR*)
  43. SPICtrl({netEnable}) (*enable radio*)
  44. END SubRcv;
  45. PROCEDURE SubSnd(src: INTEGER; VAR timeout: BOOLEAN);
  46. VAR i, dat, res, t1, try: INTEGER; x, status: BYTE;
  47. BEGIN (*already in xmit mode*)
  48. StartCmd(0A0H); (*W_TX_PAYLOAD*)
  49. SPICtrl({netSelect, spiFast});
  50. FOR i := 0 TO SubPacket-4 BY 4 DO
  51. SYSTEM.GET(src+i, dat); SPI(dat)
  52. END;
  53. SPICtrl({}); (*end W_TX_PAYLOAD command*)
  54. try := 0;
  55. SPICtrl({netEnable, netSelect}); (*start xmit pulse, start NOP cmd*)
  56. REPEAT
  57. t1 := Kernel.Time() + Wait;
  58. REPEAT (*wait for sent or retransmits exceeded*);
  59. SPI(0FFH); SYSTEM.GET(spiData, status); (*NOP*)
  60. res := status DIV 10H MOD 4;
  61. SPICtrl({}); SPICtrl({netSelect}) (*end & restart NOP cmd, end =10us pulse on enable*)
  62. UNTIL res # 0;
  63. IF res = 2 THEN WriteReg1(7, 20H) (*TX_DS: sent, ack received; reset it*)
  64. ELSIF res = 1 THEN WriteReg1(7, 10H); INC(try); (*MAX_RT: retransmits exceeded; reset it*)
  65. IF try = SendTries THEN res := 0
  66. ELSE REPEAT UNTIL Kernel.Time() >= t1;
  67. SPICtrl({netEnable, netSelect}); (*start xmit pulse, start NOP cmd again*)
  68. END
  69. END
  70. UNTIL res # 1;
  71. timeout := (res # 2)
  72. END SubSnd;
  73. PROCEDURE Flush();
  74. BEGIN StartCmd(0E1H); SPICtrl({}); StartCmd(0E2H); SPICtrl({})
  75. (*FLUSH_TX, FLUSH_RX*)
  76. END Flush;
  77. PROCEDURE ResetRcv;
  78. BEGIN SYSTEM.PUT(SYSTEM.ADR(rx), 0); rx.hd.len := 0; rcvd := 0
  79. END ResetRcv;
  80. PROCEDURE Listen(b: BOOLEAN);
  81. BEGIN
  82. WriteReg1(0, 07EH + ORD(b)); (*CONFIG <= mask ints; EN_CRC(2 byte), PWR_UP, PRX/PTX*)
  83. WriteReg1(7, 70H); (*STATUS <= clear ints*)
  84. IF b THEN SPICtrl({netEnable}) END (*turn radio on*)
  85. END Listen;
  86. PROCEDURE Start*(filt: BOOLEAN);
  87. VAR n: INTEGER;
  88. BEGIN filter := filt; Adr := 0;
  89. SYSTEM.GET(swi, n); n := n DIV 4 MOD 10H * 10 + 5;
  90. WriteReg1(5, n); (*RF_CH <= channel: 5, 15, 25...*)
  91. WriteReg1(6, 07H); (*RF_SETUP <= 1Mb for better range, 0dBm*)
  92. WriteReg1(11H, SubPacket); (*RX_PW_P0 <= pipe 0 payload width*)
  93. Flush(); Listen(TRUE); ResetRcv
  94. END Start;
  95. PROCEDURE SendPacket*(VAR head: Header; dat: ARRAY OF BYTE);
  96. VAR len, i, off: INTEGER; timeout: BOOLEAN; payload: ARRAY SubPacket
  97. OF BYTE;
  98. BEGIN (*let any receive ack finish before turning radio off*)
  99. i := Kernel.Time() + Wait;
  100. REPEAT SPICtrl({netEnable, netSelect}); SPI(0FFH); SPICtrl({netEnable}) (*NOP*)
  101. UNTIL Kernel.Time() >= i;
  102. IF Adr = 0 THEN Adr := i MOD 100H END;
  103. Listen(FALSE);
  104. head.sadr := Adr; head.valid := TRUE;
  105. SYSTEM.COPY(SYSTEM.ADR(head), SYSTEM.ADR(payload), HdrSize DIV 4);
  106. i := HdrSize; off := 0; len := head.len;
  107. WHILE (len > 0) & (i < SubPacket) DO payload[i] := dat[off]; INC(i); INC(off); DEC(len) END;
  108. WHILE i < SubPacket DO payload[i] := 0; INC(i) END;
  109. SubSnd(SYSTEM.ADR(payload), timeout);
  110. WHILE ~timeout & (len # 0) DO i := 0; (*send the rest*)
  111. WHILE (len > 0) & (i < SubPacket) DO payload[i] := dat[off]; INC(i); INC(off); DEC(len) END;
  112. WHILE i < SubPacket DO payload[i] := 0; INC(i) END;
  113. SubSnd(SYSTEM.ADR(payload), timeout)
  114. END;
  115. Listen(TRUE)
  116. END SendPacket;
  117. PROCEDURE Available*(): INTEGER;
  118. BEGIN (*packet already rcvd*)
  119. RETURN rx.hd.len - rcvd
  120. END Available;
  121. PROCEDURE Receive*(VAR x: BYTE);
  122. BEGIN (*packet already rcvd*)
  123. IF rcvd < rx.hd.len THEN x := rx.dat[rcvd]; INC(rcvd) ELSE x := 0 END
  124. END Receive;
  125. PROCEDURE Rcvd(time: INTEGER): BOOLEAN;
  126. VAR status, fifoStatus: BYTE; rcvd: BOOLEAN;
  127. BEGIN time := time + Kernel.Time();
  128. REPEAT
  129. SPICtrl({netEnable, netSelect}); SPI(17H); (*R_REGISTER FIFO_STATUS*)
  130. SYSTEM.GET(spiData, status); SPI(-1); SYSTEM.GET(spiData, fifoStatus); SPICtrl({netEnable});
  131. rcvd := ODD(status DIV 40H) OR ~ODD(fifoStatus) (*RX_DR (data ready) or RX FIFO not empty*)
  132. UNTIL rcvd OR (Kernel.Time() >= time);
  133. RETURN rcvd
  134. END Rcvd;
  135. PROCEDURE ReceiveHead*(VAR head: Header); (*actually, recv whole packet*)
  136. VAR adr, n: INTEGER;
  137. BEGIN head.valid := FALSE;
  138. IF Rcvd(0) THEN
  139. ResetRcv; adr := SYSTEM.ADR(rx); SubRcv(adr);
  140. n := (rx.hd.len + HdrSize - 1) DIV SubPacket;
  141. IF (rx.hd.len <= MaxPayload)
  142. & ((rx.hd.dadr = 0FFH) OR ~filter OR (Adr = 0) OR (rx.hd.dadr = Adr)) THEN
  143. WHILE (n > 0) & Rcvd(Wait) DO
  144. INC(adr, SubPacket); SubRcv(adr); DEC(n)
  145. END;
  146. rx.hd.valid := (n = 0)
  147. ELSE WHILE Rcvd(Wait) DO SubRcv(adr) END; ResetRcv (*discard packet*)
  148. END;
  149. head := rx.hd
  150. END
  151. END ReceiveHead;
  152. PROCEDURE Skip*(m: INTEGER);
  153. VAR dmy: BYTE;
  154. BEGIN WHILE m # 0 DO Receive(dmy); DEC(m) END
  155. END Skip;
  156. PROCEDURE Stop*;
  157. BEGIN SPICtrl({}); Flush(); ResetRcv
  158. END Stop;
  159. BEGIN Start(TRUE)
  160. END SCC.