News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

LORA RFM98W Using SX1278 Chip?

Started by Craig, Mar 31, 2022, 06:49 AM

Previous topic - Next topic

Craig

Hello
I am using a Lora RFM98W (433Mhz) which uses the SX1278 Chip. I have setup a basic Test Link with two of the Lora units one is set as a Transmitter and the other as a  Receiver to just send a message for testing purposes. I have the Transmit side working as I have another Standard Receiver (Not a Lora Receiver)  setup with a field LED to see if it receives a 433Mhz signal and it does when the Lora transmitter is triggered. I can also see on my Logic analyzer that it is Transmitting data and it looks correct. The issue I am having is that I am Not receiving anything on the Lora Receiver I cannot get the RXDone Interrupt to Trigger on the DiO0 Pin (DIO0 Pin is set as an INPUT and as a "INTERRUPT ON CHANGE"), to indicate that it has received a packet. I am sure that both the radios are set up the same ie.On Default they are (Frequency 434Mhz, Band Width_125, Coding Rate_4/5, Spreading Factor_128,PA Boost = On,).

What I do First with the radios is:
1) Do a Manual RESET
2) Put in SLEEP Mode then to STANDBY Mode.
3) INITIALIZE the Radios
4) Go To TRANSMIT Mode or RECEIVE Mode depending on which radio is used.
If I am using TRANSMIT Mode I set the Register to the TXDone IRQ Flag to wait for the Tx Interrupt on the DIO0 Pin
If I am using RECEIVE Mode, Which is set to CONTINUOUS RECEIVE I set the Register to the RXDone IRQ Flag to wait for the RX Interrupt on the DIO0 Pin.

Does anyone know these RFM Lora Modules or similar using the SX1278/6 Chipset running on SPI and could you please help me to understand why I cannot get an Interrupt on the RXDone IRQ and where I can look as my eyes are tired at this stage of hunting for a solution to this problem?

Regards
Craig

trastikata

Hello Craig,

with the SX1278 I've achieve 30+ km link without any trouble. However for the correct work it is very important that your TX packet descriptor matches the RX packet descriptor so the Receiver in SX1278 can threat it correctly and issue Interrupt.I'd assume you are using the LoRa modulation?

Also make sure your FIFO buffer addresses are correctly set and read and the preamble is sufficient.

Another thing - I am not familiar with RFM98W since I design with bare SX1278 chips, but if it is using a crystal - the lowest stable link you can get is at SF11 and BW 62.5kHz. With a TCXO you can go down to SF11 and 15.6 kHz. I do not recommend SF12 - nevr got a stable link with it at lower BW.

top204

I'm currently working on a library that uses an SX1278 module, and I cannot get it to go beyond a 100 metres or so!

It is using LoRa and I have it set for maximum power and highest LNA gain etc, but I cannot get the module to draw more that 15mA or so, so it is not transmitting very far. All the data is received and tranmsitted and the DIO0 pin is brought high when it receives and transmits etc, but something I am doing is not quite right. I'm now reducing the bandwidth to see if that makes a range difference.

The datasheet is a nightmare for it. :-) So many registers with so many meanings. i.e. If something is done that way, it will do that, but not if it is doing that etc... LOL And the C++ code for them is a nightmare, and sooooooo bloated and cumbersome I gave up trying to see what was happening under the hood because it certainly was not, initially, written for a microcontroller.

I've created the library so it replaces the HRSout4/HRsin4 commands and operates just like a USART, with timeouts etc... So the packet only has a single byte in it at offset address 0.

Any help would be much appreciated to give a better range, and I will add the library to my website.



trastikata

Quote from: top204 on Mar 31, 2022, 03:40 PMAny help would be much appreciated to give a better range, and I will add the library to my website.

Hello Les, check your PM.

top204

#4
Many thanks.

Upon looking at your LoRa setup routine, I saw I was missing the "cSX_REG_PA_DAC" register, which is at address $4D. I have now added it to the library's SX_Setup procedure, and I can see it is working better because the current has gone up slightly when transmitting.

top204

Trastikata...

What current does your SX1278 unit use when it is transmitting?

Giuseppe MPO

Very, very interesting, I have tried a long time with a PIC but never had good results. Les will you give us this gift in the next update? Maybe....

Craig

Hello Trastikata

Thanks for the feed back, I am testing only in Lora Mode and the RFM98W uses an External Xtal. After Resting the Sx1278, I do the Initialize in the following order For Both the TX and RX.
Just to keep the thread short, I have left out the Writing & Reading to the SPI and only showed what's loaded into the Registers etc.

Dim PacketSize As 20
Dim TxBuf[PacketSize] As Byte 
Str TxBuf = "Hello world"          ' Test Message to load into Packet to send
'----------------------------------------------------------------------------------------------
{Initialize For Transmitter) 
$[01] = $81 ' RegOpMode (Select Lora & Standby Mode)
DelayMS 10

$[06] = $6C, $[07] = $80, $[08] = 00 ' Frequency to 434.00Mhz.

$[1D] = $72 ' RegModemConfig1 (Bw125Khz, Cr4/5, Explicit Header)
$[1E] = $74 ' RegModemConfig2 (SF128Chirps/Symbol, Tx = Normal Mode, CRC = On)
$[26] = $00 ' RegModemConfig3
$[09] = $CF ' RegPaConfig (Pa Selection & Output Power)[PA_BOOST = 1, Max Power, POut = 17]
$[0A] = $09 ' RegPaRamp (Pa Ramp Time = 40us)
$[0B] = $1B ' RegOCP (OcpOn = 1, OcpTrim = 100mA)
$[0C] = $20 ' RegLNA (LNA = G1 Max)
$[0E] = $00 ' Tx Start at Position 00 in the FIFO.
$[0F] = $00 ' Rx Start at Position 00 in the FIFO.
$[20] = $00 ' RegPreambleMsb - Preamble Length MSB
$[21] = $08 ' RegPreambleLsb - Preamble Length LSB
$[22] = PACKETSize ' RegPayloadLength - Payload Length in Bytes
$[24] = $00 ' RegHopPeriod - Frequency Hopping Period 
$[26] = $00 ' RegModemConfig3 - Frequency Hopping Period
$[1F] = $64 ' RegSymbTimeoutLsb - RX Time-Out LSB
$[42] = $11 ' RegVersion - Hope RF ID Relating To the Silicon Revision
$[4B] = $09 ' RegTcxo - TCXO Or Xtal Input Settings [Xtal = ON] 
'---------------------------------------------------------------------------------------------
{Initialize For Receiver)

Identical to Transmitter as Above Except for Location [$1E].
$[1E] = $70 ' RegModemConfig2 (SF128Chirps/Symbol, Tx = Normal Mode, CRC = OFF)
'---------------------------------------------------------------------------------------------

TX_Mode:
RegAddress = $01 : DataOut = $81 : GoSub SPIOut          ' Set Standby Mode, HF, Lora Mode
RegAddress = $40 : DataOut = $01 : GoSub SPIOut          ' LORA Mode = DIO0 TxDone(01)
RegAddress = $12 : DataOut = $FF : GoSub SPIOut          ' Clear the RegIrqFlags
RegAddress = $11 : DataOut = $00 : GoSub SPIOut          ' Clear All IrqFlagsMasks
RegAddress = $11 : DataOut = $08 : GoSub SPIOut          ' Set TxDoneMask IRQ Flag - RFM98w
RegAddress = $0E : GoSub SPIIn : DataHold = DataRec      ' Read TxBaseAddr Read RegFifoTxBaseAddr
RegAddress = $0D : DataOut = DataHold : GoSub SPIOut    ' TxBaseAddr -> FiFoAddrPtr

For j = 0 To PacketSize - 2                              ' j = 0 To PacketSize-2
  RegAddress = $00 : DataOut = TxBuf[j] : GoSub SPIOut    ' Send Payload to the TX FIFO
Next j
   
IOCAF.4 = 0                                              ' Clear PORTA.4 IOC Flag PORTA.4
RegAddress = $01 : DataOut = $8B : GoSub SPIOut          ' Start TX Tell the RFM98W To start transmitting......

Wait_TX:
  If IOCAF.4 = 0 Then
  High Rx_Tx_LED
  GoTo Wait_TX
  EndIf

  DelayMS 50
  RegAddress = $01 : DataOut = $81 : GoSub SPIOut          ' Set STANDBY Mode, LORA, Low Frequency Mode in RFM98w
  If IOCAF.4 = 1 Then
  Low Rx_Tx_LED
  EndIf

Return

'-----------------------------------------------------------------------------------------------------------------
' For The Receiver I Setup as Follows:
'_________________________________________________________________________________________________________________

To_RX_Mode:
    RegAddress = $01 : DataOut = $81 : GoSub SPIOut                ' Set Standby Mode, LORA, Low Frequency Mode in RFM98
    RegAddress = $21 : DataOut = $08 : GoSub SPIOut                ' Set the preamble Length 8 Bytes     
    RegAddress = $22 : DataOut = PacketSize  : GoSub SPIOut        ' Packet length Set to 20 Bytes
    RegAddress = $40 : DataOut = $22 : GoSub SPIOut                ' LORA Mode = DIO0 RxDone(00)
    RegAddress = $12 : DataOut = $FF : GoSub SPIOut                ' Clear All Interrupt's - RFM98W
    RegAddress = $11 : DataOut = $00 : GoSub SPIOut                ' Clear All IrqFlagsMasks
    RegAddress = $11 : DataOut = $C0 : GoSub SPIOut                ' ONLY Set RxDoneMask IRQ Flag & RxTimeoutMask - RFM98W
    RegAddress = $0F : GoSub SPIIn : DataHold = DataRec            ' Read RxBaseAddr Read RegFifoRxBaseAddr
    RegAddress = $0D : DataOut = DataHold : GoSub SPIOut            ' RxBaseAddr -> FiFoAddrPtr 
    RegAddress = $1C : DataOut = $40 : GoSub SPIOut                ' RegHopChannel, RxPayLoadCrcOn = 1 = ON 
    RegAddress = $01 : DataOut = $85 : GoSub SPIOut                ' Start Rx - Tell the RFM98w to Wait in Continious Receive Mode
    IOCAF.4 = 0                                                    ' Clear PORTA.4 IOC Flag PORTA.4
Return

'------------------------------------------------------------------------------------------------------------------
RX_Waiting:                                                        ' Wait Here for the RxIrq Interrupt Flag to Appear?

    Print At 1,1, " Waiting.....Rx "
 
RXWait:
If IOCAF.4 = 0 Then                             
  High LEDs
  GoTo RXWait
Endif

DelayMS 50
RegAddress = $01 : DataOut = $81 : GoSub SPIOut                      ' Set STANDBY Mode, LORA, Low Frequency Mode in RFM98
If IOCAF.4 = 1 Then             
  Low LEDs
EndIf

Return 
'---------------------------------------------------------------------------------------------------------------------

I must still be missing a register or something as I still cannot get the RxDone Irq Flag to trigger, I am not worrying about
the other Flags after this as I must get this to trigger first then I can go further.

Regards

Craig

trastikata

Quote from: top204 on Mar 31, 2022, 08:09 PMWhat current does your SX1278 unit use when it is transmitting?

Les, when using the PO_BOOST pin at maximum power - about 150mA with a whip antenna.

If yours is drawing less current - check your over-current protection register - simply set it to aout 200mA.

Also it is very important to have good impedance matching circuit to the antenna connector (following the recommended hardware design worked very well for me) and of course the antenna should be matching the frequency.

Craig

Hi Trastikata and Guys

Sorry only got back to this now started post and then saw all the replies thanks very much.
Les / Trastikata I get on average 70 - 80Ma on a long burst Transmission and about 40Ma on a short burst Transmission.
The Datasheets are Pathetic to say the least, I have spent days picking through various libraries which is quit confusing
to say the least as they all contradict one another.

trastikata

#10
Quote from: Craig on Mar 31, 2022, 09:18 PMI must still be missing a register or something as I still cannot get the RxDone Irq Flag to trigger, I am not worrying about
the other Flags after this as I must get this to trigger first then I can go further.

Craig I see quite few problems while skimming through - sorry if I missed something, just pointing out things you might need to take a look at:

- You need to reset the chip first
- The packet properties are predetermined, ergo the header must be Implicit on both RX and TX
- Sync word is not set
- You set the frequency to 434 MHz, but in the same time the RegOpMode is set to HF
- I don't see the Interrupt mask set to TX done
- The FIFO base address is 0 but the pointer seems different from 0
- You routine for writing in the FIFO for TX seems odd
- The preamble settings for RX should be slightly longer than TX

Anyway I think it would be easier to give you a starting point with working code and you continue from there. This is working code, sending 17 bytes with SX1278 only over 30km distance, stripped from some subroutines but their names speak for their purpose.  The code is from this project:
http://www.blog.exrockets.com/blog/100-mw-433-mhz-long-range-30-km-gps-tracker-kit/

When Les' code is ready maybe it would be easier just using the libraries he wrote.

'=================================================== TX MODE =====================================================================================
INITIALIZE_LORA_TX:
    Low MODEM_RESET
    DelayMS 100
    High MODEM_RESET
    DelayMS 100

    spi_address = RegOpMode             : spi_data = %00001000 : GoSub SPI_WRITE     'Set Sleep mode
    spi_address = RegOpMode             : spi_data = %10001000 : GoSub SPI_WRITE     'Set LoRa mode SLEEP

    spi_address = RegFrMsb              : spi_data = freq.Byte2: GoSub SPI_WRITE     'Set FRQ
    spi_address = RegFrMid              : spi_data = freq.Byte1: GoSub SPI_WRITE     'Set FRQ
    spi_address = RegFrLsb              : spi_data = freq.Byte0: GoSub SPI_WRITE     'Set FRQ
   
    spi_address = RegPaConfig           : spi_data = %11111111 : GoSub SPI_WRITE     'Set pout
    spi_address = RegOcp                : spi_data = %00110111 : GoSub SPI_WRITE     'Set 200mA current protection
    spi_address = RegIrqFlagsMask       : spi_data = %11110111 : GoSub SPI_WRITE     'Set IRQ on TX_done
    spi_address = RegModemConfig1       : spi_data = %00101001 : GoSub SPI_WRITE     'Set BW, 4/8, Implicit, 15.6kHz
    spi_address = RegModemConfig2       : spi_data = %10110100 : GoSub SPI_WRITE     'Set Spreading Factor 11, CRC on
    spi_address = RegSymbTimeoutLsb     : spi_data = %01100100 : GoSub SPI_WRITE     'Set SymbTimeout
    spi_address = RegDioMapping1        : spi_data = %01000000 : GoSub SPI_WRITE     'DIO0 = TX Done
    spi_address = RegFifoTxBaseAddr     : spi_data = 0         : GoSub SPI_WRITE     'Set FIFO base address to 0
    spi_address = RegFifoAddrPtr        : spi_data = 0         : GoSub SPI_WRITE     'Set FIFO pointer address to 0
    spi_address = RegPreambleMsb        : spi_data = 0         : GoSub SPI_WRITE     'Set Preamble
    spi_address = RegPreambleLsb        : spi_data = 16        : GoSub SPI_WRITE     'Set Preamble to 16 bits
    spi_address = RegSyncWord           : spi_data = %10001000 : GoSub SPI_WRITE     'Set Sync word
    spi_address = RegPayloadLength      : spi_data = 17        : GoSub SPI_WRITE     'Set Payload length to 17 bytes
    spi_address = RegMaxPayloadLength   : spi_data = 17        : GoSub SPI_WRITE     'Set Maximum payload length to 17 bytes
    spi_address = RegModemConfig3       : spi_data = %00001000 : GoSub SPI_WRITE     'Set Low Data Rate Optimize, register LnaGain
    spi_address = RegPllLf              : spi_data = %00010000 : GoSub SPI_WRITE
    spi_address = RegDetectOptimize     : spi_data = %01100011 : GoSub SPI_WRITE     'Set Errata
    spi_address = $36                   : spi_data = $03       : GoSub SPI_WRITE     'Set Errata
    spi_address = RegPaDac              : spi_data = $87       : GoSub SPI_WRITE     'Set High Power Settings
    spi_address = RegOpMode             : spi_data = %10001001 : GoSub SPI_WRITE     'Set LoRa mode STANDBY
    spi_address = RegOpMode             : spi_data = %10001010 : GoSub SPI_WRITE     'Set LoRa mode FSTX MODE

    GoSub CLEAR_IRQ
Return

