adafruit / Adafruit_CircuitPython_RFM69

CircuitPython module for the RFM69 series of 433/915 mhz packet radios.
MIT License
31 stars 28 forks source link

Can receive from Radiohead with different modem config, but it is unable to receive back from this library #50

Closed matteius closed 8 months ago

matteius commented 9 months ago

In the following code you can see I am changing the

rfm69.bitrate = 2400
rfm69.preamble_length = 3
rfm69.frequency_deviation = 4800  # 4.8khz

This works to match the modem config of the RadioHead Arduino library for receiving from that device, but when it comes to sending, the packets only get sent if I keep the default 250/250 settings making me thing there is something I need to do on the circuit python side to set the modem config registers the same, but it is not clear how.

# SPDX-FileCopyrightText: 2018 Tony DiCola for Adafruit Industries
# SPDX-License-Identifier: MIT

# Simple example to send a message and then wait indefinitely for messages
# to be received.  This uses the default RadioHead compatible GFSK_Rb250_Fd250
# modulation and packet format for the radio.
import board
import busio
import digitalio
import time
import adafruit_rfm69
from neopixel import NeoPixel

num_pixels = 24
pixels = NeoPixel(board.GP16, num_pixels)
pixels.brightness = 0.5

def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if pos < 0 or pos > 255:
        r = g = b = 0
    elif pos < 85:
        r = int(pos * 3)
        g = int(255 - pos * 3)
        b = 0
    elif pos < 170:
        pos -= 85
        r = int(255 - pos * 3)
        g = 0
        b = int(pos * 3)
    else:
        pos -= 170
        r = 0
        g = int(pos * 3)
        b = int(255 - pos * 3)
    return (r, g, b)

def rainbow_cycle(wait):
    pixels.brightness = 1
    for i in range(num_pixels):
        pixel_index = (i * 256 // num_pixels)
        pixels[i] = wheel(pixel_index & 255)
    pixels.show()
    time.sleep(wait)
    pixels.brightness = 0
    pixels.show()

# Define radio parameters.
RADIO_FREQ_MHZ = 915.0  # Frequency of the radio in Mhz. Must match your
# module! Can be a value like 915.0, 433.0, etc.

# Define pins connected to the chip, use these if wiring up the breakout according to the guide:
CS = digitalio.DigitalInOut(board.GP5)
RESET = digitalio.DigitalInOut(board.GP27)

# Initialize SPI bus.
spi = busio.SPI(board.GP2, MOSI=board.GP3, MISO=board.GP4)

time.sleep(1.0)

# Initialze RFM radio
rfm69 = adafruit_rfm69.RFM69(spi, CS, RESET, RADIO_FREQ_MHZ, baudrate=1000000)
rfm69.bitrate = 2400
rfm69.preamble_length = 3
rfm69.frequency_deviation = 4800  # 4.8khz
rfm69.tx_power = 20
print(rfm69.bitrate)
print(rfm69.frequency_deviation)
print(rfm69.tx_power)

# Optionally set an encryption key (16 byte AES key). MUST match both
# on the transmitter and receiver (or be set to None to disable/the default).
# REDACTED

# Print out some chip state:
print("Temperature: {0}C".format(rfm69.temperature))
print("Frequency: {0}mhz".format(rfm69.frequency_mhz))
print("Bit rate: {0}kbit/s".format(rfm69.bitrate / 1000))
print("Frequency deviation: {0}hz".format(rfm69.frequency_deviation))

# Send a packet.  Note you can only send a packet up to 60 bytes in length.
# This is a limitation of the radio packet size, so if you need to send larger
# amounts of data you will need to break it into smaller send calls.  Each send
# call will wait for the previous one to finish before continuing.
#rfm69.send(bytes("Hello world!\r\n", "utf-8"))
#print("Sent hello world message!")

# Wait to receive packets.  Note that this library can't receive data at a fast
# rate, in fact it can only receive and process one 60 byte packet at a time.
# This means you should only use this for low bandwidth scenarios, like sending
# and receiving a single message at a time.
print("Waiting for packets...")             
while True:
    packet = rfm69.receive()
    # Optionally change the receive timeout from its default of 0.5 seconds:
    # packet = rfm69.receive(timeout=5.0)
    # If no packet was received during the timeout then None is returned.
    if packet is None:
        # Packet has not been received
        # print("Received nothing! Listening again...")
        pass
    else:
        # Received a packet!
        # Print out the raw bytes of the packet:
        t = time.time()
        print("Received at {0} (raw bytes): {1}".format(t, packet))
        print(rfm69.rssi)
        # And decode to ASCII text and print it too.  Note that you always
        # receive raw bytes and need to convert to a text format like ASCII
        # if you intend to do string processing on your data.  Make sure the
        # sending side is sending ASCII data before you try to decode!
        try:
            time.sleep(.5)
            packet_text = str(packet, "ascii")
            print("Received at {0} (ASCII): {1}".format(t, packet_text))
            if "Mail Recieved" in packet_text:
                print("Send Ack")
                print(rfm69.transmit())
                print(rfm69.send(bytes("Ack", "utf-8"), keep_listening=True))
                print(rfm69.packet_sent())
                rainbow_cycle(2.0)
            time.sleep(1.0)
        except:
            pass
matteius commented 9 months ago

This seems to only happen at the lower modem transmission rates, for example, this still works: rf69.setModemConfig(RH_RF69::GFSK_Rb57_6Fd120);

# Initialze RFM radio
rfm69 = adafruit_rfm69.RFM69(spi, CS, RESET, RADIO_FREQ_MHZ, baudrate=1000000)
rfm69.frequency_mhz = 915
rfm69.bitrate = 57600
rfm69.preamble_length = 3
rfm69.frequency_deviation = 120000  # 4.8khz
rfm69.tx_power = 20
print(rfm69.bitrate)
print(rfm69.frequency_deviation)
print(rfm69.tx_power)
jerryneedell commented 8 months ago

Just to clarify the issue, for the 2400 bitrate, example you do receive packets from RadioHead but packets you send to Radiohead are not received. Just to check, can you also provide the Radiohead configuration (rf69.setModemConfig) taht you used for the failing example?

jerryneedell commented 8 months ago

I am able to send and receive using

rf69.setModemConfig(RH_RF69::GFSK_Rb4_8Fd4_8) on the RadioHead side and

rfm69.bitrate = 2400
rfm69.preamble_length = 3
rfm69.frequency_deviation = 4800  # 4.8khz

on the CircuitPython side

jerryneedell commented 8 months ago

Perhaps I am not understanding the issue.

matteius commented 8 months ago

@jerryneedell I will do more testing this weekend, but I thin what I was seeing in my last round of tests was when I set lower speed configs such as RH_RF69::GFSK_Rb38_4Fd76_8 it appears to work on the 5V USB, but once I go to the 3.7V lipo battery only, then it transmits fine but fails to recieve on the feather/radiohead side. I haven't tried the reverse yet of a lipo battery on the circuitpython side because that pico I am using doesn't have a connector, but I have a different one I can swap out and do more tests with, but I am beginning to think its a difference in how the radio behaves under different votlages.

Here is the code on both sides, I was lighting up a neo pixel ring when mail is received, and sending the packet until the radio gets an ack, then it stops. When hooked up to the 5V it seems to work, and then going off battery it keeps pinging and lighting up the neopixel and not getting the Ack, if that makes sense.

// rf69 demo tx rx.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple messaging client
// with the RH_RF69 class. RH_RF69 class does not provide for addressing
// or reliability, so you should only use RH_RF69 if you do not need the
// higher level messaging abilities.
// It is designed to work with the other example RadioHead69_RawDemo_RX.
// Demonstrates the use of AES encryption, setting the frequency and
// modem configuration.

#include <SPI.h>
#include <RH_RF69.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL343.h>

/************ Radio Setup ***************/

// Change to 434.0 or other frequency, must match RX's freq!
#define RF69_FREQ 915.0
#define RFM69_HW true

// First 3 here are boards w/radio BUILT-IN. Boards using FeatherWing follow.
#if defined (__AVR_ATmega32U4__)  // Feather 32u4 w/Radio
  #define RFM69_CS    8
  #define RFM69_INT   7
  #define RFM69_RST   4
  #define LED        13

#elif defined(ADAFRUIT_FEATHER_M0) || defined(ADAFRUIT_FEATHER_M0_EXPRESS) || defined(ARDUINO_SAMD_FEATHER_M0)  // Feather M0 w/Radio
  #define RFM69_CS    8
  #define RFM69_INT   3
  #define RFM69_RST   4
  #define LED        13

#elif defined(ARDUINO_ADAFRUIT_FEATHER_RP2040_RFM)  // Feather RP2040 w/Radio
  #define RFM69_CS   16
  #define RFM69_INT  21
  #define RFM69_RST  17
  #define LED        LED_BUILTIN

#elif defined (__AVR_ATmega328P__)  // Feather 328P w/wing
  #define RFM69_CS    4  //
  #define RFM69_INT   3  //
  #define RFM69_RST   2  // "A"
  #define LED        13

#elif defined(ESP8266)  // ESP8266 feather w/wing
  #define RFM69_CS    2  // "E"
  #define RFM69_INT  15  // "B"
  #define RFM69_RST  16  // "D"
  #define LED         0

#elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) || defined(ARDUINO_NRF52840_FEATHER) || defined(ARDUINO_NRF52840_FEATHER_SENSE)
  #define RFM69_CS   10  // "B"
  #define RFM69_INT   9  // "A"
  #define RFM69_RST  11  // "C"
  #define LED        13

#elif defined(ESP32)  // ESP32 feather w/wing
  #define RFM69_CS   33  // "B"
  #define RFM69_INT  27  // "A"
  #define RFM69_RST  13  // same as LED
  #define LED        13

#elif defined(ARDUINO_NRF52832_FEATHER)  // nRF52832 feather w/wing
  #define RFM69_CS   11  // "B"
  #define RFM69_INT  31  // "C"
  #define RFM69_RST   7  // "A"
  #define LED        17

#endif

/* Teensy 3.x w/wing
#define RFM69_CS     10  // "B"
#define RFM69_INT     4  // "C"
#define RFM69_RST     9  // "A"
#define RFM69_IRQN   digitalPinToInterrupt(RFM69_INT)
*/

/* WICED Feather w/wing
#define RFM69_CS     PB4  // "B"
#define RFM69_INT    PA15 // "C"
#define RFM69_RST    PA4  // "A"
#define RFM69_IRQN   RFM69_INT
*/

// ADXL Constants
#define ADXL343_SCK 13
#define ADXL343_MISO 12
#define ADXL343_MOSI 11
#define ADXL343_CS 10

/** The input pin to enable the interrupt on, connected to INT1 on the ADXL. */
#define INPUT_PIN_INT1 19 //  A5 interrupt pin

// Singleton instance of the radio driver
RH_RF69 rf69(RFM69_CS, RFM69_INT);

/* Assign a unique ID to this sensor at the same time */
Adafruit_ADXL343 accel = Adafruit_ADXL343(12348);
int16_t packetnum = 0;  // packet counter, we increment per xmission

uint32_t g_tap_count = 0;
int_config g_int_config_enabled = { 0 };
int_config g_int_config_map = { 0 };

/** Interrupt service routine for INT1 events. This will be called when a single tap is detected. */
void int1_isr(void)
{
  Serial.print("Interupt!");
  g_tap_count = 1;
  // SCB->SCR = 0;   // Resume normal operation
}

/** Configures the HW interrupts on the ADXL343 and the target MCU. */
void config_interrupts(void)
{
  /* NOTE: Once an interrupt fires on the ADXL you can read a register
   *  to know the source of the interrupt, but since this would likely
   *  happen in the 'interrupt context' performing an I2C read is a bad
   *  idea since it will block the device from handling other interrupts
   *  in a timely manner.
   *
   *  The best approach is to try to make use of only two interrupts on
   *  two different interrupt pins, so that when an interrupt fires, based
   *  on the 'isr' function that is called, you already know the int source.
   */

  /* Attach interrupt inputs on the MCU. */
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(INPUT_PIN_INT1, INPUT);
  attachInterrupt(digitalPinToInterrupt(INPUT_PIN_INT1), int1_isr, RISING);

  /* Enable interrupts on the accelerometer. */
  g_int_config_enabled.bits.overrun    = false;    /* Set the INT1 */
  g_int_config_enabled.bits.watermark  = false;
  g_int_config_enabled.bits.freefall   = false;
  g_int_config_enabled.bits.inactivity = false;
  g_int_config_enabled.bits.activity   = false;
  g_int_config_enabled.bits.double_tap = false;
  g_int_config_enabled.bits.single_tap = true;
  g_int_config_enabled.bits.data_ready = false;
  accel.enableInterrupts(g_int_config_enabled);

  /* Map specific interrupts to one of the two INT pins. */
  g_int_config_map.bits.overrun    = ADXL343_INT1;
  g_int_config_map.bits.watermark  = ADXL343_INT1;
  g_int_config_map.bits.freefall   = ADXL343_INT1;
  g_int_config_map.bits.inactivity = ADXL343_INT1;
  g_int_config_map.bits.activity   = ADXL343_INT1;
  g_int_config_map.bits.double_tap = ADXL343_INT1;
  g_int_config_map.bits.single_tap = ADXL343_INT1;
  g_int_config_map.bits.data_ready = ADXL343_INT1;
  accel.mapInterrupts(g_int_config_map);

  SYSCTRL->XOSC32K.reg |=  (SYSCTRL_XOSC32K_RUNSTDBY | SYSCTRL_XOSC32K_ONDEMAND); // set external 32k oscillator to run when idle or sleep mode is chosen
  REG_GCLK_CLKCTRL  |= GCLK_CLKCTRL_ID(GCM_EIC) |  // generic clock multiplexer id for the external interrupt controller
                       GCLK_CLKCTRL_GEN_GCLK1 |  // generic clock 1 which is xosc32k
                       GCLK_CLKCTRL_CLKEN;       // enable it
  while (GCLK->STATUS.bit.SYNCBUSY);              // write protected, wait for sync

  EIC->WAKEUP.reg |= (1 << digitalPinToInterrupt(INPUT_PIN_INT1));

  //PM->SLEEP.reg |= PM_SLEEP_IDLE_CPU;  // Enable Idle0 mode - sleep CPU clock only
  PM->SLEEP.reg |= PM_SLEEP_IDLE_AHB; // Idle1 - sleep CPU and AHB clocks
  //PM->SLEEP.reg |= PM_SLEEP_IDLE_APB; // Idle2 - sleep CPU, AHB, and APB clocks

  __enable_irq();
}

void setup() {
  Serial.begin(115200);
  while (!Serial); // Wait for Serial Console (comment out line if no computer)
  Serial.println("Accelerometer Test"); Serial.println("");
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH); // Show we're awake

  if(!accel.begin()) {
    Serial.println("ADXL343 not found, check your wiring.");
  } else {
    Serial.println("ADXL343 found!");

    /* Display some basic information on this sensor */
    displaySensorDetails();

    /* Display additional settings (outside the scope of sensor_t) */
    displayDataRate();
    displayRange();
    Serial.println("");

    /* Set the range to whatever is appropriate for your project */
    accel.setRange(ADXL343_RANGE_2_G);
    accel.writeRegister(0x1D, 0x11);
    //accel.writeRegister(0x21, 0x03);
    Serial.println(accel.readRegister(0x1D));
    Serial.println(accel.readRegister(0x21));

    /* Configure the HW interrupts. */
    config_interrupts();

    Serial.println("ADXL343 init complete. Waiting for single tap INT activity.");
  }

  pinMode(LED, OUTPUT);
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, LOW);

  Serial.println("Feather RFM69 TX Test!");
  Serial.println();

  // manual reset
  digitalWrite(RFM69_RST, HIGH);
  delay(10);
  digitalWrite(RFM69_RST, LOW);
  delay(10);

  if (!rf69.init()) {
    Serial.println("RFM69 radio init failed");
    while (1);
  }
  Serial.println("RFM69 radio init OK!");
  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module)
  // No encryption
  if (!rf69.setFrequency(RF69_FREQ)) {
    Serial.println("setFrequency failed");
  }

  //uint8_t    reg_02;   ///< Value for register RH_RF69_REG_02_DATAMODUL
  //uint8_t    reg_03;   ///< Value for register RH_RF69_REG_03_BITRATEMSB
  //uint8_t    reg_04;   ///< Value for register RH_RF69_REG_04_BITRATELSB
  //uint8_t    reg_05;   ///< Value for register RH_RF69_REG_05_FDEVMSB
  //uint8_t    reg_06;   ///< Value for register RH_RF69_REG_06_FDEVLSB
  //uint8_t    reg_19;   ///< Value for register RH_RF69_REG_19_RXBW
  //uint8_t    reg_1a;   ///< Value for register RH_RF69_REG_1A_AFCBW
  //uint8_t    reg_37;   ///< Value for register RH_RF69_REG_37_PACKETCONFIG1
  // For compat with RFM69 Struct_send
  rf69.setModemConfig(RH_RF69::GFSK_Rb38_4Fd76_8);
  rf69.setPreambleLength(3);
  uint8_t syncwords[] = { 0x2d, 0xD4 };
  rf69.setSyncWords(syncwords, sizeof(syncwords));
  rf69.printRegister(0x03);
  rf69.printRegister(0x04);
  rf69.printRegister(0x05);
  rf69.printRegister(0x06);
  rf69.printRegister(0x19);
  rf69.printRegister(0x1a);
  rf69.printRegister(0x37);
  //const RH_RF69::ModemConfig modemConfig = {0x01, 0x7D, 0x00, 0x00, 0x52, 0xF4, 0XF5, 0XD0};
  //rf69.setModemRegisters(&modemConfig);

  // If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the
  // ishighpowermodule flag set like this:
  rf69.setTxPower(20, true);  // range from 14-20 for power, 2nd arg must be true for 69HCW

  // The encryption key has to be the same as the one in the server
  uint8_t key[] = { REDACTED };
  rf69.setEncryptionKey(key);

  Serial.print("RFM69 radio @");  Serial.print((int)RF69_FREQ);  Serial.println(" MHz");
}

void displaySensorDetails(void)
{
  sensor_t sensor;
  accel.getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" m/s^2");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" m/s^2");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" m/s^2");  
  Serial.println("------------------------------------");
  Serial.println("");
  delay(500);
}

void displayDataRate(void)
{
  Serial.print  ("Data Rate:    "); 

  switch(accel.getDataRate())
  {
    case ADXL343_DATARATE_3200_HZ:
      Serial.print  ("3200 "); 
      break;
    case ADXL343_DATARATE_1600_HZ:
      Serial.print  ("1600 "); 
      break;
    case ADXL343_DATARATE_800_HZ:
      Serial.print  ("800 "); 
      break;
    case ADXL343_DATARATE_400_HZ:
      Serial.print  ("400 "); 
      break;
    case ADXL343_DATARATE_200_HZ:
      Serial.print  ("200 "); 
      break;
    case ADXL343_DATARATE_100_HZ:
      Serial.print  ("100 "); 
      break;
    case ADXL343_DATARATE_50_HZ:
      Serial.print  ("50 "); 
      break;
    case ADXL343_DATARATE_25_HZ:
      Serial.print  ("25 "); 
      break;
    case ADXL343_DATARATE_12_5_HZ:
      Serial.print  ("12.5 "); 
      break;
    case ADXL343_DATARATE_6_25HZ:
      Serial.print  ("6.25 "); 
      break;
    case ADXL343_DATARATE_3_13_HZ:
      Serial.print  ("3.13 "); 
      break;
    case ADXL343_DATARATE_1_56_HZ:
      Serial.print  ("1.56 "); 
      break;
    case ADXL343_DATARATE_0_78_HZ:
      Serial.print  ("0.78 "); 
      break;
    case ADXL343_DATARATE_0_39_HZ:
      Serial.print  ("0.39 "); 
      break;
    case ADXL343_DATARATE_0_20_HZ:
      Serial.print  ("0.20 "); 
      break;
    case ADXL343_DATARATE_0_10_HZ:
      Serial.print  ("0.10 "); 
      break;
    default:
      Serial.print  ("???? "); 
      break;
  }  
  Serial.println(" Hz");  
}

void displayRange(void)
{
  Serial.print  ("Range:         +/- "); 

  switch(accel.getRange())
  {
    case ADXL343_RANGE_16_G:
      Serial.print  ("16 "); 
      break;
    case ADXL343_RANGE_8_G:
      Serial.print  ("8 "); 
      break;
    case ADXL343_RANGE_4_G:
      Serial.print  ("4 "); 
      break;
    case ADXL343_RANGE_2_G:
      Serial.print  ("2 "); 
      break;
    default:
      Serial.print  ("?? "); 
      break;
  }  
  Serial.println(" g");  
}

void loop() {
  /* Get a new sensor event */
  sensors_event_t event;
  accel.getEvent(&event);
  unsigned long currentTime = millis();
  char radiopacket[30] = "";
  sprintf(radiopacket, "Reporting in at: %lu", currentTime);
  rf69.send((uint8_t *)radiopacket, strlen(radiopacket));
  rf69.waitPacketSent();

  digitalWrite(LED_BUILTIN, LOW); // Show we're asleep
  if (g_tap_count) {
    bool messageComplete = false;
    Serial.println("Single tap detected!");
    accel.checkInterrupts();
    sprintf(radiopacket, "Mail Recieved: %lu", currentTime);
    uint8_t buf[RH_RF69_MAX_MESSAGE_LEN] = "";
    uint8_t len = sizeof(buf);
    rf69.setModeRx();
    rf69.recv(buf, &len);
    delay(100);
    rf69.send((uint8_t *)radiopacket, strlen(radiopacket));
    while (!messageComplete)
    {
        if (rf69.waitAvailableTimeout(50)) {
          // Should be a reply message for us now   
          if (rf69.recv(buf, &len))
          {
            Serial.print("got reply: ");
            Serial.println((char*)buf);
            if (buf[0] == 'A' && buf[1] == 'c' && buf[2] == 'k') {
              Serial.println("Message complete!");
              messageComplete = true;
            } 
          }
        } 
        else {
          // Serial.println("recv failed");
          rf69.send((uint8_t *)radiopacket, strlen(radiopacket));
          rf69.waitPacketSent();
        }
    }
    /* Clear the interrupt as a side-effect of reading the interrupt source register. */
    g_tap_count = 0;
    accel.checkInterrupts();
    // It is either Idle mode or Standby mode, not both. 
    // __WFI();
    // SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;   // Enable Standby or "deep sleep" mode
  }
  delay(2000);
}
# SPDX-FileCopyrightText: 2018 Tony DiCola for Adafruit Industries
# SPDX-License-Identifier: MIT

