# virtual_wire

Virtual Wire

Author | Rob Jansen, Copyright © 2018..2019, all rights reserved.
Adapted-by |
Compiler | 2.5r2

Description

    Library for sending and receiving data over an RF Link based
                 on Virtual Wire. The driver implements a Phase Locked Loop to
                 increase sensitivity and so extend the range of the connection.
                 Next to that it uses a special encoding format for the bit
                 pattern to stay DC neutral. See sources for more information
                 on Virtual Wire.
                 A standard 433 MHz transmitter and 433 MHz receiver was used
                 for testing this driver using a maximum bitrate of 2000 bits/s.
                 In order to use this driver the main program must have the
                 following defined (this to make this driver PIC independent):
                 -) An alias for the tranmission pin vw_tx_pin.
                 -) An alias for the receive pin vw_rx_pin.
                 -) Initializing a timer that is used for transmission and
                    reception. The timer must run at 8 times the bitrate.
                 -) An interrupt routine of the used timer which must call the
                    vw_service() procedure.
                 A transmitter only and receiver only version is also available
                 to save data space and code space for use in smaller PICs.

Sources

    http://www.airspayce.com/mikem/arduino/VirtualWire.pdf

Notes

    Changes to the original driver that was created for Arduino:
    *) From C converted to JAL. This required an extra receive buffer because
       of the lack of pointers which could not pass a receive buffer.
    *) The inverting of the output and input signal was removed.
    *) The 6 to 4 conversion was changed into a look-up table to improve speed.
    *) The maximum message length was reduced to 10 to save data space but can
       be changed by the user by setting VW_MAX_MESSAGE_LEN to another value.
    *) The transmission header was moved from data to constant as to decrease
       the size of the transmit buffer and so save data space.
    *) The transmission buffer and reception buffer were combined into one
       buffer to save data space. This can be done since the original driver does
       not support transmission and reception at the same time.
    *) The bit rate is defined by the user by initializing the used timer.

Dependencies

No dependency found

## Summary

### Global variables/contants

- `var byte vw_rx_bit_count`
- `const byte VW_HEADER_LEN = 8`
- `var byte vw_tx_sample`
- `var bit vw_rx_last_sample`
- `const byte VW_RAMP_INC_RETARD = (VW_RAMP_INC - VW_RAMP_ADJUST)`
- `var byte vw_rx_pll_ramp`
- `var bit vw_rx_active`
- `var bit vw_tx_header`
- `const byte symbols_c[] =`
- `const byte vw_tx_header_buf[VW_HEADER_LEN]`
- `var word data_2`
- `var byte vw_tx_index`
- `var bit vw_rx_enabled`
- `const byte VW_MAX_PAYLOAD = VW_MAX_MESSAGE_LEN - 3`
- `var byte vw_rx_integrator`
- `var dword vw_rx_bad`
- `var word vw_rx_bits`
- `const byte VW_RX_SAMPLES_PER_BIT = 8`
- `var dword vw_rx_good`
- `const byte VW_RAMP_INC = (VW_RX_RAMP_LEN/VW_RX_SAMPLES_PER_BIT)`
- `const byte VW_RAMP_ADJUST = 9`
- `const byte symbols_d[] =`
- `var byte vw_rx_count`
- `const byte VW_RX_RAMP_LEN = 160`
- `const byte VW_RAMP_INC_ADVANCE = (VW_RAMP_INC + VW_RAMP_ADJUST)`
- `var byte vw_rx_len`
- `var bit vw_tx_enabled`
- `var byte vw_rx_return_buf[VW_MAX_PAYLOAD]`
- `var byte vw_tx_bit`
- `var bit vw_rx_sample`
- `var byte this_byte`
- `var byte vw_tx_rx_buf[VW_MAX_MESSAGE_LEN * 2]`
- `var byte vw_tx_len`
- `var bit vw_rx_done`
- `const byte VW_RAMP_TRANSITION = VW_RX_RAMP_LEN/2`

### Procedures