CLEAR_IRQ:
    spi_address = RegIrqFlags : GoSub SPI_READ
    If spi_byte.3 = 1 Then
        spi_address = RegIrqFlags : spi_data = %00001000 : GoSub SPI_WRITE     'Clear IRQ
    EndIf
Return

SEND_MESSAGE:
    If DIO0 = 1 Then
        GoSub CLEAR_IRQ             'Clear IRQ
    EndIf
   
    spi_address = RegFifoAddrPtr : spi_data = 0 : GoSub SPI_WRITE           'Set FIFO pointer address to 0
    spi_address = RegFifo : GoSub SEND_FIFO
    spi_address = RegOpMode : spi_data = %10001011 : GoSub SPI_WRITE     'Set Tx mode

    While DIO0 = 0 : Wend

    GoSub CLEAR_IRQ
Return

SEND_FIFO:
    Low SEL
        temp_spi = spi_address
        temp_spi.7 = 1
        spi_byte = temp_spi : GoSub SPI_SEND
        For y = 0 To 16
            spi_byte = payload[y]
            GoSub SPI_SEND
        Next
    High SEL
Return

'=================================================== RX MODE =====================================================================================
INITIALIZE_LORA:
    Low MODEM_RESET
    DelayMS 100
    High MODEM_RESET
    DelayMS 100

    spi_address = RegOpMode             : spi_data = %00001000 : GoSub SPI_WRITE     'Set Sleep mode
    spi_address = RegOpMode             : spi_data = %10001000 : GoSub SPI_WRITE     'Set LoRa mode SLEEP
    spi_address = RegOpMode             : spi_data = %10001001 : GoSub SPI_WRITE     'Set LoRa mode STANDBY

    spi_address = RegFrMsb              : spi_data = freq.Byte2: GoSub SPI_WRITE     'Set FRQ
    spi_address = RegFrMid              : spi_data = freq.Byte1: GoSub SPI_WRITE     'Set FRQ
    spi_address = RegFrLsb              : spi_data = freq.Byte0: GoSub SPI_WRITE     'Set FRQ
   
    spi_address = RegLna                : spi_data = %00100011 : GoSub SPI_WRITE     'Set LNA max gain
    spi_address = RegFifoRxBaseAddr     : spi_data = 0         : GoSub SPI_WRITE     'Set FIFO base address to 0
    spi_address = RegFifoAddrPtr        : spi_data = 0         : GoSub SPI_WRITE     'Set FIFO pointer address to 0
    spi_address = RegIrqFlagsMask       : spi_data = %10001111 : GoSub SPI_WRITE     'Set IRQ on RX_done, PayloadCrcErrorMask, ValidHeaderMask
    spi_address = RegModemConfig1       : spi_data = %00101001 : GoSub SPI_WRITE     'Set BW, 4/8, Implicit, 15.6kHz
    spi_address = RegModemConfig2       : spi_data = %10110100 : GoSub SPI_WRITE     'Set Spreading Factor 11, CRC on
    spi_address = RegSymbTimeoutLsb     : spi_data = %01100100 : GoSub SPI_WRITE     'Set SymbTimeout
    spi_address = RegDioMapping1        : spi_data = %00000000 : GoSub SPI_WRITE     'DIO0 = RX Done
    spi_address = RegPreambleMsb        : spi_data = 0         : GoSub SPI_WRITE     'Set Preamble
    spi_address = RegPreambleLsb        : spi_data = 18        : GoSub SPI_WRITE     'Set Preamble to 18 bits
    spi_address = RegSyncWord           : spi_data = %10001000 : GoSub SPI_WRITE     'Set Sync word
    spi_address = RegPayloadLength      : spi_data = 17        : GoSub SPI_WRITE     'Set Payload length to 17 bytes
    spi_address = RegMaxPayloadLength   : spi_data = 17        : GoSub SPI_WRITE     'Set Maximum payload length To 17 bytes
    spi_address = RegModemConfig3       : spi_data = %00001000 : GoSub SPI_WRITE     'Set AGC

    spi_address = RegAgcRefLf           : spi_data = %00011001 : GoSub SPI_WRITE
    spi_address = RegAgcThresh1Lf       : spi_data = %00001100 : GoSub SPI_WRITE
    spi_address = RegAgcThresh2Lf       : spi_data = %01001011 : GoSub SPI_WRITE
    spi_address = RegAgcThresh3Lf       : spi_data = %11001100 : GoSub SPI_WRITE
    spi_address = RegPllLf              : spi_data = %00010000 : GoSub SPI_WRITE

    spi_address = RegDetectOptimize     : spi_data = %01100011 : GoSub SPI_WRITE     'Set Errata
    spi_address = $36                   : spi_data = $03       : GoSub SPI_WRITE     'Set Errata
    spi_address = RegPaDac              : spi_data = $87       : GoSub SPI_WRITE     'Set High Power Settings

    spi_address = RegOpMode             : spi_data = %10001100 : GoSub SPI_WRITE     'Set LoRa mode FSRX MODE
    spi_address = RegOpMode             : spi_data = %10001101 : GoSub SPI_WRITE    'Set LoRa mode Cont RX MODE
   
    GoSub CLEAR_IRQ
Return

CLEAR_IRQ:
    spi_address = RegIrqFlags : spi_data = %11111111 : GoSub SPI_WRITE     'Clear IRQ
Return

RECEIVE_MESSAGE:
    While DIO0 = 0 : Wend
   
    spi_address = RegIrqFlags : GoSub SPI_READ
    If spi_data.6 = 0 Or spi_data.5 = 1 Or spi_data.4 = 0 Then
        GoSub CLEAR_IRQ
        DelayMS 1
        GoTo RECEIVE_MESSAGE
    EndIf
   
    'Read SNR
    spi_address = RegPktSnrValue : GoSub SPI_READ
    SNR = spi_data
   
    'Read RSSI
    spi_address = RegPktRssiValue : GoSub SPI_READ
    RSSI = spi_data
   
    'Get the frequency offset for correction
    LoRaFeiValue = 0
    spi_address = RegFeiMsb : GoSub SPI_READ
    LoRaFeiValue.Byte2 = spi_data
    spi_address = RegFeiMid : GoSub SPI_READ
    LoRaFeiValue.Byte1 = spi_data
    spi_address = RegFeiLsb : GoSub SPI_READ
    LoRaFeiValue.Byte0 = spi_data
   
    'Get payload length
    spi_address = RegRxNbBytes : GoSub SPI_READ
    payload_len = spi_data
    'Start address of last packet received
    spi_address = RegFifoRxCurrentAddr : GoSub SPI_READ
    payload_add = spi_data
    'Set FIFO pointer address
    spi_address = RegFifoAddrPtr : spi_data = payload_add : GoSub SPI_WRITE   
     
    Low SEL : DelayCS 4
        spi_address = RegFifo
        temp_spi = spi_address
        temp_spi.7 = 0
        spi_byte = temp_spi : GoSub SPI_SEND
        Low MOSI

        For y = 0 To payload_len - 1
            GoSub SPI_RECEIVE
            payload[y] = spi_byte
        Next
    High SEL

    GoSub CLEAR_IRQ
Return

Giuseppe MPO

I have tried to use both the RFM98 (433MHz) and the RFM95 (868MHz), trying to connect them with the PIC I have not succeeded, I have not been able to establish an interview with RFM. To try to understand what kind of conversation and what parameters to set, I connected the modules to Arduino using its libraries. It all worked flawlessly with distances or in hidden places, in an incredible way, in a way that I never expected for such small powers. It must be said that I also connected my amateur radio antenna that I have on the roof, a collinear one for 430MHz and, by setting all the parameters, it really did things you would not believe, I never expected so much. This post is really interesting, being able to use these modules not with Arduino but with PICs would be really fantastic.

Brett

I have been playing with RFM69W modules for a while on a project using OOK. I found the frequency to vary between modules, so for maximum range you might need to calibrate your frequency with a counter or signal generator.

atomix

I use these modules here, they represent the ready-made UART bridge.

https://aliexpress.com/item/32791728376.html

trastikata

Quote from: Giuseppe MPO on Apr 01, 2022, 01:01 AMwith PICs would be really fantastic.

Giuseppe MPO, this is my fully working code, stripped from other not really necessary subs, as mentioned earlier. All you need to do is to change the pin declares and display the data you receive somewhere. The code below includes the RX and TX part. It is not pretty but with not much commenting but that's the way I often write when in a hurry.

Hope it helps

Device = 18F25J50

Declare Xtal = 4

Declare Auto_Variable_Bank_Cross = On
Declare FSR_CONTEXT_SAVE = On
Declare LABEL_BANK_RESETS = On
Declare Optimiser_Level = 3
Declare Dead_Code_Remove = On


Symbol RegFifo = $00
Symbol RegOpMode = $01
Symbol RegFrMsb = $06
Symbol RegFrMid = $07
Symbol RegFrLsb = $08
Symbol RegPaConfig = $09
Symbol RegPaRamp = $0A
Symbol RegOcp = $0B
Symbol RegLna = $0C
Symbol RegFifoAddrPtr = $0D
Symbol RegFifoTxBaseAddr = $0E
Symbol RegFifoRxBaseAddr = $0F
Symbol RegFifoRxCurrentAddr = $10
Symbol RegIrqFlagsMask = $11
Symbol RegIrqFlags = $12
Symbol RegRxNbBytes = $13
Symbol RegRxHeaderCntValueMsb = $14
Symbol RegRxHeaderCntValueLsb = $15
Symbol RegRxPacketCntValueMsb = $16
Symbol RegRxPacketCntValueLsb = $17
Symbol RegModemStat = $18
Symbol RegPktSnrValue = $19
Symbol RegPktRssiValue = $1A
Symbol RegRssiValue = $1B
Symbol RegHopChannel = $1C
Symbol RegModemConfig1 = $1D
Symbol RegModemConfig2 = $1E
Symbol RegSymbTimeoutLsb = $1F
Symbol RegPreambleMsb = $20
Symbol RegPreambleLsb = $21
Symbol RegPayloadLength = $22
Symbol RegMaxPayloadLength = $23
Symbol RegHopPeriod = $24
Symbol RegFifoRxByteAddr = $25
Symbol RegModemConfig3 = $26
Symbol PpmCorrection = $27
Symbol RegFeiMsb = $28
Symbol RegFeiMid = $29
Symbol RegFeiLsb = $2A
Symbol RegRssiWideband = $2C
Symbol IfFreq2 = $2F
Symbol IfFreq1 = $30
Symbol RegDetectOptimize = $31
Symbol RegInvertIQ = $33
Symbol RegHighBWOptimize1 = $36
Symbol RegDetectionThreshold = $37
Symbol RegSyncWord = $39
Symbol RegHighBWOptimize2 = $3A
Symbol RegInvertIQ2 = $3B
Symbol RegTcxo = $4B
Symbol RegPaDac = $4D
Symbol RegAgcRefLf = $61
Symbol RegAgcThresh1Lf = $62
Symbol RegAgcThresh2Lf = $63
Symbol RegAgcThresh3Lf = $64
Symbol RegPllLf = $70
Symbol RegDioMapping1 = $40
Symbol RegDioMapping2 = $41


Symbol DIO0 = PORTA.1
Input DIO0
Symbol MOSI = PORTA.5
Output MOSI
Symbol SEL = PORTB.0
Output SEL
Symbol MODEM_RESET = PORTB.1
Output MODEM_RESET
Symbol SCLK = PORTB.2
Output SCLK
Symbol MISO = PORTB.3
Input MISO

Dim i As Byte
Dim spi_byte As Byte
Dim spi_data As Byte
Dim temp_spi As Byte
Dim spi_address As Byte
Dim payload[17] As Byte
Dim payload_add As Byte
Dim payload_len As Byte
Dim freq As Dword
Dim SNR As SByte
Dim fSNR As Float
Dim RSSI As Byte
Dim fRSSI As Float
Dim LoRaFeiValue As SDword

MAIN:
    Low SCLK : High SEL
    freq = 6802637
   
'Tx routines
    GoSub INITIALIZE_LORA_TX       
    GoSub CONSTRUCT_MESSAGE
    GoSub SEND_MESSAGE
   
    While 1 = 1 : Wend
   
'Rx routines   
    GoSub INITIALIZE_LORA_RX  
    GoSub RECEIVE_MESSAGE
    'Do something with the data from payload buffer
    
    While DIO0 = 0 : Wend
   

'=================================================== TX MODE =====================================================================================
INITIALIZE_LORA_TX:
    Low MODEM_RESET
    DelayMS 100
    High MODEM_RESET
    DelayMS 100

    spi_address = RegOpMode             : spi_data = %00001000 : GoSub SPI_WRITE     'Set Sleep mode
    spi_address = RegOpMode             : spi_data = %10001000 : GoSub SPI_WRITE     'Set LoRa mode SLEEP

    spi_address = RegFrMsb              : spi_data = freq.Byte2: GoSub SPI_WRITE     'Set FRQ
    spi_address = RegFrMid              : spi_data = freq.Byte1: GoSub SPI_WRITE     'Set FRQ
    spi_address = RegFrLsb              : spi_data = freq.Byte0: GoSub SPI_WRITE     'Set FRQ
  
    spi_address = RegPaConfig           : spi_data = %11111111 : GoSub SPI_WRITE     'Set pout
    spi_address = RegOcp                : spi_data = %00110111 : GoSub SPI_WRITE     'Set 200mA current protection
    spi_address = RegIrqFlagsMask       : spi_data = %11110111 : GoSub SPI_WRITE     'Set IRQ on TX_done
    spi_address = RegModemConfig1       : spi_data = %00101001 : GoSub SPI_WRITE     'Set BW, 4/8, Implicit, 15.6kHz
    spi_address = RegModemConfig2       : spi_data = %10110100 : GoSub SPI_WRITE     'Set Spreading Factor 11, CRC on
    spi_address = RegSymbTimeoutLsb     : spi_data = %01100100 : GoSub SPI_WRITE     'Set SymbTimeout
    spi_address = RegDioMapping1        : spi_data = %01000000 : GoSub SPI_WRITE     'DIO0 = TX Done
    spi_address = RegFifoTxBaseAddr     : spi_data = 0         : GoSub SPI_WRITE     'Set FIFO base address to 0
    spi_address = RegFifoAddrPtr        : spi_data = 0         : GoSub SPI_WRITE     'Set FIFO pointer address to 0
    spi_address = RegPreambleMsb        : spi_data = 0         : GoSub SPI_WRITE     'Set Preamble
    spi_address = RegPreambleLsb        : spi_data = 16        : GoSub SPI_WRITE     'Set Preamble to 16 bits
    spi_address = RegSyncWord           : spi_data = %10001000 : GoSub SPI_WRITE     'Set Sync word
    spi_address = RegPayloadLength      : spi_data = 17        : GoSub SPI_WRITE     'Set Payload length to 17 bytes
    spi_address = RegMaxPayloadLength   : spi_data = 17        : GoSub SPI_WRITE     'Set Maximum payload length to 17 bytes
    spi_address = RegModemConfig3       : spi_data = %00001000 : GoSub SPI_WRITE     'Set Low Data Rate Optimize, register LnaGain
    spi_address = RegPllLf              : spi_data = %00010000 : GoSub SPI_WRITE
    spi_address = RegDetectOptimize     : spi_data = %01100011 : GoSub SPI_WRITE     'Set Errata
    spi_address = $36                   : spi_data = $03       : GoSub SPI_WRITE     'Set Errata
    spi_address = RegPaDac              : spi_data = $87       : GoSub SPI_WRITE     'Set High Power Settings
    spi_address = RegOpMode             : spi_data = %10001001 : GoSub SPI_WRITE     'Set LoRa mode STANDBY
    spi_address = RegOpMode             : spi_data = %10001010 : GoSub SPI_WRITE     'Set LoRa mode FSTX MODE

    GoSub CLEAR_IRQ_TX
Return

CLEAR_IRQ_TX:
    spi_address = RegIrqFlags : GoSub SPI_READ
    If spi_byte.3 = 1 Then
        spi_address = RegIrqFlags : spi_data = %00001000 : GoSub SPI_WRITE     'Clear IRQ
    EndIf
Return

CONSTRUCT_MESSAGE:
    'Fill some data to send
    For i = 0 To 16
        payload[i] = i
    Next
Return

SEND_MESSAGE:
    If DIO0 = 1 Then
        GoSub CLEAR_IRQ_TX             'Clear IRQ
    EndIf
  
    spi_address = RegFifoAddrPtr : spi_data = 0 : GoSub SPI_WRITE           'Set FIFO pointer address to 0
    spi_address = RegFifo : GoSub SEND_FIFO
    spi_address = RegOpMode : spi_data = %10001011 : GoSub SPI_WRITE     'Set Tx mode

    While DIO0 = 0 : Wend

    GoSub CLEAR_IRQ_TX