# Simple example to send a message and then wait indefinitely for messages
# to be received.  This uses the default RadioHead compatible GFSK_Rb250_Fd250
# modulation and packet format for the radio.
import board
import busio
import digitalio
import time
import adafruit_rfm69
from neopixel import NeoPixel

num_pixels = 24
pixels = NeoPixel(board.GP16, num_pixels)
pixels.brightness = 0.5

def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if pos < 0 or pos > 255:
        r = g = b = 0
    elif pos < 85:
        r = int(pos * 3)
        g = int(255 - pos * 3)
        b = 0
    elif pos < 170:
        pos -= 85
        r = int(255 - pos * 3)
        g = 0
        b = int(pos * 3)
    else:
        pos -= 170
        r = 0
        g = int(pos * 3)
        b = int(255 - pos * 3)
    return (r, g, b)

def rainbow_cycle(wait):
    pixels.brightness = 1
    for i in range(num_pixels):
        pixel_index = (i * 256 // num_pixels)
        pixels[i] = wheel(pixel_index & 255)
    pixels.show()
    time.sleep(wait)
    pixels.brightness = 0
    pixels.show()

# Define radio parameters.
RADIO_FREQ_MHZ = 915.0  # Frequency of the radio in Mhz. Must match your
# module! Can be a value like 915.0, 433.0, etc.

# Define pins connected to the chip, use these if wiring up the breakout according to the guide:
CS = digitalio.DigitalInOut(board.GP5)
RESET = digitalio.DigitalInOut(board.GP27)

# Initialize SPI bus.
spi = busio.SPI(board.GP2, MOSI=board.GP3, MISO=board.GP4)

time.sleep(1.0)

# Initialze RFM radio
rfm69 = adafruit_rfm69.RFM69(spi, CS, RESET, RADIO_FREQ_MHZ, baudrate=1000000)
rfm69.frequency_mhz = 915
rfm69.preamble_length = 3
rfm69.bitrate = 38400   
rfm69.frequency_deviation = 76800  # 4.8khz
rfm69.tx_power = 17
print(rfm69.bitrate)
print(rfm69.frequency_deviation)
print(rfm69.tx_power)

# Optionally set an encryption key (16 byte AES key). MUST match both
# on the transmitter and receiver (or be set to None to disable/the default).
fm69.encryption_key = (
    b"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08"
)

# Print out some chip state:
print("Temperature: {0}C".format(rfm69.temperature))
print("Frequency: {0}mhz".format(rfm69.frequency_mhz))
print("Bit rate: {0}kbit/s".format(rfm69.bitrate / 1000))
print("Frequency deviation: {0}hz".format(rfm69.frequency_deviation))

# Send a packet.  Note you can only send a packet up to 60 bytes in length.
# This is a limitation of the radio packet size, so if you need to send larger
# amounts of data you will need to break it into smaller send calls.  Each send
# call will wait for the previous one to finish before continuing.
#rfm69.send(bytes("Hello world!\r\n", "utf-8"))
#print("Sent hello world message!")

# Wait to receive packets.  Note that this library can't receive data at a fast
# rate, in fact it can only receive and process one 60 byte packet at a time.
# This means you should only use this for low bandwidth scenarios, like sending
# and receiving a single message at a time.
print("Waiting for packets...")             
while True:
    packet = rfm69.receive()
    # Optionally change the receive timeout from its default of 0.5 seconds:
    # packet = rfm69.receive(timeout=5.0)
    # If no packet was received during the timeout then None is returned.
    if packet is None:
        # Packet has not been received
        # print("Received nothing! Listening again...")
        pass
    else:
        # Received a packet!
        # Print out the raw bytes of the packet:
        t = time.time()
        print("Received at {0} (raw bytes): {1}".format(t, packet))
        print(rfm69.rssi)
        # And decode to ASCII text and print it too.  Note that you always
        # receive raw bytes and need to convert to a text format like ASCII
        # if you intend to do string processing on your data.  Make sure the
        # sending side is sending ASCII data before you try to decode!
        try:
            time.sleep(.5)
            packet_text = str(packet, "ascii")
            print("Received at {0} (ASCII): {1}".format(t, packet_text))
            if "Mail Recieved" in packet_text:
                print("Send Ack")
                print(rfm69.transmit())
                print(rfm69.send(bytes("Ack", "utf-8"), keep_listening=True))
                print(rfm69.packet_sent())
                rainbow_cycle(2.0)
            time.sleep(1.0)
        except:
            pass
matteius commented 8 months ago

To clarify too, I mean both radios in the same room where it was working under 5V, so not a signal issue.

jerryneedell commented 8 months ago

Just to check, with this line

 Serial.begin(115200);
  while (!Serial); // Wait for Serial Console (comment out line if no computer)

it won't work at all on battery

jerryneedell commented 8 months ago

I'm sorry but I am unable to reproduce the issue. I set up this test using 38400 and running the arduino side on a LiPo battery The arduino code blinks the LED when it receives the response. It works OK here

CircuitPython code:

# SPDX-License-Identifier: MIT

# Example to send a packet periodically

import time
import board
import busio
import digitalio
import adafruit_rfm69

# set the time interval (seconds) for sending packets
transmit_interval = 10

# Define radio parameters.
RADIO_FREQ_MHZ = 915.0  # Frequency of the radio in Mhz. Must match your
# module! Can be a value like 915.0, 433.0, etc.

# Define pins connected to the chip.
CS = digitalio.DigitalInOut(board.CE1)
RESET = digitalio.DigitalInOut(board.D25)

# Initialize SPI bus.
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)

# Initialze RFM radio
rfm69 = adafruit_rfm69.RFM69(spi, CS, RESET, RADIO_FREQ_MHZ)
# Initialze RFM radio
rfm69.frequency_mhz = 915
#rfm69.bitrate = 57600
#rfm69.preamble_length = 3
#rfm69.frequency_deviation = 120000  # 4.8khz
#rfm69.bitrate = 2400
#rfm69.preamble_length = 3
#rfm69.frequency_deviation = 4800  # 4.8khz
rfm69.bitrate = 38400
rfm69.preamble_length = 3
rfm69.frequency_deviation = 76800
rfm69.tx_power = 17
print(rfm69.bitrate)
print(rfm69.frequency_deviation)
print(rfm69.tx_power)
# Optionally set an encryption key (16 byte AES key). MUST match both
# on the transmitter and receiver (or be set to None to disable/the default).
rfm69.encryption_key = (
    b"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08"
)

# initialize counters
message_counter = 0
response_counter = 0
# send a broadcast mesage
rfm69.send(bytes("message number {}".format(message_counter), "UTF-8"))

# Wait to receive packets.
print("Waiting for packets...")
# initialize timer
time_now = time.monotonic()
while True:
    # Look for a new packet:
    packet = rfm69.receive()
    # If no packet was received during the timeout then None is returned.
    if packet is not None:
        # Received a packet!
        # Print out the raw bytes of the packet:
        print("Received (raw bytes): {0}".format(packet))
        print("RSSI: ", rfm69.last_rssi)
        # send response after any packet received
        response_counter = response_counter + 1
        rfm69.send(bytes("response number {}\0".format(response_counter), "UTF-8"))
    # send periodic message if nothing received
    elif time.monotonic() - time_now > transmit_interval:
        # reset timeer
        time_now = time.monotonic()
        message_counter = message_counter + 1
        rfm69.send(bytes("message number {}\0".format(message_counter), "UTF-8"))```

Arduino code

// rf69_client.pde // -- mode: C++ -- // Example sketch showing how to create a simple messageing client // with the RH_RF69 class. RH_RF69 class does not provide for addressing or // reliability, so you should only use RH_RF69 if you do not need the higher // level messaging abilities. // It is designed to work with the other example rf69_server. // Demonstrates the use of AES encryption, setting the frequency and modem // configuration // Tested on Moteino with RFM69 http://lowpowerlab.com/moteino/ // Tested on miniWireless with RFM69 www.anarduino.com/miniwireless // Tested on Teensy 3.1 with RF69 on PJRC breakout board

include

include

define RFM69_RST 4

define RFM69_CS 8

define RFM69_IRQ 3

define LED 13

// Singleton instance of the radio driver //RH_RF69 rf69; //RH_RF69 rf69(15, 16); // For RF69 on PJRC breakout board with Teensy 3.1 //RH_RF69 rf69(4, 2); // For MoteinoMEGA https://lowpowerlab.com/shop/moteinomega RH_RF69 rf69(RFM69_CS, RFM69_IRQ); // Adafruit Feather M0

void setup() { pinMode(RFM69_RST,OUTPUT); digitalWrite(RFM69_RST,LOW); pinMode(LED,OUTPUT); digitalWrite(LED,LOW); Serial.begin(9600); // while (!Serial) // ; // RESET RFM69
pinMode(RFM69_RST,OUTPUT); digitalWrite(RFM69_RST,HIGH); delay(10);
pinMode(RFM69_RST,OUTPUT); digitalWrite(RFM69_RST,LOW); delay(10); if (!rf69.init()) Serial.println("init failed"); // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module) // No encryption if (!rf69.setFrequency(915.0)) Serial.println("setFrequency failed"); //rf69.setModemConfig(RH_RF69::GFSK_Rb2_4Fd4_8); rf69.setModemConfig(RH_RF69::GFSK_Rb38_4Fd76_8); // If you are using a high power RF69 eg RFM69HW, you must set a Tx power with the // ishighpowermodule flag set like this: rf69.setTxPower(17, true);

// The encryption key has to be the same as the one in the server uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; rf69.setEncryptionKey(key); }

void loop() { Serial.println("Sending to rf69_server"); // Send a message to rf69_server uint8_t data[] = "Hello World!"; rf69.send(data, sizeof(data)); digitalWrite(LED,HIGH); rf69.waitPacketSent(); // Now wait for a reply uint8_t buf[RH_RF69_MAX_MESSAGE_LEN]; uint8_t len = sizeof(buf);

if (rf69.waitAvailableTimeout(500)) { // Should be a reply message for us now
if (rf69.recv(buf, &len)) { Serial.print("got reply: "); Serial.println((char*)buf); digitalWrite(LED,LOW); } else { Serial.println("recv failed"); } } else { Serial.println("No reply, is rf69_server running?"); } delay(2000); }

jerryneedell commented 8 months ago

@matteius Have you resolved this?

matteius commented 8 months ago

@jerryneedell I have been short on time so I haven't resumed yet, but we can close it and I can report back on the thread if I still encounter those issues.