- `vw_rx_start()`
- `vw_service()`
- `vw_tx_stop()`
- `vw_rx_stop()`
- `vw_wait_rx()`
- `vw_wait_tx()`
- `vw_reset_rx_good_bad_count()`
- `vw_init()`

Private

- `_vw_pll()`

### Functions

- `vw_get_message(byte in out len) return bit`
- `vw_tx_active() return bit`
- `vw_send(byte in buf[], byte in len) return bit`
- `vw_get_rx_good() return dword`
- `vw_get_rx_bad() return dword`
- `vw_have_message() return bit`

Private

- `_vw_calc_crc(word in crc, byte in data) return word`

## API details

### Global variables/contants

- `var byte vw_rx_bit_count`

      How many bits of message we have received. Ranges from 0 to 12

- `const byte VW_HEADER_LEN = 8`

      Outgoing message bits grouped as 6-bit words
      36 alternating 1/0 bits, followed by 12 bits of start symbol
      Followed immediately by the 4-6 bit encoded byte count,
      message buffer and 2 byte FCS
      Each byte from the byte count on is translated into 2x6-bit words
      Caution, each symbol is transmitted LSBit first,
      but each byte is transmitted high nybble first

- `var byte vw_tx_sample`

      Sample number for the transmitter. Runs 0 to 7 during one bit interval.

- `var bit vw_rx_last_sample`

      Last receivers sample.

- `const byte VW_RAMP_INC_RETARD = (VW_RAMP_INC - VW_RAMP_ADJUST)`

      Internal ramp adjustment parameter

- `var byte vw_rx_pll_ramp`

      PLL ramp, varies between 0 and VW_RX_RAMP_LEN-1 (159) over
      VW_RX_SAMPLES_PER_BIT (8) samples per nominal bit time.
      When the PLL is synchronised, bit transitions happen at about the
      0 mark.

- `var bit vw_rx_active`

      Flag indicates if we have seen the start symbol of a new message and are
      in the processes of reading and decoding it

- `var bit vw_tx_header`

      Indicates that the header must be transmitted first.

- `const byte symbols_c[] =`

      4 bit to 6 bit symbol converter table for coding
      Used to convert the high and low nibbles of the transmitted data
      into 6 bit symbols for transmission. Each 6-bit symbol has 3 1s and 3 0s
      with at most 3 consecutive identical bits

- `const byte vw_tx_header_buf[VW_HEADER_LEN]`

      Transmit header to synchronize the receiver.

- `var word data_2`

  No documentation found

- `var byte vw_tx_index`

      Index of he next symbot to send. Ranges from 0 to VW_Tx_Len

- `var bit vw_rx_enabled`

      Flag to indicate the receiver PLL is to run

- `const byte VW_MAX_PAYLOAD = VW_MAX_MESSAGE_LEN - 3`

      The maximum payload length, count (1) and FCS (2) must be subtracted.

- `var byte vw_rx_integrator`

      This is the integrate and dump integral. If there are <5 0 samples in the PLL cycle
      the bit is declared a 0, else a 1

- `var dword vw_rx_bad`

      Number of bad messages received and dropped due to bad lengths. Only
      available in complete virtual wire driver for testing purposes.

- `var word vw_rx_bits`

      Last 12 bits received, so we can look for the start symbol

- `const byte VW_RX_SAMPLES_PER_BIT = 8`

      Number of samples per bit.

- `var dword vw_rx_good`

      Number of good messages received. Only available in complete virtual
      wire driver for testing purposes.

- `const byte VW_RAMP_INC = (VW_RX_RAMP_LEN/VW_RX_SAMPLES_PER_BIT)`

      Ramp adjustment parameters
      Standard is if a transition occurs before VW_RAMP_TRANSITION (80) in the ramp,
      the ramp is retarded by adding VW_RAMP_INC_RETARD (11)
      else by adding VW_RAMP_INC_ADVANCE (29)
      If there is no transition it is adjusted by VW_RAMP_INC (20)
      Internal ramp adjustment parameter