Return

SEND_FIFO:
    Low SEL
        temp_spi = spi_address
        temp_spi.7 = 1
        spi_byte = temp_spi : GoSub SPI_SEND
        For i = 0 To 16
            spi_byte = payload[i]
            GoSub SPI_SEND
        Next
    High SEL
Return

'=================================================== RX MODE =====================================================================================
INITIALIZE_LORA_RX:
    Low MODEM_RESET
    DelayMS 100
    High MODEM_RESET
    DelayMS 100

    spi_address = RegOpMode             : spi_data = %00001000 : GoSub SPI_WRITE     'Set Sleep mode
    spi_address = RegOpMode             : spi_data = %10001000 : GoSub SPI_WRITE     'Set LoRa mode SLEEP
    spi_address = RegOpMode             : spi_data = %10001001 : GoSub SPI_WRITE     'Set LoRa mode STANDBY

    spi_address = RegFrMsb              : spi_data = freq.Byte2: GoSub SPI_WRITE     'Set FRQ
    spi_address = RegFrMid              : spi_data = freq.Byte1: GoSub SPI_WRITE     'Set FRQ
    spi_address = RegFrLsb              : spi_data = freq.Byte0: GoSub SPI_WRITE     'Set FRQ
  
    spi_address = RegLna                : spi_data = %00100011 : GoSub SPI_WRITE     'Set LNA max gain
    spi_address = RegFifoRxBaseAddr     : spi_data = 0         : GoSub SPI_WRITE     'Set FIFO base address to 0
    spi_address = RegFifoAddrPtr        : spi_data = 0         : GoSub SPI_WRITE     'Set FIFO pointer address to 0
    spi_address = RegIrqFlagsMask       : spi_data = %10001111 : GoSub SPI_WRITE     'Set IRQ on RX_done, PayloadCrcErrorMask, ValidHeaderMask
    spi_address = RegModemConfig1       : spi_data = %00101001 : GoSub SPI_WRITE     'Set BW, 4/8, Implicit, 15.6kHz
    spi_address = RegModemConfig2       : spi_data = %10110100 : GoSub SPI_WRITE     'Set Spreading Factor 11, CRC on
    spi_address = RegSymbTimeoutLsb     : spi_data = %01100100 : GoSub SPI_WRITE     'Set SymbTimeout
    spi_address = RegDioMapping1        : spi_data = %00000000 : GoSub SPI_WRITE     'DIO0 = RX Done
    spi_address = RegPreambleMsb        : spi_data = 0         : GoSub SPI_WRITE     'Set Preamble
    spi_address = RegPreambleLsb        : spi_data = 18        : GoSub SPI_WRITE     'Set Preamble to 18 bits
    spi_address = RegSyncWord           : spi_data = %10001000 : GoSub SPI_WRITE     'Set Sync word
    spi_address = RegPayloadLength      : spi_data = 17        : GoSub SPI_WRITE     'Set Payload length to 17 bytes
    spi_address = RegMaxPayloadLength   : spi_data = 17        : GoSub SPI_WRITE     'Set Maximum payload length To 17 bytes
    spi_address = RegModemConfig3       : spi_data = %00001000 : GoSub SPI_WRITE     'Set AGC

    spi_address = RegAgcRefLf           : spi_data = %00011001 : GoSub SPI_WRITE
    spi_address = RegAgcThresh1Lf       : spi_data = %00001100 : GoSub SPI_WRITE
    spi_address = RegAgcThresh2Lf       : spi_data = %01001011 : GoSub SPI_WRITE
    spi_address = RegAgcThresh3Lf       : spi_data = %11001100 : GoSub SPI_WRITE
    spi_address = RegPllLf              : spi_data = %00010000 : GoSub SPI_WRITE

    spi_address = RegDetectOptimize     : spi_data = %01100011 : GoSub SPI_WRITE     'Set Errata
    spi_address = $36                   : spi_data = $03       : GoSub SPI_WRITE     'Set Errata
    spi_address = RegPaDac              : spi_data = $87       : GoSub SPI_WRITE     'Set High Power Settings

    spi_address = RegOpMode             : spi_data = %10001100 : GoSub SPI_WRITE     'Set LoRa mode FSRX MODE
    spi_address = RegOpMode             : spi_data = %10001101 : GoSub SPI_WRITE    'Set LoRa mode Cont RX MODE
  
    GoSub CLEAR_IRQ_RX
Return

CLEAR_IRQ_RX:
    spi_address = RegIrqFlags : spi_data = %11111111 : GoSub SPI_WRITE     'Clear IRQ
Return

RECEIVE_MESSAGE:
    While DIO0 = 0 : Wend
  
    spi_address = RegIrqFlags : GoSub SPI_READ
    If spi_data.6 = 0 Or spi_data.5 = 1 Or spi_data.4 = 0 Then
        GoSub CLEAR_IRQ_RX
        DelayMS 1
        GoTo RECEIVE_MESSAGE
    EndIf
  
    'Read SNR
    spi_address = RegPktSnrValue : GoSub SPI_READ
    SNR = spi_data
    fSNR = SNR / 4
    If fSNR < 0 Then SNR = 0
  
    'Read RSSI
    spi_address = RegPktRssiValue : GoSub SPI_READ
    RSSI = spi_data
    If fSNR >= 0 Then
        fRSSI = (1.06* RSSI) - 164
    Else
        fRSSI = (SNR / 4) + RSSI
        fRSSI = fRSSI - 164
    EndIf
  
    'Get the frequency offset for correction
    LoRaFeiValue = 0
    spi_address = RegFeiMsb : GoSub SPI_READ
    LoRaFeiValue.Byte2 = spi_data
    spi_address = RegFeiMid : GoSub SPI_READ
    LoRaFeiValue.Byte1 = spi_data
    spi_address = RegFeiLsb : GoSub SPI_READ
    LoRaFeiValue.Byte0 = spi_data
  
    'Get payload length
    spi_address = RegRxNbBytes : GoSub SPI_READ
    payload_len = spi_data
    'Start address of last packet received
    spi_address = RegFifoRxCurrentAddr : GoSub SPI_READ
    payload_add = spi_data
    'Set FIFO pointer address
    spi_address = RegFifoAddrPtr : spi_data = payload_add : GoSub SPI_WRITE  
    
    Low SEL : DelayCS 1
        spi_address = RegFifo
        temp_spi = spi_address
        temp_spi.7 = 0
        spi_byte = temp_spi : GoSub SPI_SEND
        Low MOSI

        For i = 0 To payload_len - 1
            GoSub SPI_RECEIVE
            payload[i] = spi_byte
        Next
    High SEL

    GoSub CLEAR_IRQ_RX
Return


'=================================================== SPI SUBS =====================================================================================
SPI_WRITE:
    Low SEL
        temp_spi = spi_address
        temp_spi.7 = 1
        spi_byte = temp_spi : GoSub SPI_SEND
        spi_byte = spi_data : GoSub SPI_SEND
    High SEL
Return

SPI_READ:
    Low SEL
        temp_spi = spi_address
        temp_spi.7 = 0
        spi_byte = temp_spi : GoSub SPI_SEND
        Low MOSI : GoSub SPI_RECEIVE : spi_data = spi_byte
    High SEL
Return

SPI_SEND:
    MOSI = spi_byte.7 : DelayCS 1 : High SCLK : DelayCS 1 : Low SCLK : DelayCS 1
    MOSI = spi_byte.6 : DelayCS 1 : High SCLK : DelayCS 1 : Low SCLK : DelayCS 1
    MOSI = spi_byte.5 : DelayCS 1 : High SCLK : DelayCS 1 : Low SCLK : DelayCS 1
    MOSI = spi_byte.4 : DelayCS 1 : High SCLK : DelayCS 1 : Low SCLK : DelayCS 1
    MOSI = spi_byte.3 : DelayCS 1 : High SCLK : DelayCS 1 : Low SCLK : DelayCS 1
    MOSI = spi_byte.2 : DelayCS 1 : High SCLK : DelayCS 1 : Low SCLK : DelayCS 1
    MOSI = spi_byte.1 : DelayCS 1 : High SCLK : DelayCS 1 : Low SCLK : DelayCS 1
    MOSI = spi_byte.0 : DelayCS 1 : High SCLK : DelayCS 1 : Low SCLK : DelayCS 1
Return

SPI_RECEIVE:
    High SCLK : DelayCS 1 : spi_byte.7 = MISO : DelayCS 1 : Low SCLK : DelayCS 1
    High SCLK : DelayCS 1 : spi_byte.6 = MISO : DelayCS 1 : Low SCLK : DelayCS 1
    High SCLK : DelayCS 1 : spi_byte.5 = MISO : DelayCS 1 : Low SCLK : DelayCS 1
    High SCLK : DelayCS 1 : spi_byte.4 = MISO : DelayCS 1 : Low SCLK : DelayCS 1
    High SCLK : DelayCS 1 : spi_byte.3 = MISO : DelayCS 1 : Low SCLK : DelayCS 1
    High SCLK : DelayCS 1 : spi_byte.2 = MISO : DelayCS 1 : Low SCLK : DelayCS 1
    High SCLK : DelayCS 1 : spi_byte.1 = MISO : DelayCS 1 : Low SCLK : DelayCS 1
    High SCLK : DelayCS 1 : spi_byte.0 = MISO : DelayCS 1 : Low SCLK : DelayCS 1
Return

top204

#15
Below, is the, preliminary, listing for the SX1278 library. I am still not getting long range, but it has improved a little. The library uses the compiler's HRsin4/HRsout4 and HSerin4/HSerout4, re-directed, commands, so the SX1278 acts just like a USART connection, with timeout and modifiers etc... It defaults to a software SPI interface, so will work on any 18F device. :-)

$ifndef _cSX_INC_
$define _cSX_INC_
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' SX1278 routines
' Written for the Positron8 compiler by Les Johnson
'
' The HRsout4 and HRsin4 and HSerin4 and HSerout4 commands are re-directed to transmit and receive data to and from the SX1278 module
'
    #Disable HRSIn4, HRsin4To, HRSOut4, HRSIn4_RCREG_Read ' Disable the compiler's HRsin4 and HRsout4 library routines

$define SX_cSoftSPI                             ' Uncomment for a hardware SPI interface
'
' Set the pins to use for the interface to the SX1278 device
'
$ifndef SX_SCK_Pin
    $define SX_SCK_Pin  PORTC.3                 ' Connects to the SX1278's SCK pin
    $SendWarning "SX_SCK_Pin missing from the main program. Using a default pin"
$endif
$ifndef SX_MISO_Pin
    $define SX_MISO_Pin PORTC.4                 ' Connects to the SX1278's MISO pin
    $SendWarning "SX_MISO_Pin missing from the main program. Using a default pin"
$endif
$ifndef SX_MOSI_Pin
    $define SX_MOSI_Pin PORTC.5                 ' Connects to the SX1278's MOSI pin
    $SendWarning "SX_MOSI_Pin missing from the main program. Using a default pin"
$endif
$ifndef SX_NSS_Pin
    $define SX_NSS_Pin  PORTC.1                 ' Connects to the SX1278's NSS pin
    $SendWarning "SX_NSS_Pin missing from the main program. Using a default pin"
$endif
$ifndef SX_RST_Pin
    $define SX_RST_Pin  PORTC.0                 ' Connects to the SX1278's RST pin
    $SendWarning "SX_RST_Pin missing from the main program. Using a default pin"
$endif

$ifndef SX_DIO0_Pin
    $define SX_DIO0_Pin PORTA.0                 ' Connects to the SX1278's DIO0 pin (Used as an IRQ for received data)
    $SendWarning "SX_DIO0_Pin missing from the main program. Using a default pin"
$endif

'$ifndef SX_DIO1_Pin
'    $define SX_DIO1_Pin PORTA.1                 ' Connects to the SX1278's DIO1 Pin
'$endif
'$ifndef SX_DIO2_Pin
'    $define SX_DIO2_Pin PORTA.2                 ' Connects to the SX1278's DIO2 Pin
'$endif
'$ifndef SX_DIO3_Pin
'    $define SX_DIO3_Pin PORTA.3                 ' Connects to the SX1278's DIO3 Pin
'$endif
'$ifndef SX_DIO4_Pin
'    $define SX_DIO4_Pin PORTA.4                 ' Connects to the SX1278's DIO4 Pin
'$endif
'
' SX127x physical layer properties
'
$define cSX_FREQUENCY_STEP_SIZE                    61.03515625
$define cSX_MAX_PACKET_LENGTH                      255
$define cSX_MAX_PACKET_LENGTH_FSK                  64
$define cSX_CRYSTAL_FREQ                           32.0
$define cSX_DIV_EXPONENT                           19
'
' SX127x series common LoRa registers
'
$define cSX_REG_FIFO                               $00
$define cSX_REG_OP_MODE                            $01
$define cSX_REG_FRF_MSB                            $06
$define cSX_REG_FRF_MID                            $07
$define cSX_REG_FRF_LSB                            $08
$define cSX_REG_PA_CONFIG                          $09
$define cSX_REG_PA_RAMP                            $0A
$define cSX_REG_OCP                                $0B
$define cSX_REG_LNA                                $0C
$define cSX_REG_FIFO_ADDR_PTR                      $0D
$define cSX_REG_FIFO_TX_BASE_ADDR                  $0E
$define cSX_REG_FIFO_RX_BASE_ADDR                  $0F
$define cSX_REG_FIFO_RX_CURRENT_ADDR               $10
$define cSX_REG_IRQ_FLAGS_MASK                     $11
$define cSX_REG_IRQ_FLAGS                          $12
$define cSX_REG_RX_NB_BYTES                        $13
$define cSX_REG_RX_HEADER_CNT_VALUE_MSB            $14
$define cSX_REG_RX_HEADER_CNT_VALUE_LSB            $15
$define cSX_REG_RX_PACKET_CNT_VALUE_MSB            $16
$define cSX_REG_RX_PACKET_CNT_VALUE_LSB            $17
$define cSX_REG_MODEM_STAT                         $18
$define cSX_REG_PKT_SNR_VALUE                      $19
$define cSX_REG_PKT_RSSI_VALUE                     $1A
$define cSX_REG_RSSI_VALUE                         $1B
$define cSX_REG_HOP_CHANNEL                        $1C
$define cSX_REG_MODEM_CONFIG_1                     $1D
$define cSX_REG_MODEM_CONFIG_2                     $1E
$define cSX_REG_SYMB_TIMEOUT_LSB                   $1F
$define cSX_REG_PREAMBLE_MSB                       $20
$define cSX_REG_PREAMBLE_LSB                       $21
$define cSX_REG_PAYLOAD_LENGTH                     $22
$define cSX_REG_MAX_PAYLOAD_LENGTH                 $23
$define cSX_REG_HOP_PERIOD                         $24
$define cSX_REG_FIFO_RX_BYTE_ADDR                  $25
$define cSX_REG_FEI_MSB                            $28
$define cSX_REG_FEI_MID                            $29
$define cSX_REG_FEI_LSB                            $2A
$define cSX_REG_RSSI_WIDEBAND                      $2C
$define cSX_REG_DETECT_OPTIMISE                    $31
$define cSX_REG_INVERT_IQ                          $33
$define cSX_REG_DETECTION_THRESHOLD                $37
$define cSX_REG_SYNC_WORD                          $39
$define cSX_REG_INVERT_IQ2                         $3B
$define cSX_REG_DIO_MAPPING_1                      $40
$define cSX_REG_DIO_MAPPING_2                      $41
$define cSX_REG_VERSION                            $42

$define cSX_REG_TCXO                               $4B
$define cSX_REG_PA_DAC                             $4D
'
' cSX_REG_OP_MODE
'
' LoRa or FSK Mode (bit 7 of register cSX_REG_OP_MODE) (Address $00)
' This bit can be modified only in Sleep mode. A write operation on other device modes is ignored
'
$define cSX_FSK_OOK_MODE                           %00000000  ' FSK/OOK Mode
$define cSX_LORA_MODE                              %10000000  ' LoRa Mode
'
' Modulation Type (bits 5 and 6 of register cSX_REG_OP_MODE)
'
$define cSX_MODULATION_FSK                         %00000000  ' FSK modulation
$define cSX_MODULATION_OOK                         %00100000  ' OOK modulation
'
' Low Frequency Mode (bit 3 of register cSX_REG_OP_MODE)
' Access Low Frequency Mode registers (from address $61 on)
'
$define cSX_HIGH_FREQUENCY_MODE                    %00000000  ' High Frequency Mode (access to HF test registers)
$define cSX_LOW_FREQUENCY_MODE                     %00001000  ' Low Frequency Mode (access to LF test registers)
'
' Transceiver modes (Bits 0 to 2 of register cSX_REG_OP_MODE)
'
$define cSX_SLEEP_MODE                             %00000000  ' Sleep mode
$define cSX_STANDBY_MODE                           %00000001  ' Stdby mode
$define cSX_FS_TX_MODE                             %00000010  ' FS mode TX (FSTx)
$define cSX_TX_MODE                                %00000011  ' Transmitter mode (Tx)
$define cSX_FS_RX_MODE                             %00000100  ' FS mode RX (FSRx)
$define cSX_RX_MODE                                %00000101  ' Receiver mode (Rx)
'
' cSX_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB
'
$define cSX_FRF_MSB                                $6C        ' Carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19
$define cSX_FRF_MID                                $80        ' Where F(XOSC) = 32 MHz
$define cSX_FRF_LSB                                $00        ' FRF = 3 byte value of FRF registers
'
' cSX_REG_LNA
'
$define cSX_LNA_BOOST_LF_OFF                       %00000000  ' Default LNA current
'
' cSX_REG_MODEM_CONFIG_1
'
$define cSX_BW_7_80_KHZ                            %00000000  ' Bandwidth: 7.80 kHz
$define cSX_BW_10_40_KHZ                           %00010000  ' Bandwidth: 10.40 kHz
$define cSX_BW_15_60_KHZ                           %00100000  ' Bandwidth: 15.60 kHz
$define cSX_BW_20_80_KHZ                           %00110000  ' Bandwidth: 20.80 kHz
$define cSX_BW_31_25_KHZ                           %01000000  ' Bandwidth: 31.25 kHz
$define cSX_BW_41_70_KHZ                           %01010000  ' Bandwidth: 41.70 kHz
$define cSX_BW_62_50_KHZ                           %01100000  ' Bandwidth: 62.50 kHz
$define cSX_BW_125_00_KHZ                          %01110000  ' Bandwidth: 125.00 kHz
$define cSX_BW_250_00_KHZ                          %10000000  ' Bandwidth: 250.00 kHz
$define cSX_BW_500_00_KHZ                          %10010000  ' Bandwidth: 500.00 kHz
$define cSX_CR_4_5                                 %00000010  ' Error coding rate: 4/5
$define cSX_CR_4_6                                 %00000100  ' Error coding rate: 4/6
$define cSX_CR_4_7                                 %00000110  ' Error coding rate: 4/7
$define cSX_CR_4_8                                 %00001000  ' Error coding rate: 4/8
$define cSX_HEADER_EXPL_MODE                       %00000000  ' Explicit header mode
$define cSX_HEADER_IMPL_MODE                       %00000001  ' Implicit header mode
'
' cSX_REG_MODEM_CONFIG_2
'
$define cSX_RX_CRC_MODE_OFF                        %00000000  ' CRC disabled
$define cSX_RX_CRC_MODE_ON                         %00000100  ' CRC enabled
'
' cSX_REG_MODEM_CONFIG_3
'
$define cSX_LOW_DATA_RATE_OPT_OFF                  %00000000  ' low data rate optimization disabled
$define cSX_LOW_DATA_RATE_OPT_ON                   %00001000  ' low data rate optimization enabled
$define cSX_AGC_AUTO_OFF                           %00000000  ' LNA gain set by REG_LNA
$define cSX_AGC_AUTO_ON                            %00000100  ' LNA gain set by internal AGC loop
'
' cSX_REG_OP_MODE
'
$define cSX_FSK_OOK                                %00000000  ' FSK/OOK mode
$define cSX_LORA                                   %10000000  ' LoRa mode
$define cSX_ACCESS_SHARED_REG_OFF                  %00000000  ' Access LoRa registers ($0D:$3F) in LoRa mode
$define cSX_ACCESS_SHARED_REG_ON                   %01000000  ' Access FSK registers ($0D:$3F) in LoRa mode
$define cSX_SLEEP                                  %00000000  ' Sleep
$define cSX_STANDBY                                %00000001  ' Standby
$define cSX_FSTX                                   %00000010  ' Frequency synthesis TX
$define cSX_TX                                     %00000011  ' Transmit
$define cSX_FSRX                                   %00000100  ' Frequency synthesis RX
$define cSX_RXCONTINUOUS                           %00000101  ' Receive continuous
$define cSX_RXSINGLE                               %00000110  ' Receive single
$define cSX_CAD                                    %00000111  ' Channel activity detection
'
' Bits to use in the cSX_REG_PA_CONFIG register with ORing (Register address $09)
'
$define cSX_USE_RFO_PIN                            %00000000  ' Use the RFO pin. Maximum power of +14 dBm Bit-7 of the cSX_REG_PA_CONFIG register.
$define cSX_USE_PA_BOOST_PIN                       %10000000  ' Use the PA_BOOST pin. Maximum power of +20 dBm  Bit-7 of the cSX_REG_PA_CONFIG register.
'
' Select max output power: Pmax=10.8+0.6*MaxPower [dBm] (Bits 4 to 6 of the cSX_REG_PA_CONFIG register)
'
$define cSX_MAX_POWER0                             %00000000   ' Set the Max Power to 0
$define cSX_MAX_POWER1                             %00010000   ' Set the Max Power to 1
$define cSX_MAX_POWER2                             %00100000   ' Set the Max Power to 2
$define cSX_MAX_POWER3                             %00110000   ' Set the Max Power to 3
$define cSX_MAX_POWER4                             %01000000   ' Set the Max Power to 4
$define cSX_MAX_POWER5                             %01010000   ' Set the Max Power to 5
$define cSX_MAX_POWER6                             %01100000   ' Set the Max Power to 6
$define cSX_MAX_POWER7                             %01110000   ' Set the Max Power to 7
'
' Pout = Pmax-(15-OutputPower) if PaSelect = 0 (RFO pins)
' Pout = 17-(15-OutputPower) if PaSelect = 1 (PA_BOOST pin)
'
$define cSX_OUTPUT_POWER0                          %00000000  ' Set the Output Power to 0
$define cSX_OUTPUT_POWER1                          %00000001  ' Set the Output Power to 1
$define cSX_OUTPUT_POWER2                          %00000010  ' Set the Output Power to 2
$define cSX_OUTPUT_POWER3                          %00000011  ' Set the Output Power to 3
$define cSX_OUTPUT_POWER4                          %00000100  ' Set the Output Power to 4
$define cSX_OUTPUT_POWER5                          %00000101  ' Set the Output Power to 5
$define cSX_OUTPUT_POWER6                          %00000110  ' Set the Output Power to 6
$define cSX_OUTPUT_POWER7                          %00000111  ' Set the Output Power to 7
$define cSX_OUTPUT_POWER8                          %00001000  ' Set the Output Power to 8
$define cSX_OUTPUT_POWER9                          %00001001  ' Set the Output Power to 9
$define cSX_OUTPUT_POWER10                         %00001010  ' Set the Output Power to 10
$define cSX_OUTPUT_POWER11                         %00001011  ' Set the Output Power to 11
$define cSX_OUTPUT_POWER12                         %00001100  ' Set the Output Power to 12
$define cSX_OUTPUT_POWER13                         %00001101  ' Set the Output Power to 13
$define cSX_OUTPUT_POWER14                         %00001110  ' Set the Output Power to 14
$define cSX_OUTPUT_POWER15                         %00001111  ' Set the Output Power to 15

$define cSX_PA_SELECT_RFO                          %00000000  ' RFO pin output, power limited to +14 dBm
$define cSX_OUTPUT_POWER                           %00001111  ' Output power: P_out = 2 + OUTPUT_POWER [dBm] for PA_SELECT_BOOST
'                                                               P_out = -1 + OUTPUT_POWER [dBm] for PA_SELECT_RFO
' cSX_REG_OCP
'
$define cSX_OCP_OFF                                %00000000  ' PA overload current protection disabled
$define cSX_OCP_ON                                 %00100000  ' PA overload current protection enabled
$define cSX_OCP_TRIM                               %00001011  ' OCP current: I_max(OCP_TRIM = %1011) = 100 mA
'
' cSX_REG_LNA
'
$define cSX_LNA_GAIN_1                             %00100000  ' LNA gain setting:   max gain
$define cSX_LNA_GAIN_2                             %01000000  '                     .
$define cSX_LNA_GAIN_3                             %01100000  '                     .
$define cSX_LNA_GAIN_4                             %10000000  '                     .
$define cSX_LNA_GAIN_5                             %10100000  '                     .
$define cSX_LNA_GAIN_6                             %11000000  '                     min gain
$define cSX_LNA_BOOST_OFF                          %00000000  ' Default LNA current
$define cSX_LNA_BOOST_ON                           %00000011  ' 150% LNA current
'
' cSX_REG_MODEM_CONFIG_2
'
$define cSX_SF_6                                   %01100000  ' Spreading factor:   64 chips/bit
$define cSX_SF_7                                   %01110000  '                     128 chips/bit
$define cSX_SF_8                                   %10000000  '                     256 chips/bit
$define cSX_SF_9                                   %10010000  '                     512 chips/bit
$define cSX_SF_10                                  %10100000  '                     1024 chips/bit
$define cSX_SF_11                                  %10110000  '                     2048 chips/bit
$define cSX_SF_12                                  %11000000  '                     4096 chips/bit
$define cSX_TX_MODE_SINGLE                         %00000000  ' Single TX
$define cSX_TX_MODE_CONT                           %00001000  ' Continuous TX
$define cSX_RX_TIMEOUT_MSB                         %00000000
'
' cSX_REG_SYMB_TIMEOUT_LSB
'
$define cSX_RX_TIMEOUT_LSB                         %01100100  ' 10 bit RX operation timeout
'
' cSX_REG_PREAMBLE_MSB + REG_PREAMBLE_LSB
'
$define cSX_PREAMBLE_LENGTH_MSB                    %00000000  ' 2 byte preamble length setting: l_P = PREAMBLE_LENGTH + 4.25
$define cSX_PREAMBLE_LENGTH_LSB                    %00001000  ' Where l_p = preamble length
'
' cSX_REG_DETECT_OPTIMISE
'
$define cSX_DETECT_OPTIMISE_SF_6                   %00000101  ' SF6 detection optimization
$define cSX_DETECT_OPTIMISE_SF_7_12                %00000011  ' SF7 to SF12 detection optimization
'
' cSX_REG_INVERT_IQ
'
$define cSX_INVERT_IQ_RXPATH_ON                    %01000000  ' I and Q signals are inverted
$define cSX_INVERT_IQ_RXPATH_OFF                   %00000000  ' Normal mode
$define cSX_INVERT_IQ_TXPATH_ON                    %00000001  ' I and Q signals are inverted
$define cSX_INVERT_IQ_TXPATH_OFF                   %00000000  ' Normal mode
'
' cSX_REG_DETECTION_THRESHOLD
'
$define cSX_DETECTION_THRESHOLD_SF_6               %00001100  ' SF6 detection threshold
$define cSX_DETECTION_THRESHOLD_SF_7_12            %00001010  ' SF7 to SF12 detection threshold
'
' cSX_REG_PA_CONFIG
'
$define cSX_PA_BOOST_OFF                           %00000100  ' PA_BOOST disabled
$define cSX_PA_BOOST_ON                            %00000111  ' +20 dBm on PA_BOOST when Output_Power = %1111
'
' cSX_REG_HOP_PERIOD
'
$define cSX_HOP_PERIOD_OFF                         %00000000  ' Number of periods between frequency hops; 0 = disabled
$define cSX_HOP_PERIOD_MAX                         %11111111
'
' cSX_REG_DIO_MAPPING_1
'
$define cSX_DIO0_RX_DONE                           %00000000
$define cSX_DIO0_TX_DONE                           %01000000
$define cSX_DIO0_CAD_DONE                          %10000000
$define cSX_DIO1_RX_TIMEOUT                        %00000000
$define cSX_DIO1_FHSS_CHANGE_CHANNEL               %00010000
$define cSX_DIO1_CAD_DETECTED                      %00100000
'
' cSX_REG_IRQ_FLAGS
'
$define cSX_CLEAR_IRQ_FLAG_RX_TIMEOUT              %10000000  ' Timeout
$define cSX_CLEAR_IRQ_FLAG_RX_DONE                 %01000000  ' Packet reception complete
$define cSX_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR       %00100000  ' Payload CRC error
$define cSX_CLEAR_IRQ_FLAG_VALID_HEADER            %00010000  ' Valid header received
$define cSX_CLEAR_IRQ_FLAG_TX_DONE                 %00001000  ' Payload transmission complete
$define cSX_CLEAR_IRQ_FLAG_CAD_DONE                %00000100  ' CAD complete
$define cSX_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL     %00000010  ' FHSS change channel
$define cSX_CLEAR_IRQ_FLAG_CAD_DETECTED            %00000001  ' Valid LoRa signal detected during CAD operation
'
' cSX_REG_IRQ_FLAGS_MASK
'
$define cSX_MASK_IRQ_FLAG_RX_TIMEOUT               %01111111  ' Timeout
$define cSX_MASK_IRQ_FLAG_RX_DONE                  %10111111  ' Packet reception complete
$define cSX_MASK_IRQ_FLAG_PAYLOAD_CRC_ERROR        %11011111  ' Payload CRC error
$define cSX_MASK_IRQ_FLAG_VALID_HEADER             %11101111  ' Valid header received
$define cSX_MASK_IRQ_FLAG_TX_DONE                  %11110111  ' Payload transmission complete
$define cSX_MASK_IRQ_FLAG_CAD_DONE                 %11111011  ' CAD complete
$define cSX_MASK_IRQ_FLAG_FHSS_CHANGE_CHANNEL      %11111101  ' FHSS change channel
$define cSX_MASK_IRQ_FLAG_CAD_DETECTED             %11111110  ' Valid LoRa signal detected during CAD operation
'
' cSX_REG_FIFO_TX_BASE_ADDR
'
$define cSX_FIFO_TX_BASE_ADDR_MAX                  %00000000  ' Allocate the entire FIFO buffer for TX only
'
' cSX_REG_FIFO_RX_BASE_ADDR
'
$define cSX_FIFO_RX_BASE_ADDR_MAX                  %00000000  ' Allocate the entire FIFO buffer for RX only
'
' cSX_REG_SYNC_WORD
'
$define cSX_SYNC_WORD                              $12        ' Default LoRa sync word
$define cSX_SYNC_WORD_LORAWAN                      $34        ' Sync word reserved for LoRaWAN networks
'
' cSX_REG_INVERT_IQ2
'
$define cSX_IQ2_ENABLE                             $19        ' Enable optimize for inverted IQ
$define cSX_IQ2_DISABLE                            $1D        ' Reset optimize for inverted IQ
'
' Common FSK registers
' Note: FSK register names that are conflicting with LoRa registers are marked with "_FSK"
'
$define cSX_REG_BITRATE_MSB                        $02
$define cSX_REG_BITRATE_LSB                        $03
$define cSX_REG_FDEV_MSB                           $04
$define cSX_REG_FDEV_LSB                           $05
$define cSX_REG_RX_CONFIG                          $0D
$define cSX_REG_RSSI_CONFIG                        $0E
$define cSX_REG_RSSI_COLLISION                     $0F
$define cSX_REG_RSSI_THRESH                        $10
$define cSX_REG_RSSI_VALUE_FSK                     $11
$define cSX_REG_RX_BW                              $12
$define cSX_REG_AFC_BW                             $13
$define cSX_REG_OOK_PEAK                           $14
$define cSX_REG_OOK_FIX                            $15
$define cSX_REG_OOK_AVG                            $16
$define cSX_REG_AFC_FEI                            $1A
$define cSX_REG_AFC_MSB                            $1B
$define cSX_REG_AFC_LSB                            $1C
$define cSX_REG_FEI_MSB_FSK                        $1D
$define cSX_REG_FEI_LSB_FSK                        $1E
$define cSX_REG_PREAMBLE_DETECT                    $1F
$define cSX_REG_RX_TIMEOUT_1                       $20
$define cSX_REG_RX_TIMEOUT_2                       $21
$define cSX_REG_RX_TIMEOUT_3                       $22
$define cSX_REG_RX_DELAY                           $23
$define cSX_REG_OSC                                $24
$define cSX_REG_PREAMBLE_MSB_FSK                   $25
$define cSX_REG_PREAMBLE_LSB_FSK                   $26
$define cSX_REG_SYNC_CONFIG                        $27
$define cSX_REG_SYNC_VALUE_1                       $28
$define cSX_REG_SYNC_VALUE_2                       $29
$define cSX_REG_SYNC_VALUE_3                       $2A
$define cSX_REG_SYNC_VALUE_4                       $2B
$define cSX_REG_SYNC_VALUE_5                       $2C
$define cSX_REG_SYNC_VALUE_6                       $2D
$define cSX_REG_SYNC_VALUE_7                       $2E
$define cSX_REG_SYNC_VALUE_8                       $2F
$define cSX_REG_PACKET_CONFIG_1                    $30
$define cSX_REG_PACKET_CONFIG_2                    $31
$define cSX_REG_PAYLOAD_LENGTH_FSK                 $32
$define cSX_REG_NODE_ADRS                          $33
$define cSX_REG_BROADCAST_ADRS                     $34
$define cSX_REG_FIFO_THRESH                        $35
$define cSX_REG_SEQ_CONFIG_1                       $36
$define cSX_REG_SEQ_CONFIG_2                       $37
$define cSX_REG_TIMER_RESOL                        $38
$define cSX_REG_TIMER1_COEF                        $39
$define cSX_REG_TIMER2_COEF                        $3A
$define cSX_REG_IMAGE_CAL                          $3B
$define cSX_REG_TEMP                               $3C
$define cSX_REG_LOW_BAT                            $3D
$define cSX_REG_IRQ_FLAGS_1                        $3E
$define cSX_REG_IRQ_FLAGS_2                        $3F
'
' Modes
'
$define cSX_MODE_LONG_RANGE_MODE                  %10000000
$define cSX_MODE_SLEEP                            %00000000
$define cSX_MODE_STDBY                            %00000001
$define cSX_MODE_TX                               %00000011
$define cSX_MODE_RX_CONTINUOUS                    %00000101
$define cSX_MODE_RX_SINGLE                        %00000110
'
' cSX_REG_OP_MODE
'
$define cSX_MODULATION_FSK                         %00000000  ' FSK modulation scheme
$define cSX_MODULATION_OOK                         %00100000  ' OOK modulation scheme
$define cSX_RX                                     %00000101  ' Receiver mode
'
' cSX_REG_BITRATE_MSB + cSX_REG_BITRATE_LSB
'
$define cSX_BITRATE_MSB                            $1A        ' Bit rate setting: BitRate = F(XOSC)/(BITRATE + BITRATE_FRAC/16)
$define cSX_BITRATE_LSB                            $0B        '                   Default value: 4.8 kbps
'
' cSX_REG_FDEV_MSB + cSX_REG_FDEV_LSB
'
$define cSX_FDEV_MSB                               $00        ' Frequency deviation: Fdev = Fstep * FDEV
$define cSX_FDEV_LSB                               $52        '                      default value: 5 kHz
'
' cSX_REG_RX_CONFIG
'
$define cSX_RESTART_RX_ON_COLLISION_OFF            %00000000  ' Automatic receiver restart disabled (default)
$define cSX_RESTART_RX_ON_COLLISION_ON             %10000000  ' Automatically restart receiver if it gets saturated or on packet collision
$define cSX_RESTART_RX_WITHOUT_PLL_LOCK            %01000000  ' Manually restart receiver without frequency change
$define cSX_RESTART_RX_WITH_PLL_LOCK               %00100000  ' Manually restart receiver with frequency change
$define cSX_AFC_AUTO_OFF                           %00000000  ' No AFC performed (default)
$define cSX_AFC_AUTO_ON                            %00010000  ' AFC performed at each receiver startup
$define cSX_AGC_AUTO_OFF                           %00000000  ' LNA gain set manually by register
$define cSX_AGC_AUTO_ON                            %00001000  ' LNA gain controlled by AGC
$define cSX_RX_TRIGGER_NONE                        %00000000  ' Receiver startup at: none
$define cSX_RX_TRIGGER_RSSI_INTERRUPT              %00000001  '                      RSSI interrupt
$define cSX_RX_TRIGGER_PREAMBLE_DETECT             %00000110  '                      preamble detected
$define cSX_RX_TRIGGER_BOTH                        %00000111  '                      RSSI interrupt and preamble detected
'
' cSX_REG_RSSI_CONFIG
'
$define cSX_RSSI_SMOOTHING_SAMPLES_2               %00000000  ' Number of samples for RSSI average: 2
$define cSX_RSSI_SMOOTHING_SAMPLES_4               %00000001  '                                     4
$define cSX_RSSI_SMOOTHING_SAMPLES_8               %00000010  '                                     8 (default)
$define cSX_RSSI_SMOOTHING_SAMPLES_16              %00000011  '                                     16
$define cSX_RSSI_SMOOTHING_SAMPLES_32              %00000100  '                                     32
$define cSX_RSSI_SMOOTHING_SAMPLES_64              %00000101  '                                     64
$define cSX_RSSI_SMOOTHING_SAMPLES_128             %00000110  '                                     128
$define cSX_RSSI_SMOOTHING_SAMPLES_256             %00000111  '                                     256
'
' cSX_REG_RSSI_COLLISION
'
$define cSX_RSSI_COLLISION_THRESHOLD               $0A        ' RSSI threshold in dB that will be considered a collision, default value: 10 dB
'
' cSX_REG_RSSI_THRESH
'
$define cSX_RSSI_THRESHOLD                         $FF        ' RSSI threshold that will trigger RSSI interrupt, RssiThreshold = RSSI_THRESHOLD / 2 [dBm]
'
' cSX_REG_RX_BW
'
$define cSX_RX_BW_MANT_16                          %00000000  ' Channel filter bandwidth: RxBw = F(XOSC) / (RxBwMant * 2^(RxBwExp + 2)) [kHz]
$define cSX_RX_BW_MANT_20                          %00001000  '
$define cSX_RX_BW_MANT_24                          %00010000  ' Default RxBwMant parameter
$define cSX_RX_BW_EXP                              %00000101  ' Default RxBwExp parameter
'
' cSX_REG_AFC_BW
'
$define cSX_RX_BW_MANT_AFC                         %00001000  ' Default RxBwMant parameter used during AFC
$define cSX_RX_BW_EXP_AFC                          %00000011  ' Default RxBwExp parameter used during AFC
'
' cSX_REG_OOK_PEAK
 '
$define cSX_BIT_SYNC_OFF                           %00000000  ' Bit synchronizer disabled (not allowed in packet mode)
$define cSX_BIT_SYNC_ON                            %00100000  ' Bit synchronizer enabled (default)
$define cSX_OOK_THRESH_FIXED                       %00000000  ' OOK threshold type: fixed value
$define cSX_OOK_THRESH_PEAK                        %00001000  '                          peak mode (default)
$define cSX_OOK_THRESH_AVERAGE                     %00010000  '                          average mode
$define cSX_OOK_PEAK_THRESH_STEP_0_5_DB            %00000000  ' OOK demodulator step size: 0.5 dB (default)
$define cSX_OOK_PEAK_THRESH_STEP_1_0_DB            %00000001  '                            1.0 dB
$define cSX_OOK_PEAK_THRESH_STEP_1_5_DB            %00000010  '                            1.5 dB
$define cSX_OOK_PEAK_THRESH_STEP_2_0_DB            %00000011  '                            2.0 dB
$define cSX_OOK_PEAK_THRESH_STEP_3_0_DB            %00000100  '                            3.0 dB
$define cSX_OOK_PEAK_THRESH_STEP_4_0_DB            %00000101  '                            4.0 dB
$define cSX_OOK_PEAK_THRESH_STEP_5_0_DB            %00000110  '                            5.0 dB
$define cSX_OOK_PEAK_THRESH_STEP_6_0_DB            %00000111  '                            6.0 dB
'
' cSX_REG_OOK_FIX
'
$define cSX_OOK_FIXED_THRESHOLD                    $0C        ' Default fixed threshold for OOK data slicer
'
' cSX_REG_OOK_AVG
'
$define cSX_OOK_PEAK_THRESH_DEC_1_1_CHIP           %00000000  ' OOK demodulator step period: once per chip (default)
$define cSX_OOK_PEAK_THRESH_DEC_1_2_CHIP           %00100000  '                              once every 2 chips
$define cSX_OOK_PEAK_THRESH_DEC_1_4_CHIP           %01000000  '                              once every 4 chips
$define cSX_OOK_PEAK_THRESH_DEC_1_8_CHIP           %01100000  '                              once every 8 chips
$define cSX_OOK_PEAK_THRESH_DEC_2_1_CHIP           %10000000  '                              2 times per chip
$define cSX_OOK_PEAK_THRESH_DEC_4_1_CHIP           %10100000  '                              4 times per chip
$define cSX_OOK_PEAK_THRESH_DEC_8_1_CHIP           %11000000  '                              8 times per chip
$define cSX_OOK_PEAK_THRESH_DEC_16_1_CHIP          %11100000  '                              16 times per chip
$define cSX_OOK_AVERAGE_OFFSET_0_DB                %00000000  ' OOK average threshold offset: 0.0 dB (default)
$define cSX_OOK_AVERAGE_OFFSET_2_DB                %00000100  '                               2.0 dB
$define cSX_OOK_AVERAGE_OFFSET_4_DB                %00001000  '                               4.0 dB
$define cSX_OOK_AVERAGE_OFFSET_6_DB                %00001100  '                               6.0 dB
$define cSX_OOK_AVG_THRESH_FILT_32_PI              %00000000  ' OOK average filter coefficient: chip rate / 32*pi
$define cSX_OOK_AVG_THRESH_FILT_8_PI               %00000001  '                                 chip rate / 8*pi
$define cSX_OOK_AVG_THRESH_FILT_4_PI               %00000010  '                                 chip rate / 4*pi (default)
$define cSX_OOK_AVG_THRESH_FILT_2_PI               %00000011  '                                 chip rate / 2*pi
'
' cSX_REG_AFC_FEI
'
$define cSX_AGC_START                              %00010000  ' Manually start AGC sequence
$define cSX_AFC_CLEAR                              %00000010  ' Manually clear AFC register
$define cSX_AFC_AUTO_CLEAR_OFF                     %00000000  ' AFC register will not be cleared at the start of AFC (default)
$define cSX_AFC_AUTO_CLEAR_ON                      %00000001  ' AFC register will be cleared at the start of AFC
'
' cSX_REG_PREAMBLE_DETECT
'
$define cSX_PREAMBLE_DETECTOR_OFF                  %00000000  ' Preamble detection disabled
$define cSX_PREAMBLE_DETECTOR_ON                   %10000000  ' Preamble detection enabled (default)
$define cSX_PREAMBLE_DETECTOR_1_BYTE               %00000000  ' Preamble detection size: 1 byte (default)
$define cSX_PREAMBLE_DETECTOR_2_BYTE               %00100000  '                          2 bytes
$define cSX_PREAMBLE_DETECTOR_3_BYTE               %01000000  '                          3 bytes
$define cSX_PREAMBLE_DETECTOR_TOL                  $0A        ' Default number of tolerated errors per chip (4 chips per bit)
'
' cSX_REG_RX_TIMEOUT_1
'
$define cSX_TIMEOUT_RX_RSSI_OFF                    $00        ' Disable receiver timeout when RSSI interrupt doesn't occur (default)
'
' cSX_REG_RX_TIMEOUT_2
'
$define cSX_TIMEOUT_RX_PREAMBLE_OFF                $00        ' Disable receiver timeout when preamble interrupt doesn't occur (default)
'
' cSX_REG_RX_TIMEOUT_3
'
$define cSX_TIMEOUT_SIGNAL_SYNC_OFF                $00        ' Disable receiver timeout when sync address interrupt doesn't occur (default)
'
' cSX_REG_OSC
'
$define cSX_RC_CAL_START                           %00000000  ' Manually start RC oscillator calibration
$define cSX_CLK_OUT_FXOSC                          %00000000  ' ClkOut frequency: F(XOSC)
$define cSX_CLK_OUT_FXOSC_2                        %00000001  '                   F(XOSC) / 2
$define cSX_CLK_OUT_FXOSC_4                        %00000010  '                   F(XOSC) / 4
$define cSX_CLK_OUT_FXOSC_8                        %00000011  '                   F(XOSC) / 8
$define cSX_CLK_OUT_FXOSC_16                       %00000100  '                   F(XOSC) / 16
$define cSX_CLK_OUT_FXOSC_32                       %00000101  '                   F(XOSC) / 32
$define cSX_CLK_OUT_RC                             %00000110  '                   RC
$define cSX_CLK_OUT_OFF                            %00000111  '                   disabled (default)
'
' cSX_REG_PREAMBLE_MSB_FSK + cSX_REG_PREAMBLE_LSB_FSK
'
$define cSX_PREAMBLE_SIZE_MSB                      $00        ' Preamble size in bytes
$define cSX_PREAMBLE_SIZE_LSB                      $03        ' Default value: 3 bytes
'
' cSX_REG_SYNC_CONFIG
'
$define cSX_AUTO_RESTART_RX_MODE_OFF               %00000000  ' Rx mode restart after packet reception: disabled
$define cSX_AUTO_RESTART_RX_MODE_NO_PLL            %01000000  '                                         enabled, don't wait for PLL lock
$define cSX_AUTO_RESTART_RX_MODE_PLL               %10000000  '                                         enabled, wait for PLL lock (default)
$define cSX_PREAMBLE_POLARITY_AA                   %00000000  ' Preamble polarity: $AA = %10101010 (default)
$define cSX_PREAMBLE_POLARITY_55                   %00100000  '                   $55 = %01010101
$define cSX_SYNC_OFF                               %00000000  ' Sync word disabled
$define cSX_SYNC_ON                                %00010000  ' Sync word enabled (default)
$define cSX_SYNC_SIZE                              $03        ' Sync word size in bytes, SyncSize = SYNC_SIZE + 1 bytes
'
' cSX_REG_SYNC_VALUE_1 - cSX_REG_SYNC_VALUE_8
'
$define cSX_SYNC_VALUE_1                           $01        ' Sync word: 1st byte (MSB)
$define cSX_SYNC_VALUE_2                           $01        '            2nd byte
$define cSX_SYNC_VALUE_3                           $01        '            3rd byte
$define cSX_SYNC_VALUE_4                           $01        '            4th byte
$define cSX_SYNC_VALUE_5                           $01        '            5th byte
$define cSX_SYNC_VALUE_6                           $01        '            6th byte
$define cSX_SYNC_VALUE_7                           $01        '            7th byte
$define cSX_SYNC_VALUE_8                           $01        '            8th byte (LSB)
'
' cSX_REG_PACKET_CONFIG_1
'
$define cSX_PACKET_FIXED                           %00000000  ' Packet format: fixed length
$define cSX_PACKET_VARIABLE                        %10000000  '                variable length (default)
$define cSX_DC_FREE_NONE                           %00000000  ' DC-free encoding: disabled (default)
$define cSX_DC_FREE_MANCHESTER                     %00100000  '                   Manchester
$define cSX_DC_FREE_WHITENING                      %01000000  '                   Whitening
$define cSX_CRC_OFF                                %00000000  ' CRC disabled
$define cSX_CRC_ON                                 %00010000  ' CRC enabled (default)
$define cSX_CRC_AUTOCLEAR_OFF                      %00001000  '      Keep FIFO on CRC mismatch, issue payload ready interrupt
$define cSX_CRC_AUTOCLEAR_ON                       %00000000  '      Clear FIFO on CRC mismatch, do not issue payload ready interrupt
$define cSX_ADDRESS_FILTERING_OFF                  %00000000  ' Address filtering: none (default)
$define cSX_ADDRESS_FILTERING_NODE                 %00000010  '                    node
$define cSX_ADDRESS_FILTERING_NODE_BROADCAST       %00000100  '                    node or broadcast
$define cSX_CRC_WHITENING_TYPE_CCITT               %00000000  ' CRC and whitening algorithms: CCITT CRC with standard whitening (default)
$define cSX_CRC_WHITENING_TYPE_IBM                 %00000001  '                               IBM CRC with alternate whitening
'
' cSX_REG_PACKET_CONFIG_2
'
$define cSX_DATA_MODE_PACKET                       %01000000  ' Data mode: packet (default)
$define cSX_DATA_MODE_CONTINUOUS                   %00000000  '            continuous
$define cSX_IO_HOME_OFF                            %00000000  ' IO-homecontrol compatibility disabled (default)
$define cSX_IO_HOME_ON                             %00100000  'I O-homecontrol compatibility enabled
'
' cSX_REG_FIFO_THRESH
'
$define cSX_TX_START_FIFO_LEVEL                    %00000000  ' Start packet transmission when: number of bytes in FIFO exceeds FIFO_THRESHOLD
$define cSX_TX_START_FIFO_NOT_EMPTY                %10000000  '                                 at least one byte in FIFO (default)
$define cSX_FIFO_THRESH                            $0F        ' FIFO level threshold
'
' cSX_REG_SEQ_CONFIG_1
'
$define cSX_SEQUENCER_START                        %10000000  ' Manually start sequencer
$define cSX_SEQUENCER_STOP                         %01000000  ' Manually stop sequencer
$define cSX_IDLE_MODE_STANDBY                      %00000000  ' Chip mode during sequencer idle mode: standby (default)
$define cSX_IDLE_MODE_SLEEP                        %00100000  '                                      sleep
$define cSX_FROM_START_LP_SELECTION                %00000000  ' Mode that will be set after starting sequencer: low power selection (default)
$define cSX_FROM_START_RECEIVE                     %00001000  '                                                      receive
$define cSX_FROM_START_TRANSMIT                    %00010000  '                                                      transmit
$define cSX_FROM_START_TRANSMIT_FIFO_LEVEL         %00011000  '                                                      transmit on a FIFO level interrupt
$define cSX_LP_SELECTION_SEQ_OFF                   %00000000  ' Mode that will be set after exiting low power selection: sequencer off (default)
$define cSX_LP_SELECTION_IDLE                      %00000100  '                                                          idle state
$define cSX_FROM_IDLE_TRANSMIT                     %00000000  ' Mode that will be set after exiting idle mode: transmit (default)
$define cSX_FROM_IDLE_RECEIVE                      %00000010  '                                                receive
$define cSX_FROM_TRANSMIT_LP_SELECTION             %00000000  ' Mode that will be set after exiting transmit mode: low power selection (default)
$define cSX_FROM_TRANSMIT_RECEIVE                  %00000001  '                                                    receive
'
' cSX_REG_SEQ_CONFIG_2
'
$define cSX_FROM_RECEIVE_PACKET_RECEIVED_PAYLOAD   %00100000  ' Mode that will be set after exiting receive mode: packet received on payload ready interrupt (default)
$define cSX_FROM_RECEIVE_LP_SELECTION              %01000000  '                                                   low power selection
$define cSX_FROM_RECEIVE_PACKET_RECEIVED_CRC_OK    %01100000  '                                                   packet received on CRC OK interrupt
$define cSX_FROM_RECEIVE_SEQ_OFF_RSSI              %10000000  '                                                   sequencer off on RSSI interrupt
$define cSX_FROM_RECEIVE_SEQ_OFF_SYNC_ADDR         %10100000  '                                                   sequencer off on sync address interrupt
$define cSX_FROM_RECEIVE_SEQ_OFF_PREAMBLE_DETECT   %11000000  '                                                   sequencer off on preamble detect interrupt
$define cSX_FROM_RX_TIMEOUT_RECEIVE                %00000000  ' Mode that will be set after Rx timeout: receive (default)
$define cSX_FROM_RX_TIMEOUT_TRANSMIT               %00001000  '                                              transmit
$define cSX_FROM_RX_TIMEOUT_LP_SELECTION           %00010000  '                                              low power selection
$define cSX_FROM_RX_TIMEOUT_SEQ_OFF                %00011000  '                                              sequencer off
$define cSX_FROM_PACKET_RECEIVED_SEQ_OFF           %00000000  ' Mode that will be set after packet received: sequencer off (default)
$define cSX_FROM_PACKET_RECEIVED_TRANSMIT          %00000001  '                                              transmit
$define cSX_FROM_PACKET_RECEIVED_LP_SELECTION      %00000010  '                                              low power selection
$define cSX_FROM_PACKET_RECEIVED_RECEIVE_FS        %00000011  '                                              receive via FS
$define cSX_FROM_PACKET_RECEIVED_RECEIVE           %00000100  '                                              receive
'
' cSX_REG_TIMER_RESOL
'
$define cSX_TIMER1_OFF                             %00000000  ' Timer 1 resolution: disabled (default)
$define cSX_TIMER1_RESOLUTION_64_US                %00000100  '                     64 us
$define cSX_TIMER1_RESOLUTION_4_1_MS               %00001000  '                     4.1 ms
$define cSX_TIMER1_RESOLUTION_262_MS               %00001100  '                     262 ms
$define cSX_TIMER2_OFF                             %00000000  ' Timer 2 resolution: disabled (default)
$define cSX_TIMER2_RESOLUTION_64_US                %00000001  '                     64 us
$define cSX_TIMER2_RESOLUTION_4_1_MS               %00000010  '                     4.1 ms
$define cSX_TIMER2_RESOLUTION_262_MS               %00000011  '                     262 ms
'
' cSX_REG_TIMER1_COEF
'
$define cSX_TIMER1_COEFFICIENT                     $F5        ' Multiplication coefficient for timer 1
'
' cSX_REG_TIMER2_COEF
'
$define cSX_TIMER2_COEFFICIENT                     $20        ' Multiplication coefficient for timer 2
'
' cSX_REG_IMAGE_CAL
'
$define cSX_AUTO_IMAGE_CAL_OFF                     %00000000  ' Temperature calibration disabled (default)
$define cSX_AUTO_IMAGE_CAL_ON                      %10000000  ' Temperature calibration enabled
$define cSX_IMAGE_CAL_START                        %01000000  ' Start temperature calibration
$define cSX_IMAGE_CAL_RUNNING                      %00100000  ' Temperature calibration is on-going
$define cSX_IMAGE_CAL_COMPLETE                     %00000000  ' Temperature calibration finished
$define cSX_TEMP_CHANGED                           %00001000  ' Temperature changed more than TEMP_THRESHOLD since last calibration
$define cSX_TEMP_THRESHOLD_5_DEG_C                 %00000000  ' Temperature change threshold: 5 deg. C
$define cSX_TEMP_THRESHOLD_10_DEG_C                %00000010  '                               10 deg. C (default)
$define cSX_TEMP_THRESHOLD_15_DEG_C                %00000100  '                               15 deg. C
$define cSX_TEMP_THRESHOLD_20_DEG_C                %00000110  '                               20 deg. C
$define cSX_TEMP_MONITOR_ON                        %00000000  ' Temperature monitoring enabled (default)
$define cSX_TEMP_MONITOR_OFF                       %00000001  ' Temperature monitoring disabled
'
' cSX_REG_LOW_BAT
'
$define cSX_LOW_BAT_OFF                            %00000000  ' Low battery detector disabled
$define cSX_LOW_BAT_ON                             %00001000  ' Low battery detector enabled
$define cSX_LOW_BAT_TRIM_1_695_V                   %00000000  ' Battery voltage threshold: 1.695 V
$define cSX_LOW_BAT_TRIM_1_764_V                   %00000001  '                            1.764 V
$define cSX_LOW_BAT_TRIM_1_835_V                   %00000010  '                            1.835 V (default)
$define cSX_LOW_BAT_TRIM_1_905_V                   %00000011  '                            1.905 V
$define cSX_LOW_BAT_TRIM_1_976_V                   %00000100  '                            1.976 V
$define cSX_LOW_BAT_TRIM_2_045_V                   %00000101  '                            2.045 V
$define cSX_LOW_BAT_TRIM_2_116_V                   %00000110  '                            2.116 V
$define cSX_LOW_BAT_TRIM_2_185_V                   %00000111  '                            2.185 V
'
' cSX_REG_IRQ_FLAGS_1
'
$define cSX_FLAG_MODE_READY                        %10000000  ' Requested mode is ready
$define cSX_FLAG_RX_READY                          %01000000  ' Reception ready (after RSSI, AGC, AFC)
$define cSX_FLAG_TX_READY                          %00100000  ' Transmission ready (after PA ramp-up)
$define cSX_FLAG_PLL_LOCK                          %00010000  ' PLL locked
$define cSX_FLAG_RSSI                              %00001000  ' RSSI value exceeds RSSI threshold
$define cSX_FLAG_TIMEOUT                           %00000100  ' Timeout occurred
$define cSX_FLAG_PREAMBLE_DETECT                   %00000010  ' Valid preamble was detected
$define cSX_FLAG_SYNC_ADDRESS_MATCH                %00000001  ' Sync address matched
'
' cSX_REG_IRQ_FLAGS_2
'
$define cSX_FLAG_FIFO_FULL                         %10000000  ' FIFO is full
$define cSX_FLAG_FIFO_EMPTY                        %01000000  ' FIFO is empty
$define cSX_FLAG_FIFO_LEVEL                        %00100000  ' Number of bytes in FIFO exceeds FIFO_THRESHOLD
$define cSX_FLAG_FIFO_OVERRUN                      %00010000  ' FIFO overrun occurred
$define cSX_FLAG_PACKET_SENT                       %00001000  ' Packet was successfully sent
$define cSX_FLAG_PAYLOAD_READY                     %00000100  ' Packet was successfully received
$define cSX_FLAG_CRC_OK                            %00000010  ' CRC check passed
$define cSX_FLAG_LOW_BAT                           %00000001  ' Battery voltage dropped below threshold
'
' cSX_REG_DIO_MAPPING_1
'
$define cSX_DIO0_CONT_SYNC_ADDRESS                 %00000000
$define cSX_DIO0_CONT_TX_READY                     %00000000
$define cSX_DIO0_CONT_RSSI_RADIOLIB_PREAMBLE_DETECTED       %01000000
$define cSX_DIO0_CONT_RX_READY                     %10000000
$define cSX_DIO0_PACK_PAYLOAD_READY                %00000000
$define cSX_DIO0_PACK_PACKET_SENT                  %00000000
$define cSX_DIO0_PACK_CRC_OK                       %01000000
$define cSX_DIO0_PACK_TEMP_CHANGE_LOW_BAT          %11000000
$define cSX_DIO1_CONT_DCLK                         %00000000
$define cSX_DIO1_CONT_RSSI_RADIOLIB_PREAMBLE_DETECTED %00010000
$define cSX_DIO1_PACK_FIFO_LEVEL                   %00000000
$define cSX_DIO1_PACK_FIFO_EMPTY                   %00010000
$define cSX_DIO1_PACK_FIFO_FULL                    %00100000
$define cSX_DIO2_CONT_DATA                         %00000000
'
' cSX_REG_PLL_HOP
'
$define cSX_FAST_HOP_OFF                           %00000000  ' Carrier frequency validated when FRF registers are written
$define cSX_FAST_HOP_ON                            %10000000  ' Carrier frequency validated when FS modes are requested
'
' cSX_REG_TCXO
'
$define cSX_TCXO_INPUT_EXTERNAL                    %00000000  ' Use external crystal oscillator
$define cSX_TCXO_INPUT_EXTERNAL_CLIPPED            %00010000  ' Use external crystal oscillator clipped sine connected to XTA pin
'
' cSX_REG_PLL
'
$define cSX_PLL_BANDWIDTH_75_KHZ                   %00000000  ' PLL bandwidth: 75 kHz
$define cSX_PLL_BANDWIDTH_150_KHZ                  %01000000  '                150 kHz
$define cSX_PLL_BANDWIDTH_225_KHZ                  %10000000  '                225 kHz
$define cSX_PLL_BANDWIDTH_300_KHZ                  %11000000  '                300 kHz (default)
'
' Modulation Shaping (bits 5 and 6 of the PA Ramp register) Address $0A
'
' In FSK
'
$define cSX_FSK_SHAPING_NONE   %00000000    ' No shaping
$define cSX_FSK_SHAPING_BT_1_0 %00100000    ' Gaussian filter BT = 1.0
$define cSX_FSK_SHAPING_BT_0_5 %01000000    ' Gaussian filter BT = 0.5
$define cSX_FSK_SHAPING_BT_0_3 %01100000    ' Gaussian filter BT = 0.3
'
' In OOK
'
$define cSX_FSK_SHAPING_NONE     %00000000  ' No shaping
$define cSX_FSK_SHAPING_BITRATE1 %00100000  ' Filtering with fcutoff = bit_rate
$define cSX_FSK_SHAPING_BITRATE2 %01000000  ' Filtering with fcutoff = 2*bit_rate (for bit_rate < 125 kb/s)
'
' Rise/Fall time of ramp up/down in FSK (bits 0 to 3 of the PA Ramp register) Address $0A
'
$define cSX_FSK_RAMP_3_4MS %00000000    ' 3.4 ms
$define cSX_FSK_RAMP_2MS   %00000001    ' 2 ms
$define cSX_FSK_RAMP_1MS   %00000010    ' 1 ms
$define cSX_FSK_RAMP_500US %00000011    ' 500 us
$define cSX_FSK_RAMP_250US %00000100    ' 250 us
$define cSX_FSK_RAMP_125US %00000101    ' 125 us
$define cSX_FSK_RAMP_100US %00000110    ' 100 us
$define cSX_FSK_RAMP_62US  %00000111    ' 62 us
$define cSX_FSK_RAMP_50US  %00001000    ' 50 us
$define cSX_FSK_RAMP_40US  %00001001    ' 40 us
$define cSX_FSK_RAMP_31US  %00001010    ' 31 us
$define cSX_FSK_RAMP_25US  %00001011    ' 25 us
$define cSX_FSK_RAMP_20US  %00001100    ' 20 us
$define cSX_FSK_RAMP_15US  %00001101    ' 15 us
$define cSX_FSK_RAMP_12US  %00001110    ' 12 us
$define cSX_FSK_RAMP_10US  %00001111    ' 10 us
'
' MSSP1 SPI setup bit masks
'
$define MODE_00       %00000000         ' Setting for SPI bus Mode 0,0
$define MODE_01       %00000001         ' Setting for SPI bus Mode 0,1
$define MODE_10       %00000010         ' Setting for SPI bus Mode 1,0
$define MODE_11       %00000011         ' Setting for SPI bus Mode 1,1
'
' SSP1STAT Register
'
$define SMPEND        %10000000         ' Input data sample at end of data out
$define SMPMID        %00000000         ' Input data sample at middle of data out

$define SSPACTIDLE    %01000000         ' SPI Transmit occurs on the transition from active to Idle clock state
$define SSPIDLEACT    %00000000         ' SPI Transmit occurs on the transition from Idle to active clock state
'
' SSP1CON1 Register
'
$define SSPENB        %00100000         ' Enable SPI and configures SCK, SDO, SDI

$define SSPIDLEHIGH   %00010000         ' SPI Idle state for the clock is a high level
$define SSPIDLELOW    %00000000         ' SPI Idle state for the clock is a low level

$define SPI_FOSC_4    %00000000         ' SPI Master mode, clock = Fosc/4
$define SPI_FOSC_16   %00000001         ' SPI Master mode, clock = Fosc/16
$define SPI_FOSC_64   %00000010         ' SPI Master mode, clock = Fosc/64
$define SPI_FOSC_TMR2 %00000011         ' SPI Master mode, clock = TMR2 output/2
$define SLV_SSON      %00000100         ' SPI Slave mode, /SS pin control enabled
$define SLV_SSOFF     %00000101         ' SPI Slave mode, /SS pin control disabled

$ifndef False
    $define False 0
$endif
$ifndef True
    $define True 1
$endif
'
' Rename the HSerin4/HSerout4 and HRsin4/HRsout4 commands for the SX1278 module operation
'
$define SX_SerIn HSerIn4
$define SX_SerOut HSerOut4
$define SX_SerOutLn HSerOut4Ln

$define SX_In HRSIn4
$define SX_Out HRSOut4
$define SX_OutLn HRSOut4Ln

$define SX_SPI_Delay() DelayUS 1
'
' Create some Compiler system variables
'
    Dim GEN     As Byte System                      ' \
    Dim GENH    As Byte System                      ' / Hrsin4 Timeout value storage
    Dim PP0     As Byte System                      ' \
    Dim PP0H    As Byte System                      ' / Hrsin4 Timeout outside loop counter
    Dim PP1     As Byte System                      ' \
    Dim PP1H    As Byte System                      ' / Hrsin4 Timeout inside loop counter
