Commit a2954f8f authored by TMRh20's avatar TMRh20

Merge pull request #35 from mz-fuzzy/master

Python wrapper for RPi added

This wrapper and the pingpair_dyn example seems to have brought up a bit of a timing issue that should be fixed in the latest commit https://github.com/TMRh20/RF24/commit/d41d47ab20cb794b8250560154076b1b2b06feae  
Also, (minor issue) it seems to be missing the define for ```BCM2835_SPI_CS0``` and ```BCM2835_SPI_CS1``` 
That can be fixed, and it seems to work nicely otherwise, so merging.
parents deef592b 567ca692
#include <RF24/RF24.h>
#include <boost/python.hpp>
namespace bp = boost::python;
// ******************** explicit wrappers **************************
// for methods which need it - mostly for buffer operations
//
std::string read_wrap(RF24& ref, int maxlen)
{
char *buf = new char[maxlen+1];
ref.read(buf, maxlen);
std::string str(buf, maxlen<ref.getPayloadSize()?maxlen:ref.getPayloadSize());
delete[] buf;
return str;
}
bool write_wrap1(RF24& ref, std::string buf)
{
return ref.write(buf.c_str(), buf.length());
}
bool write_wrap2(RF24& ref, std::string buf, const bool multicast)
{
return ref.write(buf.c_str(), buf.length(), multicast);
}
void writeAckPayload_wrap(RF24& ref, uint8_t pipe, std::string buf)
{
ref.writeAckPayload(pipe, buf.c_str(), buf.length());
}
bool writeFast_wrap1(RF24& ref, std::string buf)
{
return ref.writeFast(buf.c_str(), buf.length());
}
bool writeFast_wrap2(RF24& ref, std::string buf, const bool multicast)
{
return ref.writeFast(buf.c_str(), buf.length(), multicast);
}
bool writeBlocking_wrap(RF24& ref, std::string buf, uint32_t timeout)
{
return ref.writeBlocking(buf.c_str(), buf.length(), timeout);
}
void startFastWrite_wrap(RF24& ref, std::string buf, const bool multicast)
{
ref.startFastWrite(buf.c_str(), buf.length(), multicast);
}
void startWrite_wrap(RF24& ref, std::string buf, const bool multicast)
{
ref.startWrite(buf.c_str(), buf.length(), multicast);
}
void openWritingPipe_wrap(RF24& ref, const std::string address)
{
ref.openWritingPipe((const uint8_t *)(address.c_str()));
}
void openReadingPipe_wrap(RF24& ref, uint8_t number, const std::string address)
{
ref.openReadingPipe(number, (const uint8_t *)(address.c_str()));
}
bp::tuple whatHappened_wrap(RF24& ref)
{
bool tx_ok;
bool tx_fail;
bool tx_ready;
ref.whatHappened(tx_ok, tx_fail, tx_ready);
return bp::make_tuple(tx_ok, tx_fail, tx_ready);
}
bp::tuple available_wrap(RF24& ref)
{
bool result;
uint8_t pipe;
result = ref.available(&pipe);
return bp::make_tuple(result, pipe);
}
// ******************** enums **************************
// from both RF24 and bcm2835
//
BOOST_PYTHON_MODULE(RF24){
bp::enum_< RPiGPIOPin>("RPiGPIOPin")
.value("RPI_GPIO_P1_03", RPI_GPIO_P1_03)
.value("RPI_GPIO_P1_05", RPI_GPIO_P1_05)
.value("RPI_GPIO_P1_07", RPI_GPIO_P1_07)
.value("RPI_GPIO_P1_08", RPI_GPIO_P1_08)
.value("RPI_GPIO_P1_10", RPI_GPIO_P1_10)
.value("RPI_GPIO_P1_11", RPI_GPIO_P1_11)
.value("RPI_GPIO_P1_12", RPI_GPIO_P1_12)
.value("RPI_GPIO_P1_13", RPI_GPIO_P1_13)
.value("RPI_GPIO_P1_15", RPI_GPIO_P1_15)
.value("RPI_GPIO_P1_16", RPI_GPIO_P1_16)
.value("RPI_GPIO_P1_18", RPI_GPIO_P1_18)
.value("RPI_GPIO_P1_19", RPI_GPIO_P1_19)
.value("RPI_GPIO_P1_21", RPI_GPIO_P1_21)
.value("RPI_GPIO_P1_22", RPI_GPIO_P1_22)
.value("RPI_GPIO_P1_23", RPI_GPIO_P1_23)
.value("RPI_GPIO_P1_24", RPI_GPIO_P1_24)
.value("RPI_GPIO_P1_26", RPI_GPIO_P1_26)
.value("RPI_V2_GPIO_P1_03", RPI_V2_GPIO_P1_03)
.value("RPI_V2_GPIO_P1_05", RPI_V2_GPIO_P1_05)
.value("RPI_V2_GPIO_P1_07", RPI_V2_GPIO_P1_07)
.value("RPI_V2_GPIO_P1_08", RPI_V2_GPIO_P1_08)
.value("RPI_V2_GPIO_P1_10", RPI_V2_GPIO_P1_10)
.value("RPI_V2_GPIO_P1_11", RPI_V2_GPIO_P1_11)
.value("RPI_V2_GPIO_P1_12", RPI_V2_GPIO_P1_12)
.value("RPI_V2_GPIO_P1_13", RPI_V2_GPIO_P1_13)
.value("RPI_V2_GPIO_P1_15", RPI_V2_GPIO_P1_15)
.value("RPI_V2_GPIO_P1_16", RPI_V2_GPIO_P1_16)
.value("RPI_V2_GPIO_P1_18", RPI_V2_GPIO_P1_18)
.value("RPI_V2_GPIO_P1_19", RPI_V2_GPIO_P1_19)
.value("RPI_V2_GPIO_P1_21", RPI_V2_GPIO_P1_21)
.value("RPI_V2_GPIO_P1_22", RPI_V2_GPIO_P1_22)
.value("RPI_V2_GPIO_P1_23", RPI_V2_GPIO_P1_23)
.value("RPI_V2_GPIO_P1_24", RPI_V2_GPIO_P1_24)
.value("RPI_V2_GPIO_P1_26", RPI_V2_GPIO_P1_26)
.value("RPI_V2_GPIO_P5_03", RPI_V2_GPIO_P5_03)
.value("RPI_V2_GPIO_P5_04", RPI_V2_GPIO_P5_04)
.value("RPI_V2_GPIO_P5_05", RPI_V2_GPIO_P5_05)
.value("RPI_V2_GPIO_P5_06", RPI_V2_GPIO_P5_06)
.value("RPI_BPLUS_GPIO_J8_03", RPI_BPLUS_GPIO_J8_03)
.value("RPI_BPLUS_GPIO_J8_05", RPI_BPLUS_GPIO_J8_05)
.value("RPI_BPLUS_GPIO_J8_07", RPI_BPLUS_GPIO_J8_07)
.value("RPI_BPLUS_GPIO_J8_08", RPI_BPLUS_GPIO_J8_08)
.value("RPI_BPLUS_GPIO_J8_10", RPI_BPLUS_GPIO_J8_10)
.value("RPI_BPLUS_GPIO_J8_11", RPI_BPLUS_GPIO_J8_11)
.value("RPI_BPLUS_GPIO_J8_12", RPI_BPLUS_GPIO_J8_12)
.value("RPI_BPLUS_GPIO_J8_13", RPI_BPLUS_GPIO_J8_13)
.value("RPI_BPLUS_GPIO_J8_15", RPI_BPLUS_GPIO_J8_15)
.value("RPI_BPLUS_GPIO_J8_16", RPI_BPLUS_GPIO_J8_16)
.value("RPI_BPLUS_GPIO_J8_18", RPI_BPLUS_GPIO_J8_18)
.value("RPI_BPLUS_GPIO_J8_19", RPI_BPLUS_GPIO_J8_19)
.value("RPI_BPLUS_GPIO_J8_21", RPI_BPLUS_GPIO_J8_21)
.value("RPI_BPLUS_GPIO_J8_22", RPI_BPLUS_GPIO_J8_22)
.value("RPI_BPLUS_GPIO_J8_23", RPI_BPLUS_GPIO_J8_23)
.value("RPI_BPLUS_GPIO_J8_24", RPI_BPLUS_GPIO_J8_24)
.value("RPI_BPLUS_GPIO_J8_26", RPI_BPLUS_GPIO_J8_26)
.value("RPI_BPLUS_GPIO_J8_29", RPI_BPLUS_GPIO_J8_29)
.value("RPI_BPLUS_GPIO_J8_31", RPI_BPLUS_GPIO_J8_31)
.value("RPI_BPLUS_GPIO_J8_32", RPI_BPLUS_GPIO_J8_32)
.value("RPI_BPLUS_GPIO_J8_33", RPI_BPLUS_GPIO_J8_33)
.value("RPI_BPLUS_GPIO_J8_35", RPI_BPLUS_GPIO_J8_35)
.value("RPI_BPLUS_GPIO_J8_36", RPI_BPLUS_GPIO_J8_36)
.value("RPI_BPLUS_GPIO_J8_37", RPI_BPLUS_GPIO_J8_37)
.value("RPI_BPLUS_GPIO_J8_38", RPI_BPLUS_GPIO_J8_38)
.value("RPI_BPLUS_GPIO_J8_40", RPI_BPLUS_GPIO_J8_40)
.export_values()
;
bp::enum_< bcm2835SPIClockDivider>("bcm2835SPIClockDivider")
.value("BCM2835_SPI_CLOCK_DIVIDER_65536", BCM2835_SPI_CLOCK_DIVIDER_65536)
.value("BCM2835_SPI_CLOCK_DIVIDER_32768", BCM2835_SPI_CLOCK_DIVIDER_32768)
.value("BCM2835_SPI_CLOCK_DIVIDER_16384", BCM2835_SPI_CLOCK_DIVIDER_16384)
.value("BCM2835_SPI_CLOCK_DIVIDER_8192", BCM2835_SPI_CLOCK_DIVIDER_8192)
.value("BCM2835_SPI_CLOCK_DIVIDER_4096", BCM2835_SPI_CLOCK_DIVIDER_4096)
.value("BCM2835_SPI_CLOCK_DIVIDER_2048", BCM2835_SPI_CLOCK_DIVIDER_2048)
.value("BCM2835_SPI_CLOCK_DIVIDER_1024", BCM2835_SPI_CLOCK_DIVIDER_1024)
.value("BCM2835_SPI_CLOCK_DIVIDER_512", BCM2835_SPI_CLOCK_DIVIDER_512)
.value("BCM2835_SPI_CLOCK_DIVIDER_256", BCM2835_SPI_CLOCK_DIVIDER_256)
.value("BCM2835_SPI_CLOCK_DIVIDER_128", BCM2835_SPI_CLOCK_DIVIDER_128)
.value("BCM2835_SPI_CLOCK_DIVIDER_64", BCM2835_SPI_CLOCK_DIVIDER_64)
.value("BCM2835_SPI_CLOCK_DIVIDER_32", BCM2835_SPI_CLOCK_DIVIDER_32)
.value("BCM2835_SPI_CLOCK_DIVIDER_16", BCM2835_SPI_CLOCK_DIVIDER_16)
.value("BCM2835_SPI_CLOCK_DIVIDER_8", BCM2835_SPI_CLOCK_DIVIDER_8)
.value("BCM2835_SPI_CLOCK_DIVIDER_4", BCM2835_SPI_CLOCK_DIVIDER_4)
.value("BCM2835_SPI_CLOCK_DIVIDER_2", BCM2835_SPI_CLOCK_DIVIDER_2)
.value("BCM2835_SPI_CLOCK_DIVIDER_1", BCM2835_SPI_CLOCK_DIVIDER_1)
.export_values();
// exposing '#define's for SPI speed as this is needed for RF24 constructor
bp::scope().attr("BCM2835_SPI_SPEED_64MHZ") = BCM2835_SPI_SPEED_64MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_32MHZ") = BCM2835_SPI_SPEED_32MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_16MHZ") = BCM2835_SPI_SPEED_16MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_8MHZ") = BCM2835_SPI_SPEED_8MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_4MHZ") = BCM2835_SPI_SPEED_4MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_2MHZ") = BCM2835_SPI_SPEED_2MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_1MHZ") = BCM2835_SPI_SPEED_1MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_512KHZ") = BCM2835_SPI_SPEED_512KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_256KHZ") = BCM2835_SPI_SPEED_256KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_128KHZ") = BCM2835_SPI_SPEED_128KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_64KHZ") = BCM2835_SPI_SPEED_64KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_32KHZ") = BCM2835_SPI_SPEED_32KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_16KHZ") = BCM2835_SPI_SPEED_16KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_8KHZ") = BCM2835_SPI_SPEED_8KHZ;
bp::enum_< rf24_crclength_e>("rf24_crclength_e")
.value("RF24_CRC_DISABLED", RF24_CRC_DISABLED)
.value("RF24_CRC_8", RF24_CRC_8)
.value("RF24_CRC_16", RF24_CRC_16)
.export_values()
;
bp::enum_< rf24_datarate_e>("rf24_datarate_e")
.value("RF24_1MBPS", RF24_1MBPS)
.value("RF24_2MBPS", RF24_2MBPS)
.value("RF24_250KBPS", RF24_250KBPS)
.export_values()
;
bp::enum_< rf24_pa_dbm_e>("rf24_pa_dbm_e")
.value("RF24_PA_MIN", RF24_PA_MIN)
.value("RF24_PA_LOW", RF24_PA_LOW)
.value("RF24_PA_HIGH", RF24_PA_HIGH)
.value("RF24_PA_MAX", RF24_PA_MAX)
.value("RF24_PA_ERROR", RF24_PA_ERROR)
.export_values()
;
// ******************** RF24 class **************************
//
bp::class_< RF24 >( "RF24", bp::init< uint8_t, uint8_t >(( bp::arg("_cepin"), bp::arg("_cspin") )) )
.def( bp::init< uint8_t, uint8_t, uint32_t >(( bp::arg("_cepin"), bp::arg("_cspin"), bp::arg("spispeed") )) )
.def("available", (bool ( ::RF24::* )( ) )( &::RF24::available ) )
.def("available_pipe", &available_wrap ) // needed to rename this method as python does not allow such overloading
.def("begin", &RF24::begin)
.def("closeReadingPipe", &RF24::closeReadingPipe)
.def("disableCRC", &RF24::disableCRC)
.def("enableAckPayload", &RF24::enableAckPayload)
.def("enableDynamicAck", &RF24::enableDynamicAck)
.def("enableDynamicPayloads", &RF24::enableDynamicPayloads)
.def("flush_tx", &RF24::flush_tx)
.def("getCRCLength", &RF24::getCRCLength)
.def("getDataRate", &RF24::getDataRate)
.def("getDynamicPayloadSize", &RF24::getDynamicPayloadSize)
.def("getPALevel", &RF24::getPALevel)
.def("isAckPayloadAvailable", &RF24::isAckPayloadAvailable)
.def("isPVariant", &RF24::isPVariant)
.def("isValid", &RF24::isValid)
.def("maskIRQ", &RF24::maskIRQ, ( bp::arg("tx_ok"), bp::arg("tx_fail"), bp::arg("rx_ready")))
.def("openReadingPipe", &openReadingPipe_wrap, (bp::arg("number"), bp::arg("address")))
.def("openReadingPipe", (void ( ::RF24::* )( ::uint8_t,::uint64_t ) )( &::RF24::openReadingPipe), (bp::arg("number"), bp::arg("address")))
.def("openWritingPipe", &openWritingPipe_wrap, (bp::arg("address")))
.def("openWritingPipe", (void ( ::RF24::* )( ::uint64_t ) )( &::RF24::openWritingPipe), ( bp::arg("address") ) )
.def("powerDown", &RF24::powerDown)
.def("powerUp", &RF24::powerUp)
.def("printDetails", &RF24::printDetails)
.def("reUseTX", &RF24::reUseTX)
.def("read", &read_wrap, (bp::arg("maxlen")))
.def("rxFifoFull", &RF24::rxFifoFull)
.def("setAddressWidth", &RF24::setAddressWidth)
.def("setAutoAck", (void ( ::RF24::* )( bool ) )( &::RF24::setAutoAck ), ( bp::arg("enable") ) )
.def("setAutoAck", (void ( ::RF24::* )( ::uint8_t,bool ) )( &::RF24::setAutoAck ), ( bp::arg("pipe"), bp::arg("enable") ) )
.def("setCRCLength", &RF24::setCRCLength, ( bp::arg("length") ) )
.def("setChannel", &RF24::setChannel, ( bp::arg("channel") ) )
.def("setDataRate", &RF24::setDataRate, ( bp::arg("speed") ) )
.def("setPALevel", &RF24::setPALevel, ( bp::arg("level") ) )
.def("setRetries", &RF24::setRetries , (bp::arg("delay"), bp::arg("count")))
.def("startFastWrite", &startFastWrite_wrap, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast") ) )
.def("startListening", &RF24::startListening)
.def("startWrite", &startWrite_wrap, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast") ) )
.def("stopListening", &RF24::stopListening)
.def("testCarrier", &RF24::testCarrier)
.def("testRPD", &RF24::testRPD)
.def("txStandBy", (bool ( ::RF24::* )( ) ) (&RF24::txStandBy) )
.def("txStandBy", (bool ( ::RF24::* )( ::uint32_t ) )( &RF24::txStandBy ), ( bp::arg("timeout") ) )
.def("whatHappened", &whatHappened_wrap)
.def("write", &write_wrap1, ( bp::arg("buf") ) )
.def("write", &write_wrap2, ( bp::arg("buf"), bp::arg("multicast") ) )
.def("writeAckPayload", writeAckPayload_wrap, ( bp::arg("pipe"), bp::arg("buf") ) )
.def("writeBlocking", &writeBlocking_wrap, ( bp::arg("buf"), bp::arg("timeout") ) )
.def("writeFast", &writeFast_wrap1, ( bp::arg("buf") ) )
.def("writeFast", &writeFast_wrap2, ( bp::arg("buf"), bp::arg("multicast") ) )
.add_property("payloadSize", &RF24::getPayloadSize, &RF24::setPayloadSize)
.def_readwrite( "failureDetected", &RF24::failureDetected );
}
#!/usr/bin/env python
from distutils.core import setup, Extension
module_RF24 = Extension('RF24',
libraries = ['rf24-bcm', 'boost_python'],
sources = ['pyRF24.cpp'])
setup(name='RF24',
version='1.0',
ext_modules=[module_RF24]
)
#!/usr/bin/env python
#
# Example using Dynamic Payloads
#
# This is an example of how to use payloads of a varying (dynamic) size.
#
import time
from RF24 import *
# CE Pin, CSN Pin, SPI Speed
# Setup for GPIO 22 CE and GPIO 25 CSN with SPI Speed @ 1Mhz
#radio = radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_18, BCM2835_SPI_SPEED_1MHZ)
# Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
#radio = RF24(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ)
# Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 8Mhz
#radio = RF24(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ)
# Setup for GPIO 22 CE and CE0 CSN for RPi B+ with SPI Speed @ 8Mhz
radio = RF24(RPI_BPLUS_GPIO_J8_22, RPI_BPLUS_GPIO_J8_24, BCM2835_SPI_SPEED_8MHZ)
pipes = [0xF0F0F0F0E1, 0xF0F0F0F0D2]
min_payload_size = 4
max_payload_size = 32
payload_size_increments_by = 1
next_payload_size = min_payload_size
inp_role = 'none'
send_payload = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ789012'
millis = lambda: int(round(time.time() * 1000))
print 'pyRF24/examples/pingpair_dyn/'
radio.begin()
radio.enableDynamicPayloads()
radio.setRetries(5,15)
radio.printDetails()
print ' ************ Role Setup *********** '
while (inp_role !='0') and (inp_role !='1'):
inp_role = raw_input('Choose a role: Enter 0 for receiver, 1 for transmitter (CTRL+C to exit) ')
if inp_role == '0':
print 'Role: Pong Back, awaiting transmission'
radio.openWritingPipe(pipes[1])
radio.openReadingPipe(1,pipes[0])
radio.startListening()
else:
print 'Role: Ping Out, starting transmission'
radio.openWritingPipe(pipes[0])
radio.openReadingPipe(1,pipes[1])
# forever loop
while 1:
if inp_role == '1': # ping out
# The payload will always be the same, what will change is how much of it we send.
# First, stop listening so we can talk.
radio.stopListening()
# Take the time, and send it. This will block until complete
print 'Now sending length ', next_payload_size, ' ... ',
radio.write(send_payload[:next_payload_size])
# Now, continue listening
radio.startListening()
# Wait here until we get a response, or timeout
started_waiting_at = millis()
timeout = False
while (not radio.available()) and (not timeout):
if (millis() - started_waiting_at) > 500:
timeout = True
# Describe the results
if timeout:
print 'failed, response timed out.'
else:
# Grab the response, compare, and send to debugging spew
len = radio.getDynamicPayloadSize()
receive_payload = radio.read(len)
# Spew it
print 'got response size=', len, ' value="', receive_payload, '"'
# Update size for next time.
next_payload_size += payload_size_increments_by
if next_payload_size > max_payload_size:
next_payload_size = min_payload_size
time.sleep(0.1)
else:
# Pong back role. Receive each packet, dump it out, and send it back
# if there is data ready
if radio.available():
while radio.available():
# Fetch the payload, and see if this was the last one.
len = radio.getDynamicPayloadSize()
receive_payload = radio.read(len)
# Spew it
print 'Got payload size=', len, ' value="', receive_payload, '"'
# First, stop listening so we can talk
radio.stopListening()
# Send the final one back.
radio.write(receive_payload)
print 'Sent response.'
# Now, resume listening so we catch the next packets.
radio.startListening()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment