Newer
Older
pyenergenie / src / energenie / drv / hrfm69.c
@David Whale David Whale on 15 May 2016 4 KB Implemented a better HRF_readfifo_burst.
/* hrf69.c  03/04/2016  D.J.Whale
 *
 * Hope RF RFM69 radio controller low level register interface.
 */

#include <stdlib.h>

#include "system.h"
#include "hrfm69.h"
#include "spi.h"
#include "trace.h"
#include "gpio.h"


/*---------------------------------------------------------------------------*/
// Write an 8 bit value to a register

void HRF_writereg(uint8_t addr, uint8_t data)
{
    TRACE_OUTS("writereg ");
    TRACE_OUTN(addr);
    TRACE_OUTC(' ');
    TRACE_OUTN(data);
    TRACE_NL();

    spi_select();
    spi_byte(addr | HRF_MASK_WRITE_DATA);
    spi_byte(data);
    spi_deselect();
}


/*---------------------------------------------------------------------------*/
// Read an 8 bit value from a register

uint8_t HRF_readreg(uint8_t addr)
{
    uint8_t result;

    spi_select();
    spi_byte(addr);
    result = spi_byte(0x00);
    spi_deselect();
    return result;
}


/*---------------------------------------------------------------------------*/
// Write all bytes in buf to the payload FIFO, in a single burst

void HRF_writefifo_burst(uint8_t* buf, uint8_t len)
{
    spi_select();
    spi_byte(HRF_ADDR_FIFO | HRF_MASK_WRITE_DATA);
    spi_frame(buf, NULL, len);
    spi_deselect();
}


/*---------------------------------------------------------------------------*/
// Read bytes from FIFO in burst mode.
// Never reads more than buflen bytes
// If rxlen != NULL, assumes payload is count byte preceded
// and will read that number of bytes following it,
// and report actual bytes read in *rxlen.
// count byte is always returned as first byte of buffer

HRF_RESULT HRF_readfifo_burst(uint8_t* buf, uint8_t buflen, uint8_t* rxlen)
{
    uint8_t data;
    uint8_t count;

    spi_select();

    /* Read the first byte, and then decide how to do byte counting */
    data = spi_byte(ADDR_FIFO);
    count = 1; /* Already received 1 byte */
    *(buf++) = data; /* always return to user, regardless of if count byte */

    /* Decide byte-counting strategy */
    if (rxlen != NULL)
    { /* count-byte preceeded */
        if (data > buflen)
        { /* Payload won't fit into user buffer */
            spi_deselect();
            return HRF_RESULT_ERR_BUFFER_TOO_SMALL;
        }
        /* else, first byte is count byte, reduce buflen and use as count */
        buflen = data;
    }
    else
    { /* buflen is expected length of payload */
        buflen--; /* Have already received one byte */
    }

    /* buflen is now expected length, count is byte received counter */
    while (buflen != 0)
    {
        data = spi_byte(ADDR_FIFO);
        *(buf++) = data;
        buflen--;
        count++;
    }
    spi_deselect();

    if (rxlen != NULL)
    { /* Record count of actual bytes received */
        *rxlen = count;
    }
    return HRF_RESULT_OK;
}


/*---------------------------------------------------------------------------*/
// Check to see if a register matches a specific value or not

HRF_RESULT HRF_checkreg(uint8_t addr, uint8_t mask, uint8_t value)
{
    uint8_t regval = HRF_readreg(addr);
    if ((regval & mask) == value)
    {
        return HRF_RESULT_OK_TRUE;
    }
    return HRF_RESULT_OK_FALSE;
}


/*---------------------------------------------------------------------------*/
// Poll a register until it meets some criteria

void HRF_pollreg(uint8_t addr, uint8_t mask, uint8_t value)
{
    if (gpio_sim)
    {
        TRACE_OUTS("gpio simulated, bailing early to prevent lockup\n");
        return;
    }

    while (! HRF_checkreg(addr, mask, value))
    {
      // busy wait
      //TODO: No timeout or error recovery? Can cause permanent lockup
    }
}


/*---------------------------------------------------------------------------*/
// Clear any data in the HRF payload FIFO, by reading until empty

void HRF_clear_fifo(void)
{
    //TODO: max fifolen is 66, should bail after that to prevent lockup
    //especially if radio crashed and SPI always returns stuck flag bit
    while ((HRF_readreg(HRF_ADDR_IRQFLAGS2) & HRF_MASK_FIFONOTEMPTY) == HRF_MASK_FIFONOTEMPTY)
    {
        HRF_readreg(HRF_ADDR_FIFO);
    }
}


/***** END OF FILE *****/