'
' Create variables for the replacement HRsout4 and HRsin4 routines
'
    Dim SX_bTimeoutInt     As GEN
    Dim SX_bTimeoutIntH    As GENH
    Dim SX_bOutsideLoopInt  As PP0
    Dim SX_bOutsideLoopIntH As PP0H
    Dim SX_bInsideLoopInt  As PP1
    Dim SX_bInsideLoopIntH As PP1H
    Dim SX_wTimeoutValue   As SX_bTimeoutInt.Word       ' Alias the timeout value to GEN\H
    Dim SX_wInsideLoop     As Word Access 'SX_bInsideLoopInt.Word    ' Alias the inside loop to PP1\H
    Dim SX_wOutsideLoop    As Word Access 'SX_bOutsideLoopInt.Word   ' Alias the outside loop to PP0\H
'
' Create some variables
'
    Dim SX_bFlags As Byte Access                    ' Holds flags for the SX routines
    Dim SX_tTimedOut As SX_bFlags.0                 ' True if a timeout occurs while receiving data

    Dim SX_bIrqFlags As Byte Access                 ' Holds the IRQ flags from the SX1278 module
    Dim SX_bInOut    As Byte Access
    Dim SX_fFrequency As Float                      ' Holds the frequency to operate on

'------------------------------------------------------------------------------
    GoTo Over_HRs4_Replacements                     ' Jump over the replacement HRsout4 and HRsin4 replacement subroutnes

'------------------------------------------------------------------------------
' Wait for a byte from the SX1278 module with timeout
' Input     : GEN\GENH hold the timeout value in approx ms (0 to 65535)
' Output    : PP0 and WREG hold the value received
'           : Carry Flag (STATUS.0) Clear if timeout out
' Notes     : None
'
__HRsin4_With_TimeOut__:
    SX_wOutsideLoop = SX_wTimeoutValue              ' Save the timeout value so it doesn't get overwritten
    SX_wInsideLoop = 0                              ' Reset the inside loop counter

SXin_OuterLoop:
    DelayCS 3
    Do
        If SX_DIO0_Pin = 1 Then GoTo SX_hGetByte
        WREG = 255                                  ' \
        Addwf     SX_wInsideLoop,f                  ' |
        Addwfc    SX_wInsideLoopH,f                 ' | Decrement the inside and outside loops
        Addwfc    SX_wOutsideLoop,f                 ' |
        Addwfc    SX_wOutsideLoopH,f                ' /
        If STATUSbits_C = 0 Then Ret                ' Return with the Carry flag clear to indicate timed out

        Infsnz    SX_wInsideLoop,w
        Incfsz    SX_wInsideLoopH,w
        GoTo SXin_OuterLoop
        SX_wInsideLoop = ((59 * _xtal) / 4)         ' Set the inside loop counter based upon the Xtal frequency
    Loop

'------------------------------------------------------------------------------
' Wait for a byte received from the SX1278 module
' Input     : None
' Output    : WREG holds the value received
' Notes     : None
'
__Hrsin4__:
    Repeat                                          ' \ Wait until something is received from the SX1278 module
    Until SX_DIO0_Pin = 1                           ' /
'
' Fall through to SX_hGetByte
'------------------------------------------------------------------------------
' Read a byte from the SX1278 module
' Input     : None
' Output    : PP0 and WREG hold the value received
' Notes     : Uses FSR0L\H as buffer pointers
'
SX_hGetByte:
    SX_Clear_IRQ_Flags()                            ' Clear LoRA IRQ flags
    SX_WriteReg(cSX_REG_FIFO_ADDR_PTR, SX_ReadReg(cSX_REG_FIFO_RX_CURRENT_ADDR)) ' Read the last packet address and Set FifoAddrPtr to last packet address
    WREG = SX_ReadReg(cSX_REG_FIFO)                 ' Read the byte received from the FIFO
    PP0 = WREG
    Set STATUSbits_C
    Return

'--------------------------------------------------------------------------------
' Replace the library Hrsout4 library routine with this routine
' Input     : WREG holds the byte to transmit
' Output    : WREG still holds the byte transmitted
' Notes     : None
'
Sub __Hrsout4__()
    SX_SendByte(WREG)
EndSub

Over_HRs4_Replacements:

'-----------------------------------------------------------------------------------
' Unlock PPS
' Input     : None
' Output    : None
' Notes     : None
''
Proc SX_Unlock_PPS()
    PPSLOCK = $55
    PPSLOCK = $AA
    PPSLOCKbits_PPSLOCKED = 0
EndProc

'----------------------------------------------------------------------------------
' Setup the SPI interface to communicate with an SX1278 device
' Input     : None
' Output    : None
' Notes     : Mode 00
'
Proc SX_SPI_Setup()
$ifdef SX_cSoftSPI                              ' Software SPI?
    PinHigh SX_MOSI_Pin                         ' Set the MOSI pin to output high
    PinLow SX_SCK_Pin                           ' Set the SCK pin to output low
    PinHigh SX_NSS_Pin                          ' Set the NSS pin to output high
    PinInput SX_MISO_Pin                        ' Make the MISO pin an input
$else                                           ' Otherwise... Hardware SPI
    SX_Unlock_PPS()
    SSP1CLKPPS = Pin_C3                         ' \ Set PPS for RC3 as SCK1
    RC3PPS = PPS_Fn_SCK1                        ' /

    RC5PPS = PPS_Fn_SDO1                        ' Set PPS for RC5 as SDO1
    SSP1DATPPS = Pin_C4                         ' Set PPS for RC4 as SDI1

    SSP1STAT = SMPMID | SSPACTIDLE              ' SMP Middle, CKE Active to Idle
    SSP1CON1 = SSPENB | SSPIDLELOW | SPI_FOSC_16 ' SSPEN enabled, CKP Idle:Low, Active:High, SSPM FOSC/16
    SSP1ADD  = %00000000
$endif
EndProc

'-----------------------------------------------------------------------------------
' Write a byte to the SPI bus
' Input     : pDataOut holds the 8-bit value to send to the SPI bus
' Output    : None
' Notes     : None
'
$ifdef SX_cSoftSPI                              ' Software SPI?
Proc SX_SPI_Write(pDataOut As WREG)
    Dim bBitCnt As PRODH

    PRODL = pDataOut                            ' Transfer the byte to send into PRODL
    PinOutput SX_MOSI_Pin                       ' Make the MOSI pin an output
    PinLow SX_SCK_Pin                           ' Make sure the SCK pin is a low output
    For bBitCnt = 7 DownTo 0                    ' Create a loop for the 8-bits to write
        PinClear SX_SCK_Pin                     ' Bring the SCK pin low
        Rol PRODL                               ' Rotate the MSB into the Carry flag
        PinClear SX_MOSI_Pin                    ' Default to the MOSI pin low
        If STATUSbits_C = 1 Then                ' Is the Carry Flag 1?
            PinSet SX_MOSI_Pin                  ' Yes. So bring the MOSI pin high
        EndIf
        PinSet SX_SCK_Pin                       ' Bring the SCK pin high
    Next
    PinClear SX_SCK_Pin                         ' Pull the SCK pin low before exiting
EndProc

$else                                           ' Otherwise... Hardware SPI
Proc SX_SPI_Write(pDataOut As WREG)
    SSP1CON1bits_WCOL = 0
    SSP1BUF = pDataOut
    Repeat: Until SSP1STATbits_BF = 1
EndProc
$endif

'-----------------------------------------------------------------------------------
' Read from the SPI bus
' Input     : None
' Output    : Returns the value read from the SPI bus
' Notes     : None
'
$ifdef SX_cSoftSPI                              ' Software SPI?
Proc SX_SPI_Read(), WREG
    Dim bBitCnt As PRODL

    PinInput SX_MOSI_Pin                        ' Make the MISO pin an input
    PinLow SX_SCK_Pin                           ' Make sure the SCK pin is a low output
    For bBitCnt = 7 DownTo 0                    ' Create a loop for the 8-bits to read
        PinClear SX_SCK_Pin                     ' Bring the SCK pin low
        PRODH = PRODH << 1                      ' Left rotate the result value
        PinClear SX_MOSI_Pin                    ' Default to the MOSI pin low so it sends out the value $00
        PinSet SX_SCK_Pin                       ' Bring the SCK pin high
        PRODH.0 = 0                             ' Default to the bit being a 0
        If SX_MISO_Pin = 1 Then                 ' Is the MISO pin high?
            PRODH.0 = 1                         ' Yes. So set the result bit to a 1
        EndIf
    Next
    PinClear SX_SCK_Pin                         ' Pull the SCK pin low before exiting
    Result = PRODH
EndProc

$else                                           ' Otherwise... Hardware SPI
Proc SX_SPI_Read(), WREG
    SSP1CON1bits_WCOL = 0
    SSP1BUF = $00
    Repeat: Until SSP1STATbits_BF = 1
    Result = SSP1BUF
EndProc
$endif

'----------------------------------------------------------------------------------
' Write to a register within the SX device
' Input     : pRegAddr holds the register's address
'           : pValue holds the 8-bit value to write to the register
' Output    : None
' Notes     : None
'
Proc SX_WriteReg(pRegAddr As Byte, pValue As Byte)
    pRegAddr.7 = 1                              ' Set bit-7 of pRegAddr for write operation
    PinClear SX_NSS_Pin                         ' Enable the SPI interface
    SX_SPI_Write(pRegAddr)                      ' Write the address of the register
    SX_SPI_Write(pValue)                        ' Write the value to the register
    PinSet SX_NSS_Pin                           ' Disable the SPI interface
EndProc

'----------------------------------------------------------------------------------
' Read from a register within the SX device
' Input     : pRegAddr holds the register's address
' Output    : Returns the 8-bit value read from the register
' Notes     : None
'
Proc SX_ReadReg(pRegAddr As Byte), Byte
    pRegAddr.7 = 0                              ' Clear bit-7 of pRegAddr for read operation
    PinClear SX_NSS_Pin                         ' Enable the SPI interface
    SX_SPI_Write(pRegAddr)                      ' Write the address of the register
    Result = SX_SPI_Read()                      ' Read the register's value
    PinSet SX_NSS_Pin                           ' Disable the SPI interface
EndProc

'-----------------------------------------------------------------------------------
' Send a byte via the SX1278 module
' Input     : pValue (WREG) holds the byte to send
' Output    : Returns False if a timeout occurs
' Notes     : Does not transmit a byte if a timeout occurs
'           : WREG still holds the value transferred to it, when the procedure is exited
'
Proc SX_SendByte(pValue As WREG), Bit
    Dim wTimeout As Word
    SX_bInOut = pValue                              ' Save the contents of pValue (WREG)
    wTimeout = 100 * 1000                           ' Setup for approx 100ms timeout
    Result = False                                  ' Default to a timeout occured

    SX_WriteReg(cSX_REG_OP_MODE, %00001001)         ' Standby mode to set up packet
    SX_WriteReg(cSX_REG_FIFO_ADDR_PTR, $80)         ' Set SPI pointer
    SX_WriteReg(cSX_REG_FIFO, SX_bInOut)            ' Write the byte to the FIFO
    SX_WriteReg(cSX_REG_OP_MODE, %10001011)         ' TX on, low frequency mode (send the byte)
    Repeat
        SX_bIrqFlags = SX_ReadReg(cSX_REG_IRQ_FLAGS) ' Get flags reg
        If SX_bIrqFlags > 0 Then                    ' TX Done?
            SX_WriteReg(cSX_REG_IRQ_FLAGS, %11111111) ' Yes. So reset flags
            Result = True                           ' Return a true result
            Break                                   ' Exit the loop
        EndIf
        DelayMS 1
        Dec wTimeout
    Until wTimeout = 0

    SX_WriteReg(cSX_REG_OP_MODE, %10001000)         ' TX and RX to sleep in LoRa mode (clear FIFO)
    WREG = SX_bInOut                                ' Load WREG with the value sent, so it keeps what was in it before the procedure was called
EndProc

'----------------------------------------------------------------------------------
' Receive a byte from the SX1278 module
' Input     : pTimeout is the time to wait for something to be received (0 to 65535 ms)
' Output    : Returns the byte received
' Notes     : None
'
Proc SX_RecByte(pTimeout As Word), Byte
    pTimeout = pTimeout * 1000
    Result = 0
    Repeat
        If SX_DIO0_Pin = 1 Then                             ' Is there something received?
            SX_Clear_IRQ_Flags()                            ' Yes. So clear LoRA IRQ flags
            SX_WriteReg(cSX_REG_FIFO_ADDR_PTR, SX_ReadReg(cSX_REG_FIFO_RX_CURRENT_ADDR)) ' Read the last packet address and Set FifoAddrPtr to last packet address
            Result = SX_ReadReg(cSX_REG_FIFO)               ' Read the byte received from the FIFO
            SX_tTimedOut = False                            ' Clear the timeout flag for no timeout occured
            ExitProc
        EndIf
        DelayMS 1
        Dec pTimeout
    Until pTimeout = 0
    SX_tTimedOut = True                                     ' Set the timeout flag for timeout occured
EndProc

'-------------------------------------------------------------------------------------
' Read the RSSI value
' Input     : None
' Output    : Returns the RSSI value
' Notes     : None
'
Proc SX_ReadRSSI(), SByte
    Result = SX_ReadReg(cSX_REG_RSSI_VALUE)                 ' Read the LoRA RSSI value
    Result = Result + 127                                   ' \
    Result = Result - 137                                   ' / 127: Max RSSI, 137: RSSI offset
EndProc

'-------------------------------------------------------------------------------------
' Change the frequency of the SX device
' Input     : pFreq holds the frequency value, in MHz. i.e. 433.00 for 433MHz
' Output    : None
' Notes     : The calculation for the frequency value is: dFreq = (Frequency * (1 << 19)) / 32
'
Proc SX_SetFrequency(pFreq As Float)
    Dim fFreq As Float
    Dim dFreq As fFreq.Dword
    Symbol c1Lft19 = (1 << 19)

    fFreq = (pFreq * c1Lft19)
    dFreq = fFreq / 32.0
    SX_WriteReg(cSX_REG_FRF_MSB, dFreq.Byte0)
    SX_WriteReg(cSX_REG_FRF_MID, dFreq.Byte1)
    SX_WriteReg(cSX_REG_FRF_LSB, dFreq.Byte2)
EndProc

'-------------------------------------------------------------------------------------
' Clear the IRQ flags
' Input     : None
' Output    : None
' Notes     : None
'
Proc SX_Clear_IRQ_Flags()
    SX_WriteReg(cSX_REG_IRQ_FLAGS, %01000000)        ' Clear LoRA IRQ flags
EndProc

'----------------------------------------------------------------------------------
' Set the SX1278 for RX mode
' Input     : None
' Output    : None
' Notes     : None
'
Proc SX_SetFor_RX()
    SX_WriteReg(cSX_REG_IRQ_FLAGS_MASK, %10111111)  ' Set up the flag for RXdone IRQ
    SX_WriteReg(cSX_REG_OP_MODE, %10001101)         ' RXCONTINUOUS, low frequency, LoRA mode (start listening)
EndProc

'----------------------------------------------------------------------------------
' Set the SX1278 for TX mode
' Input     : None
' Output    : None
' Notes     : None
'
Proc SX_SetFor_TX()
    'SX_WriteReg(cSX_REG_PA_CONFIG, cSX_USE_PA_BOOST_PIN | cSX_MAX_POWER7 | cSX_OUTPUT_POWER15) ' +20 dBm on PA_BOOST when Output_Power = %1111

    SX_WriteReg(cSX_REG_IRQ_FLAGS_MASK, %11110111)    ' Set up for TXDone IRQ
EndProc

'----------------------------------------------------------------------------------
' Reset the SX1278 module
' Input     : None
' Output    : None
' Notes     : Pulls the RST pin low then high
'
Proc SX_Reset()
    PinClear SX_RST_Pin                             ' Pull the SX1278 module's RST pin low
    DelayMS 1                                       ' Reset for 1 ms
    PinSet SX_RST_Pin                               ' Bring the SX1278 module's RST pin high
    DelayMS 5                                       ' Time after reset has a minimum of 5 ms
EndProc

