Browse Source

switched to dynamic payload mode, added a pretender

pull/2/head
Martin Grill 3 years ago
parent
commit
122e4567b1
  1. 4
      tools/rpi/discover/CMakeLists.txt
  2. 45
      tools/rpi/discover/common.cpp
  3. 18
      tools/rpi/discover/common.hpp
  4. 21
      tools/rpi/discover/discover.cpp
  5. 90
      tools/rpi/discover/pretender.cpp

4
tools/rpi/discover/CMakeLists.txt

@ -8,3 +8,7 @@ message(STATUS "using RF24 library: ${RF24}")
add_executable(discover discover.cpp)
target_link_libraries(discover PUBLIC ${RF24} pthread)
add_executable(pretender pretender.cpp common.cpp)
target_link_libraries(pretender PUBLIC ${RF24} pthread)

45
tools/rpi/discover/common.cpp

@ -0,0 +1,45 @@
#include "common.hpp"
#include <sstream>
#include <iostream>
#include <iomanip>
using namespace std;
/** Convert given 5-byte address to human readable hex string */
string prettyPrintAddr(string &a)
{
ostringstream o;
o << hex << setw(2)
<< setfill('0') << setw(2) << int(a[0])
<< ":" << setw(2) << int(a[1])
<< ":" << setw(2) << int(a[2])
<< ":" << setw(2) << int(a[3])
<< ":" << setw(2) << int(a[4]) << dec;
return o.str();
}
/** Convert a Hoymiles inverter/DTU serial number into its
* corresponding NRF24 address byte sequence (5 bytes).
*
* The inverters use a BCD representation of the last 8
* digits of their serial number, in reverse byte order,
* followed by \x01.
*/
string serno2shockburstaddrbytes(uint64_t n)
{
char b[5];
b[3] = (((n/10)%10) << 4) | ((n/1)%10);
b[2] = (((n/1000)%10) << 4) | ((n/100)%10);
b[1] = (((n/100000)%10) << 4) | ((n/10000)%10);
b[0] = (((n/10000000)%10) << 4) | ((n/1000000)%10);
b[4] = 0x01;
string s = string(b, sizeof(b));
cout << dec << "ser# " << n << " --> addr "
<< prettyPrintAddr(s) << endl;
return s;
}

18
tools/rpi/discover/common.hpp

@ -0,0 +1,18 @@
#include <string>
#include <stdint.h>
using namespace std;
/** Convert given 5-byte address to human readable hex string */
string prettyPrintAddr(string &a);
/** Convert a Hoymiles inverter/DTU serial number into its
* corresponding NRF24 address byte sequence (5 bytes).
*
* The inverters use a BCD representation of the last 8
* digits of their serial number, in reverse byte order,
* followed by \x01.
*/
string serno2shockburstaddrbytes(uint64_t n);

21
tools/rpi/discover/discover.cpp