- `const byte VW_RAMP_ADJUST = 9`

      Internal ramp adjustment parameter

- `const byte symbols_d[] =`

      Conversion table for 6 to 4 symbol decoding using a lookup table. We only need
      to indicate the values from the encoding table. Without lookup table the
      conversion would take too long.

- `var byte vw_rx_count`

      The incoming message expected length

- `const byte VW_RX_RAMP_LEN = 160`

      The size of the receiver ramp. Ramp wraps modulo this number

- `const byte VW_RAMP_INC_ADVANCE = (VW_RAMP_INC + VW_RAMP_ADJUST)`

      Internal ramp adjustment parameter

- `var byte vw_rx_len`

      The incoming message buffer length received so far

- `var bit vw_tx_enabled`

      Indicates if the transmitter is active.

- `var byte vw_rx_return_buf[VW_MAX_PAYLOAD]`

      The buffer to copy the return message to for the main program. This buffer
      is smaller than the combined vw_tx_rx_buf since it only holds data no symbol.s

- `var byte vw_tx_bit`

      Bit number of next bot to send

- `var bit vw_rx_sample`

      Current receiver sample

- `var byte this_byte`

  No documentation found

- `var byte vw_tx_rx_buf[VW_MAX_MESSAGE_LEN * 2]`

      Transmit and receive buffer. The symbol buffer for transmission is combined
      with the data buffer for reception.

- `var byte vw_tx_len`

      Number of symbols in VW_Tx_Buf to be sent

- `var bit vw_rx_done`

      Flag to indicate that a new message is available

- `const byte VW_RAMP_TRANSITION = VW_RX_RAMP_LEN/2`

      Internal ramp adjustment parameter

### Procedures

- `vw_rx_start()`

      Enable the receiver. When a message becomes available, vw_rx_done flag
      is set, and vw_wait_rx() will return.

- `vw_service()`

      This is the service routine that must be called by the main program when the
      timer overflows. Its job is to output the next bit from the transmitter
      (every 8 calls) and to call the PLL code if the receiver is enabled.

- `vw_tx_stop()`

      Stop the transmitter, call when all bits are sent

- `vw_rx_stop()`

      Disable the receiver

- `vw_wait_rx()`

      Wait for the receiver to get a message
      Busy-wait loop until the ISR says a message is available
      can then call vw_get_message()

- `vw_wait_tx()`

      Wait for the transmitter to become available
      Busy-wait loop until the ISR says the message has been sent

- `vw_reset_rx_good_bad_count()`

      Reset the good and bad received message count

- `vw_init()`

      Initialize the virtual wire driver.

Private

- `_vw_pll()`

      Called 8 times per bit period by the timer interrupt routine
      Phase locked loop tries to synchronise with the transmitter so that bit
      transitions occur at about the time vw_rx_pll_ramp is 0
      Then the average is computed over each bit period to deduce the bit value

### Functions

- `vw_get_message(byte in out len) return bit`

      Get the last message received (without byte count or FCS)
      Copy at most len bytes, set len to the actual number copied
      Return true if there is a message and the FCS is OK
      The data is copied to a receive buffer.

- `vw_tx_active() return bit`

      Return true if the transmitter is active

- `vw_send(byte in buf[], byte in len) return bit`

      Wait until transmitter is available and encode and queue the message
      into vw_tx_buf
      The message is raw bytes, with no packet structure imposed
      It is transmitted preceded a byte count and followed by 2 FCS bytes

- `vw_get_rx_good() return dword`

      Return the number of good received messages count.

- `vw_get_rx_bad() return dword`

      Return the number of bad messages received and dropped due to bad lengths.

- `vw_have_message() return bit`

      Return true if there is a message available

Private

- `_vw_calc_crc(word in crc, byte in data) return word`

      Calculate new crc over given data. Formula is:
      Xexp16 + Xexp12 + Xexp5 + 1

## Related samples

Here are the list of samples which use this library:

16f1825 | 16f1825_virtual_wire_receiver.jal
16f1825 | 16f1825_virtual_wire_transmitter.jal