'----------------------------------------------------------------------------------
' Setup the SX device
' Input     : Global variable "SX_fFrequency" holds the frequency to operate on (in MHz)
' Output    : None
' Notes     : None
'
Proc SX_Setup()
    PinLow SX_SCK_Pin                               ' Set the SCK pin to output low
    PinHigh SX_NSS_Pin                              ' Set the NSS pin to output high
    PinInput SX_MISO_Pin                            ' Make the MISO pin an input
    PinInput SX_MOSI_Pin                            ' Make the MOSI pin an input
    PinLow SX_RST_Pin                               ' Set the Reset pin to output low
    PinInput SX_DIO0_Pin                            ' Make the DIO0 pin an input (IRQ pin)

    SX_SPI_Setup()                                  ' Setup the SPI interface
    SX_Reset()                                      ' Reset the SX device

    SX_WriteReg(cSX_REG_OP_MODE, cSX_SLEEP_MODE)    ' Need to be in sleep mode to set LoRa mode
    SX_WriteReg(cSX_REG_OP_MODE, cSX_LORA_MODE | cSX_LOW_FREQUENCY_MODE)    ' LoRa mode, low freq mode

    SX_WriteReg(cSX_REG_OCP, %00111001)
    SX_WriteReg(cSX_REG_MODEM_CONFIG_1, cSX_BW_250_00_KHZ)
    SX_WriteReg(cSX_REG_PA_CONFIG, cSX_USE_PA_BOOST_PIN | cSX_MAX_POWER7 | cSX_OUTPUT_POWER15) ' +20 dBm on PA_BOOST when Output_Power = %1111
    SX_WriteReg(cSX_REG_PA_DAC, $87)                ' Set High Power Settings

   ' SX_WriteReg(cSX_REG_FIFO_TX_BASE_ADDR, 0)       ' Set TX base address
   ' SX_WriteReg(cSX_REG_FIFO_RX_BASE_ADDR, 0)       ' Set RX base address

    SX_WriteReg(cSX_REG_LNA, cSX_LNA_GAIN_1)        ' Maximum LNA gain
    SX_SetFrequency(SX_fFrequency)                  ' Set the frequency. It is set at 433MHz in "SX_fFrequency"
EndProc

$endif  ' _cSX_INC_

Name the file created from the above listing as "SX1278.inc". I have extra procedures to add to it that ease the setting up of the SX1278 module, but I cannot add them until I have gotten the range to be correct, otherwise, it makes the library's listing more confusing to scan.

Below are a pair of programs I created to test range and reliability of the SX1278 modules. The TX program stays in my office and transmits/receives data from the RX, which receives data and if the data is correct, it flashes a green LED. If it gets data but it is incorrect, it flashes a red LED, and if it receives no data, both LEDs are extinguished. It allows me to test range in the car without having to look at data on an LCD or laptop etc...

The TX (BaseStation) program is listed below. It will flash both LEDs when it is able to transmit data after it has received it, but does not check anything:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' SX1278 Base test. The unit that this firmware sits on, is left in place.
' It receives a signal from the transmitter and send beck what was received
' When a transmission occurs, both LEDs with flash briefly
'
' Written for the Positron8 compiler by Les Johnson
'
    Device = 18F26K40
    Declare Xtal = 64
   
    Declare Hserial_Baud = 9600
    Declare HRSOut1_Pin  = PORTC.6
'
' Set the pins to use for the interface to the SX1278 device
'
$define SX_MISO_Pin PORTB.3                             ' Connects to the SX1278's MISO pin
$define SX_MOSI_Pin PORTB.4                             ' Connects to the SX1278's MOSI pin
$define SX_RST_Pin  PORTB.5                             ' Connects to the SX1278's RST pin
$define SX_NSS_Pin  PORTC.1                             ' Connects to the SX1278's NSS pin
$define SX_DIO0_Pin PORTC.2                             ' Connects to the SX1278's DIO0 pin (Used as an IRQ for received data)
$define SX_SCK_Pin  PORTC.3                             ' Connects to the SX1278's SCK pin

$define LED_Red_Pin PORTC.4
$define LED_Green_Pin PORTC.5

    Include "SX1278.inc"                                ' Load the SX1278 library routines into the program
'
' Create some variables for the test

    Dim Global_RawString As String * 30

'----------------------------------------------------------------------------------
' The main program starts here
' Receive data then re-tranmsit it
'
Main:
    SX_fFrequency = 433.0                               ' Set the frequency to use
    SX_Setup()                                          ' Setup the SX1278 module
Again:  
    Do
        SX_SetFor_RX()                                  ' Set the SX1278 to receive mode
        SX_SerIn 5000, TimedOut, [Global_RawString]     ' Receive data from the SX1278 module
        'HRSOutLn "Rec:", Global_RawString
        DelayMS 100
       
        SX_SetFor_TX()                                  ' Set the SX1278 to transmit mode
        SX_OutLn Global_RawString                       ' Transmit what was received
       
        PinHigh LED_Red_Pin                             ' \
        PinHigh LED_Green_Pin                           ' |
        DelayMS 100                                     ' | Toggle both LEDs to signal that something has been transmitted
        PinLow LED_Red_Pin                              ' |
        PinLow LED_Green_Pin                            ' |
        DelayMS 100                                     ' /
    Loop
'
' Jump here if a timeout occurs while waiting for data
'    
TimedOut:
    HRSOutLn "Timed Out"
    DelayMS 100
    GoTo Again

'------------------------------------------------------------------------------
' Setup the fuses to use the internal oscillator at 64MHz on a PIC18F26K40. With RA6 and RA7 as I/O lines
'
Config_Start
    RSTOSC = HFINTOSC_64MHZ         ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
    FEXTOSC = Off                   ' External Oscillator not enabled
    WDTE = Off                      ' WDT disabled
    CLKOUTEN = Off                  ' CLKOUT function is disabled
    CSWEN = On                      ' Writing to NOSC and NDIV is allowed
    FCMEN = Off                     ' Fail-Safe Clock Monitor disabled
    MCLRE = EXTMCLR                 ' If LVP = 0, MCLR pin is MCLR. If LVP = 1, RE3 pin function is MCLR
    PWRTE = On                      ' Power up timer enabled
    LPBOREN = off                   ' ULPBOR disabled
    BOREN = On                      ' Brown-out turned on
    BORV = VBOR_245                 ' Brown-out Reset Voltage (VBOR) set to 2.45V
    ZCD = Off                       ' ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                   ' PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = Off                    ' Stack full/underflow will not cause Reset
    Debug = Off                     ' Background debugger disabled
    XINST = Off                     ' Extended Instruction Set and Indexed Addressing Mode disabled
    SCANE = Off                     ' Scanner module is Not available for use. SCANMD bit is ignored
    LVP = On                        ' Low Voltage programming enabled
    WDTCPS = WDTCPS_15              ' Watchdog Divider ratio 1:1048576 (32 seconds)
    WDTCWS = WDTCWS_7               ' Window always open (100%). Software control. Keyed access not required
    WDTCCS = LFINTOSC               ' WDT input clock selector->WDT reference clock is the 31.2kHz HFINTOSC output
    WRT0 = Off                      ' Block 0 (000800-001FFFh) not write-protected
    WRT1 = Off                      ' Block 1 (002000-003FFFh) not write-protected
    WRTC = Off                      ' Configuration registers (300000-30000Bh) not write-protected
    WRTB = Off                      ' Boot Block (000000-0007FFh) write-protected
    WRTD = Off                      ' Data EEPROM not write-protected
    Cp = Off                        ' UserNVM code protection disabled
    CPD = Off                       ' DataNVM code protection disabled
    EBTR0 = Off                     ' Block 0 (000800-001FFFh) not protected from table reads executed in other blocks
    EBTR1 = Off                     ' Block 1 (002000-003FFFh) not protected from table reads executed in other blocks
    EBTRB = Off                     ' Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
Config_End

The RX (Mobile) program is listed below. It flashes green or red LEDs when data has arrived correctly or incorrectly:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' SX1278 mobile test. The unit that this firmware sits on is moved to check range.
' It transmits a message and if it is received correctly back, it flashes the green LED
' If it is received incorrectly, it flashes the red LED
' If nothing is received, both LEDs are extinguished until it starts receiving again
'
' Written for the Positron8 compiler by Les Johnson
'
    Device = 18F26K40
    Declare Xtal = 64
   
    Declare Hserial_Baud = 9600
    Declare HRSOut1_Pin  = PORTC.6
'
' Set the pins to use for the interface to the SX1278 device
'
$define SX_MISO_Pin PORTB.3                             ' Connects to the SX1278's MISO pin
$define SX_MOSI_Pin PORTB.4                             ' Connects to the SX1278's MOSI pin
$define SX_RST_Pin  PORTB.5                             ' Connects to the SX1278's RST pin
$define SX_NSS_Pin  PORTC.1                             ' Connects to the SX1278's NSS pin
$define SX_DIO0_Pin PORTC.2                             ' Connects to the SX1278's DIO0 pin (Used as an IRQ for received data)
$define SX_SCK_Pin  PORTC.3                             ' Connects to the SX1278's SCK pin

$define LED_Red_Pin PORTC.4
$define LED_Green_Pin PORTC.5
   
    Include "SX1278.inc"                                ' Load the SX1278 library routines into the program
'
' Create some variables
'         
    Dim ByteTransmitted As Byte
    Dim ByteReceived As Byte
    Dim Global_RawString As String * 40
   
'----------------------------------------------------------------------------------
' The main program starts here
' Transmit data and if received back correctly, flash the green LED
'
Main:   
    SX_fFrequency = 433.0                               ' Set the frequency to use
    SX_Setup()                                          ' Setup the SX1278 module
   
    ByteTransmitted = 0
Again:
    Do
        SX_SetFor_TX()                                  ' Set the SX1278 to transmit mode
        SX_OutLn "AT:", Hex2 ByteTransmitted, 13, 0     ' Transmit "AT: hex value"<CR><CR><0>
       
        SX_SetFor_RX()                                  ' Set the SX1278 to receive mode
        Clear Global_RawString
        SX_SerIn 4000, TimedOut, [Global_RawString]     ' Receive data into the String "Global_RawString"
        Global_RawString#0 = " "                        ' \
        Global_RawString#1 = " "                        ' | Remove the "AT:" text from the beginning of the received string
        Global_RawString#2 = " "                        ' |
        TidyRawString()                                 ' /
        ByteReceived = Val(Global_RawString, Hex)       ' Convert the remaining hex string value to an integer value
       
        If ByteReceived <> ByteTransmitted Then         ' Is the data received, the same as the data sent?
            HRSOutLn "AT:", Hex2 ByteReceived, " Incorrect" ' No. So display on the serial terminal
            PinHigh LED_Red_Pin                         ' \ Illuminate the red LED
            PinLow LED_Green_Pin                        ' /
        Else                                            ' Otherwise... The data was the same
            HRSOutLn "AT:", Hex2 ByteReceived           ' So display it on the serial terminal
            PinHigh LED_Green_Pin                       ' \ Illuminate the green LED
            PinLow LED_Red_Pin                          ' /
        EndIf
         
        ByteTransmitted = ByteTransmitted + 1           ' Increment the transmitted value
        DelayMS 200
        PinLow LED_Red_Pin                              ' \ Extinguish both LEDs
        PinLow LED_Green_Pin                            ' /
    Loop
'
' Jump here if a timeout occurs while waiting for data
'   
TimedOut:
    HRSOutLn "Timed Out"
    PinLow LED_Red_Pin                                  ' \ Extinguish both LEDs
    PinLow LED_Green_Pin                                ' /
    DelayMS 100
    GoTo Again:                                         ' Try again

'------------------------------------------------------------------------------------------------
' Tidy the raw string received from the SX1278 unit
' Input     : Global_RawString
' Output    : Global_RawString
' Notes     : None
'
Proc TidyRawString()
    Dim TempString As String * 32
    Dim bLoop As Byte
    Dim bCharpos As Byte
    Dim bChar As Byte
   
    Clear TempString                                ' Clear the TempString variable
    bLoop = 0
    bCharpos = 0                                    ' Start at position 0 in the string
    While bCharpos <= Len(Global_RawString)         ' Scan the raw String
        bChar = Global_RawString[bCharpos]          ' Extract a character from the raw string
        TempString[bLoop] = bChar                   ' Place it into the temp string
        Select bChar                                ' Check the character
            Case 10, 13, 0                          ' Exit the loop if ending characters found in the string
                TempString[bLoop] = 0               ' Remove any LF or CR characters
                Break                               ' Exit the loop
        EndSelect
        Inc bLoop                                   ' Move up the working string
        Inc bCharpos                                ' Move up the command string
    Wend
    Global_RawString = TempString                   ' Copy the temp string back into Global_RawString
    Trim_Left(Global_RawString)                     ' Remove any spaces from the beginning of Global_RawString
EndProc

'------------------------------------------------------------------------------
' Trim any spaces from the beginning of a RAM string
' Input     : FSR1L/H
' Output    : FSR0L/H
' Notes     : None
'
Proc Trim_Left(ByRef pStringAddr As Word)
    Dim wFSR0 As FSR0L.Word
    Dim wFSR1 As FSR1L.Word

    wFSR1 = pStringAddr
    wFSR0 = wFSR1
    While INDF1 = 32
        WREG = POSTINC1
    Wend
    While INDF1 <> 0
        POSTINC0 = POSTINC1
    Wend
    INDF0 = 0
EndProc
   
'------------------------------------------------------------------------------
' Setup the fuses to use the internal oscillator at 64MHz on a PIC18F26K40. With RA6 and RA7 as I/O lines
'
Config_Start
    RSTOSC = HFINTOSC_64MHZ         ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
    FEXTOSC = Off                   ' External Oscillator not enabled
    WDTE = Off                      ' WDT disabled
    CLKOUTEN = Off                  ' CLKOUT function is disabled
    CSWEN = On                      ' Writing to NOSC and NDIV is allowed
    FCMEN = Off                     ' Fail-Safe Clock Monitor disabled
    MCLRE = EXTMCLR                 ' If LVP = 0, MCLR pin is MCLR. If LVP = 1, RE3 pin function is MCLR
    PWRTE = On                      ' Power up timer enabled
    LPBOREN = off                   ' ULPBOR disabled
    BOREN = On                      ' Brown-out turned on
    BORV = VBOR_245                 ' Brown-out Reset Voltage (VBOR) set to 2.45V
    ZCD = Off                       ' ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                   ' PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = Off                    ' Stack full/underflow will not cause Reset
    Debug = Off                     ' Background debugger disabled
    XINST = Off                     ' Extended Instruction Set and Indexed Addressing Mode disabled
    SCANE = Off                     ' Scanner module is Not available for use. SCANMD bit is ignored
    LVP = On                        ' Low Voltage programming enabled
    WDTCPS = WDTCPS_15              ' Watchdog Divider ratio 1:1048576 (32 seconds)
    WDTCWS = WDTCWS_7               ' Window always open (100%). Software control. Keyed access not required
    WDTCCS = LFINTOSC               ' WDT input clock selector->WDT reference clock is the 31.2kHz HFINTOSC output
    WRT0 = Off                      ' Block 0 (000800-001FFFh) not write-protected
    WRT1 = Off                      ' Block 1 (002000-003FFFh) not write-protected
    WRTC = Off                      ' Configuration registers (300000-30000Bh) not write-protected
    WRTB = Off                      ' Boot Block (000000-0007FFh) write-protected
    WRTD = Off                      ' Data EEPROM not write-protected
    Cp = Off                        ' UserNVM code protection disabled
    CPD = Off                       ' DataNVM code protection disabled
    EBTR0 = Off                     ' Block 0 (000800-001FFFh) not protected from table reads executed in other blocks
    EBTR1 = Off                     ' Block 1 (002000-003FFFh) not protected from table reads executed in other blocks
    EBTRB = Off                     ' Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
Config_End   

If one of you good people can get the range greater, it would be excellent. :-)

trastikata

Quote from: top204 on Apr 01, 2022, 09:44 AMIf one of you good people can get the range greater, it would be excellent. :-)

Hello Les, thank you for the library, I'll take a look to see if I find something.

However can you share the hardware design - to me it looks like a hardware design problem?

top204

#17
The hardware is two standard SX1278 modules, with the coiled wire antennas, plugged into breadboards containing a single PIC microcontroller. I have also tried with two E19-433M20S2 modules plugged into microcontrollers.

I know the range will be limited with the dreadful antennas, but I can see that it is not achieving range by looking at the current it consumes. It never goes above 20mA to 25mA or so... I have the current overload set for 200mA.

trastikata

Quote from: top204 on Apr 01, 2022, 10:02 AMI know the range will be limited with the dreadful antennas, but I can see that it is not achieving range by looking at the current it consumes. It never goes above 20mA to 25mA or so... I have the current overload set for 200mA.

Les, I'll try this weeken to test your libraries on my devices, which I know for sure achieve several kilometers range.

trastikata

Quote from: top204 on Apr 01, 2022, 10:02 AMIt never goes above 20mA to 25mA or so... I have the current overload set for 200mA.

Les, I started looking through your libraries and I see you are using the PA_BOOST pin in your SX_Setup() routine. Maybe those Ra-02 modules are not using the PA_BOOST pin but the RFO_LF pin instead?