@ -22,10 +22,7 @@ using namespace std;
// Generic:
RF24 radio(22, 0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.github.io/RF24/pages.html for more information on usage
// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// For this example, we'll be using a payload containing
// a single float number that will be incremented
@ -58,12 +55,12 @@ string prettyPrintAddr(string &a)
}
/** Convert a hoymiles inverter/DTU serial number into its
/** Convert a Hoymiles inverter/DTU serial number into its
* corresponding NRF24 address byte sequence (5 bytes).
*
* The inverters use a BCD representation of the last 8
* digits of the serial number, in reverse byte order,
* followed by a \x01.
* digits of their serial number, in reverse byte order,
* followed by \x01.
*/
string serno2shockburstaddrbytes(uint64_t n)
{
@ -88,7 +85,8 @@ string serno2shockburstaddrbytes(uint64_t n)
bool doPing(int ch, string src, string dst)
{
// radio.setPayloadSize(sizeof(payload)); // float datatype occupies 4 bytes
radio.setPayloadSize(4); // float datatype occupies 4 bytes
// radio.setPayloadSize(4); // float datatype occupies 4 bytes
radio.enableDynamicPayloads();
radio.setChannel(ch);
radio.setPALevel(RF24_PA_MIN); // RF24_PA_MAX is default.
@ -99,12 +97,13 @@ bool doPing(int ch, string src, string dst)
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, (const uint8_t *)src.c_str());
// ...not that this matters for simple ping/ack
radio.stopListening(); // put radio in TX mode
clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer
// bool report = radio.write(&payload, sizeof(float)); // transmit & save the report
bool report = radio.write(&payload, 4); // transmit & save the report
bool report = radio.write("P", 1); // transmit & save the report
uint32_t timerEllapsed = getMicros(); // end the timer
if (report) {
@ -148,7 +147,9 @@ int main(int argc, char** argv)
// well-known valid DTU serial number
// just in case the inverter only responds to addresses
// that fulfil certain requirements.
string masteraddr = serno2shockburstaddrbytes(99912345678);
//string masteraddr = serno2shockburstaddrbytes(99912345678);
string masteraddr = serno2shockburstaddrbytes(999970535453);
// serial numbers of all inverters that we are trying to find
vector<string> dstaddrs;
@ -158,7 +159,7 @@ int main(int argc, char** argv)
dstaddrs.push_back(serno2shockburstaddrbytes(114174608177));
// channels that we will scan
vector<int> channels{1, 3, 6, 9, 11, 23, 40, 61, 75, 76, 99};
vector<int> channels{1, 3, 6, 9, 11, 23, 40, 41, 61, 75, 76, 99};
for(auto & ch : channels)
{

90
tools/rpi/discover/pretender.cpp

@ -0,0 +1,90 @@
/* based on "gettingstarted.cpp" by 2bdy5 */
/**
* Behave like we expect a Hoymiles microinverter to behave.
*/
#include <ctime> // time()
#include <iostream> // cin, cout, endl
#include <iomanip>
#include <string> // string, getline()
#include <vector>
#include <sstream>
#include <time.h> // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
#include <RF24/RF24.h> // RF24, RF24_PA_LOW, delay()
using namespace std;
#include "common.hpp"
// Generic:
RF24 radio(22, 0);
// See http://nRF24.github.io/RF24/pages.html for more information on usage
/** Receive forever
*/
void receiveForever(int ch, string myaddr)
{
uint8_t buf[30];
radio.enableDynamicPayloads();
radio.setChannel(ch);
radio.setPALevel(RF24_PA_MIN); // RF24_PA_MAX is default.
radio.setDataRate(RF24_250KBPS);
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, (const uint8_t *)myaddr.c_str());
while (true)
{
uint8_t pipe;
if (radio.available(&pipe))
{
uint8_t bytes = radio.getPayloadSize(); // get the size of the payload
cout << "I was notified of having received " << (unsigned int)bytes;
cout << " bytes on pipe " << (unsigned int)pipe << flush;
radio.read(buf, bytes); // fetch payload from FIFO
//cout << ": " << payload; // print the payload's value
//cout << " hex: " << hex << (unsigned int)b[0] << " " << (unsigned int)b[1] << " "
// << (unsigned int)b[2] << " " << (unsigned int)b[3] << " " <<endl;
}
}
}
int main(int argc, char** argv)
{
if (!radio.begin()) {
cout << "radio hardware is not responding!!" << endl;
return 0; // quit now
}
if(!radio.isPVariant())
{
printf("not nRF24L01+\n");
return 0;
}
if(!radio.isChipConnected())
{
printf("not connected\n");
return 0;
}
// TODO
// we probably want
// - 8-bit crc
// - dynamic payloads (check in rf logs)
// - what's the "primary mode"?
// - do we need/want "custom ack payloads"?
// - use isAckPayloadAvailable() once we've actually contacted an inverter successfully!
radio.printPrettyDetails();
string addr = serno2shockburstaddrbytes(114174608177);
receiveForever(41, addr);
return 0;
}
Loading…
Cancel
Save