iSkipper
iSkipper copied to clipboard
Unable to capture ACK
So...I was trying to capture some ACKs to verify @ammaraskar's finding. However it can't receive anything from the base after I send answer using iClicker. Here is my sketch, could you please check this problem?
#include "iClickerEmulator.h"
#include <string.h>
#include <RingBufCPP.h>
#include <stdint.h>
/*For Arduino Nano and RFM69HW*/
#define IS_RFM69HW true //make true if using w version
#define IRQ_PIN 3 // Must Be 3 for Nano
#define CSN 10 // NSS pin,10 for Nano
/*End For Arduino Nano and RFM69HW*/
#define MAX_BUFFERED_PACKETS 5
iClickerEmulator clicker(CSN, IRQ_PIN, digitalPinToInterrupt(IRQ_PIN), IS_RFM69HW);
RingBufCPP<iClickerPacket, MAX_BUFFERED_PACKETS> recvBuf;
// the setup function runs once when you press reset or power the board
void setup()
{
Serial.begin(115200);
clicker.begin(iClickerChannels::AA);
clicker.startPromiscuous(CHANNEL_RECV, recvPacketHandler);
}
// the loop function runs over and over again until power down or reset
void loop()
{
iClickerPacket r;
while (recvBuf.pull(&r))
{
uint8_t* ack = r.packet.respPacket.unknown;
for (int i = 0; i < 7; ++i)
{
char temp[5];
snprintf(temp, sizeof(temp), "%02X ", ack[i]);
Serial.print(temp);
}
Serial.println();
}
}
void recvPacketHandler(iClickerPacket *recvd)
{
recvBuf.add(*recvd);
}
Yeah, the promiscuousMode functionality was never quite implemented correctly for capturing the acks. The main reason for this is how these radios work. Basically, there is a concept of a sync address. These are just several bytes that are automatically prepended before the payload. The way these radios receive is they constantly are receiving (garbage when nobody is transmitting) and waiting until they see these sync bytes, when they see these bytes it means it is the start of a real packet. Only now is this packet delivered to the microcontroller via an interrupt.
For answer submission these sync bytes are fixed ({0x85, 0x85, 0x85]). However, the ack sets the sync bytes to be the first two bytes of the encoded_id. This makes promiscuous mode difficult, because every remotes ack has a different sync address.
The reason why your sketch above is not working is due to the fact the sync address is not set properly on the radio before startPromiscuous()
is called. There is a couple potential solutions. The first, is only try to capture for a particular remote. To do this, you need the following thing to happen before you call startPromisuous()
:
// encoded_id is the first two bytes of the remote's encoded ID
_radio.setSyncAddr(encoded_id, 2);
If you are trying to capture all the acks (from all the remotes), there is still a way to accomplish this. The first thing that needs to be done is disable the sync address functionality, you can see how this is done on line 57 of iClickerRadio:
/* 0x2E */ { REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_3 | RF_SYNC_TOL_0 },
Finally, you need to do is increase the dbi threshold on the receiver, so it does not trigger on background noise. If you set this value properly, you should be able to receive all acks with the code you have above.
/* 0x29 */ { REG_RSSITHRESH, 220 }, // must be set to dBm = (-Sensitivity / 2), default is 0xE4 = 228 so -114dBm
There is one more very tricky way that you can capture the acks more robustly, and that is use the sync address to trigger on the preamble (just a bunch of 0x55 before the payload). The preamble is used to train the receiver, but we can use it to also figure out the start of a packet. The difficult part is you have no clue where in the series of 0x55s will the sync address trigger on, so you will need to set the packet size of the radio to be larger, then manually in software throw out the leading 0x55s in the packet.
Thank you for your explanation! I'll first try the simplest way, which is setting the sync address manually. However, we are going to simulate the base one day. I'll try the 0x55 methods if I have chance.
Unfortunately I still can't capture anything useful. I set the threshold to be 70 (-35dbm), and I can't get anything after sending answer , if I set threshold to be 80, then I got a lot of garbage. Here are my codes:
#include "iClickerEmulator.h"
#include <string.h>
#include <RingBufCPP.h>
#include <stdint.h>
/*For Arduino Nano and RFM69HW*/
#define IS_RFM69HW true //make true if using w version
#define IRQ_PIN 3 // Must Be 3 for Nano
#define CSN 10 // NSS pin,10 for Nano
/*End For Arduino Nano and RFM69HW*/
#define MAX_BUFFERED_PACKETS 5
RingBufCPP<iClickerPacket, MAX_BUFFERED_PACKETS> recvBuf;
class ACKCapturingEmulartor : public iClickerEmulator
{
public:
ACKCapturingEmulartor() :iClickerEmulator(CSN, IRQ_PIN, digitalPinToInterrupt(IRQ_PIN), IS_RFM69HW) {}
void setSyncAddr(const uint8_t *addr, uint8_t len)
{
_radio.setSyncAddr(addr, len);
}
}clicker;
uint8_t id[] = { 0x96,0x8C,0x71,0x6B};
// the setup function runs once when you press reset or power the board
void setup()
{
Serial.begin(115200);
clicker.begin(iClickerChannels::AA);
uint8_t encodedID[4];
iClickerEmulator::encodeId(id, encodedID);
clicker.setSyncAddr(id, 2);
clicker.startPromiscuous(CHANNEL_RECV, recvPacketHandler);
}
// the loop function runs over and over again until power down or reset
void loop()
{
iClickerPacket r;
while (recvBuf.pull(&r))
{
uint8_t* ack = r.packet.respPacket.unknown;
for (int i = 0; i < 7; ++i)
{
char temp[10];
snprintf(temp, sizeof(temp), "%02X ", ack[i]);
Serial.print(temp);
}
Serial.println();
}
}
void recvPacketHandler(iClickerPacket *recvd)
{
recvBuf.add(*recvd);
}
By the way, I saw you mentioned SDR in your paper. Do you have any GNU SDR script for this project? I actually have a LimeSDR. Maybe it would be more easy to capture ACKs, if you have script about it.
So I set the sync address to {0x55,0x55,0x55, encodedID[0],encodedID[1] }, and finally I got something. I'll post my finding on #11.
Would you be interested in getting promiscuousMode working for all acks? I would like to get this functionality working and merged in.
Yes, I'll implement this and open a PR