diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 990fb11c..7b9be084 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -83,6 +83,7 @@ add_executable (rpr220-intr-example rpr220-intr.cxx) add_executable (mma7660-example mma7660.cxx) add_executable (cjq4435-example cjq4435.cxx) add_executable (adxl335-example adxl335.cxx) +add_executable (hmtrp-example hmtrp.cxx) include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l) include_directories (${PROJECT_SOURCE_DIR}/src/grove) @@ -151,6 +152,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/rpr220) include_directories (${PROJECT_SOURCE_DIR}/src/mma7660) include_directories (${PROJECT_SOURCE_DIR}/src/cjq4435) include_directories (${PROJECT_SOURCE_DIR}/src/adxl335) +include_directories (${PROJECT_SOURCE_DIR}/src/hmtrp) target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT}) @@ -237,3 +239,4 @@ target_link_libraries (rpr220-intr-example rpr220 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (mma7660-example mma7660 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (cjq4435-example cjq4435 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (adxl335-example adxl335 ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (hmtrp-example hmtrp ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/hmtrp.cxx b/examples/hmtrp.cxx new file mode 100644 index 00000000..84f7995b --- /dev/null +++ b/examples/hmtrp.cxx @@ -0,0 +1,164 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "hmtrp.h" + +using namespace std; + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +void printUsage() +{ + cout << "Usage:" << endl; + cout << "Pass a commandline argument (any argument) to this program" + << endl; + cout << "to query the radio configuration and output it. NOTE: the" + << endl; + cout << "radio must be in CONFIG mode for this to work." + << endl; + cout << endl; + cout << "Running this program without arguments will simply transmit" + << endl; + cout << "'Hello World!' every second, and output any data received from" + << endl; + cout << "another radio." + << endl; + cout << endl; +} + +const size_t bufferLength = 256; + +int main (int argc, char **argv) +{ + signal(SIGINT, sig_handler); + +//! [Interesting] + // Instantiate a HMTRP radio device on uart 0 + + upm::HMTRP* radio = new upm::HMTRP(0); + + // make sure port is initialized properly. 9600 baud is the default. + if (!radio->setupTty(B9600)) + { + cerr << "Failed to setup tty port parameters" << endl; + return 1; + } + + printUsage(); + + // By default, this radio simply transmits data sent via writeData() + // and reads any available data via readData(). + + // It can be placed into a configuration mode by grounding the + // CONFIG pin on the module. When this is done, the various + // configuration query and config methods can be used. In this + // example, by default, we just read any data available fom the + // device, and periodically transmit "Hello World". + + // If any argument was specified on the command line, do a simple + // configuration query and output the results. The radio must be in + // CONFIG mode for this to work. + + if (argc > 1) + { + // config mode + uint32_t freq; + uint32_t dataRate; + uint16_t rxBandwidth; + uint8_t modulation; + uint8_t txPower; + uint32_t uartBaud; + + if (radio->getConfig(&freq, &dataRate, &rxBandwidth, &modulation, + &txPower, &uartBaud)) + { + cout << "Radio configuration:" << endl; + cout << "freq: " << freq << " dataRate: " << dataRate + << " rxBandwidth: " << rxBandwidth << "Khz" << endl; + + cout << "modulation: " << int(modulation) << "Khz txPower: " + << int(txPower) << " uartBaud: " << uartBaud << endl; + } + else + { + cerr << "getConfig() failed. Make sure the radio is in " + << "CONFIG mode." << endl; + } + } + else + { + // normal read/write mode + char radioBuffer[bufferLength]; + int counter = 0; + cout << "Running in normal read/write mode." << endl; + + while (shouldRun) + { + // we don't want the read to block in this example, so always + // check to see if data is available first. + if (radio->dataAvailable()) + { + int rv = radio->readData(radioBuffer, bufferLength); + + if (rv > 0) + cout << "Received: " << radioBuffer << endl; + + if (rv < 0) // some sort of read error occured + { + cerr << "Port read error." << endl; + break; + } + + continue; + } + + usleep(100000); // 100ms + counter++; + // every second, transmit "Hello World" + if (counter > 10) + { + static const char *hello = "Hello World!"; + cout << "Transmitting hello world..." << endl; + radio->writeData((char *)hello, strlen(hello) + 1); + counter = 0; + } + } + } + +//! [Interesting] + + cout << "Exiting..." << endl; + + delete radio; + return 0; +} diff --git a/examples/javascript/hmtrp.js b/examples/javascript/hmtrp.js new file mode 100644 index 00000000..3bdd0f20 --- /dev/null +++ b/examples/javascript/hmtrp.js @@ -0,0 +1,161 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ + +/* +* Author: Zion Orent +* Copyright (c) 2015 Intel Corporation. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +function printUsage() +{ + var outputStr = "Usage:\n" + + "Pass a commandline argument (any argument) to this program\n" + + "to query the radio configuration and output it. NOTE: the\n" + + "radio must be in CONFIG mode for this to work.\n\n" + + "Running this program without arguments will simply transmit\n" + + "'Hello World!' every second, and output any data received from\n" + + "another radio.\n\n"; + console.log(outputStr); +} + +var HMTRP_Radio = require('jsupm_hmtrp'); + +// Instantiate a HMTRP radio device on uart 0 +var my_HMTRP_Radio = new HMTRP_Radio.HMTRP(0); + +var g_myInterval; +var g_counter = 0; + +// normal read/write mode +var bufferLength = 256; +var radioBuffer = new HMTRP_Radio.charArray(bufferLength); + +// make sure port is initialized properly. 9600 baud is the default. +if (!my_HMTRP_Radio.setupTty(HMTRP_Radio.int_B9600)) +{ + console.log("Failed to setup tty port parameters"); + process.exit(0); +} + +printUsage(); + +// By default, this radio simply transmits data sent via writeData() +// and reads any available data via readData(). + +// It can be placed into a configuration mode by grounding the +// CONFIG pin on the module. When this is done, the various +// configuration query and config methods can be used. In this +// example, by default, we just read any data available fom the +// device, and periodically transmit "Hello World". + +// If any argument was specified on the command line, do a simple +// configuration query and output the results. The radio must be in +// CONFIG mode for this to work. + + +// Note that the first command-line argument +// should be "node" and the second is "hmtrp.js". +// The data we want would be the third... if it exists +if (process.argv.length > 2) +{ + // config mode + var freq = new HMTRP_Radio.uint32Array(0); + var dataRate = new HMTRP_Radio.uint32Array(0); + var rxBandwidth = new HMTRP_Radio.uint16Array(0); + var modulation = new HMTRP_Radio.uint8Array(0); + var txPower = new HMTRP_Radio.uint8Array(0); + var uartBaud = new HMTRP_Radio.uint32Array(0); + + if (my_HMTRP_Radio.getConfig( + freq, dataRate, rxBandwidth, modulation, txPower, uartBaud)) + { + console.log("Radio configuration:"); + var outputStr = "freq: " + freq.getitem(0) + + " dataRate: " + dataRate.getitem(0) + + " rxBandwidth: " + rxBandwidth.getitem(0) + "Khz"; + console.log(outputStr); + + outputStr = "modulation: " + parseInt(modulation.getitem(0)); + outputStr += " Khz txPower: " + parseInt(txPower.getitem(0)); + outputStr += " uartBaud: " + uartBaud.getitem(0); + console.log(outputStr); + } + else + { + var errString = "getConfig() failed. Make sure the radio " + + "is in CONFIG mode."; + console.log(errString); + } +} +else +{ + console.log("Running in normal read/write mode."); + g_myInterval = setInterval(runRadio, 100); // 100ms +} + +function runRadio() +{ + // we don't want the read to block in this example, so always + // check to see if data is available first. + if (my_HMTRP_Radio.dataAvailable()) + { + var rv = my_HMTRP_Radio.readData(radioBuffer, bufferLength); + + if (rv > 0) + { + var resultStr = ""; + for (var x = 0; x < rv; x++) + resultStr += radioBuffer.getitem(x); + console.log("Received: " + resultStr); + } + + if (rv < 0) // some sort of read error occured + { + console.log("Port read error."); + return; + } + } + g_counter++; + // every second, transmit "Hello World" + if (g_counter > 10) + { + var msg = "Hello World!"; + + console.log("Transmitting " + msg + "..."); + + // Adding 1 for NULL terminator. + // Note that SWIG automatically adds a NULL terminator, + // so no need to NULL-terminate ourselves. + // Just increment the message length to include + // the NULL that's already there + my_HMTRP_Radio.writeData(msg, (msg.length + 1)); + g_counter = 0; + } +} + +// When exiting: clear interval and print message +process.on('SIGINT', function() +{ + clearInterval(g_myInterval); + console.log("Exiting..."); + process.exit(0); +}); diff --git a/src/carrays_uint32_t.i b/src/carrays_uint32_t.i new file mode 100644 index 00000000..21367b4a --- /dev/null +++ b/src/carrays_uint32_t.i @@ -0,0 +1,8 @@ +// From the SWIG documentation: +// Unlike #include, %include includes each file once +// (and will not reload the file on subsequent %include declarations). +// Therefore, it is not necessary to use include-guards in SWIG interfaces. +// So you can include this file and .i files for other C types +%include "stdint.i" +%include "carrays.i" +%array_class(uint32_t, uint32Array); diff --git a/src/hmtrp/CMakeLists.txt b/src/hmtrp/CMakeLists.txt new file mode 100644 index 00000000..6a43ba36 --- /dev/null +++ b/src/hmtrp/CMakeLists.txt @@ -0,0 +1,5 @@ +set (libname "hmtrp") +set (libdescription "upm grove serial rf pro (hmtrp) module") +set (module_src ${libname}.cxx) +set (module_h ${libname}.h) +upm_module_init() diff --git a/src/hmtrp/hmtrp.cxx b/src/hmtrp/hmtrp.cxx new file mode 100644 index 00000000..ce69335e --- /dev/null +++ b/src/hmtrp/hmtrp.cxx @@ -0,0 +1,464 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "hmtrp.h" + +using namespace upm; +using namespace std; + +static const int defaultDelay = 100; // max wait time for read + +// protocol start code +const uint8_t HMTRP_START1 = 0xaa; +const uint8_t HMTRP_START2 = 0xfa; + +HMTRP::HMTRP(int uart) +{ + m_ttyFd = -1; + + if ( !(m_uart = mraa_uart_init(uart)) ) + { + cerr << __FUNCTION__ << ": mraa_uart_init() failed" << endl; + return; + } + + // This requires a recent MRAA (1/2015) + char *devPath = mraa_uart_get_dev_path(m_uart); + + if (!devPath) + { + cerr << __FUNCTION__ << ": mraa_uart_get_dev_path() failed" << endl; + return; + } + + // now open the tty + if ( (m_ttyFd = open(devPath, O_RDWR)) == -1) + { + cerr << __FUNCTION__ << ": open of " << devPath << " failed: " + << strerror(errno) << endl; + return; + } +} + +HMTRP::~HMTRP() +{ + if (m_ttyFd != -1) + close(m_ttyFd); + + mraa_deinit(); +} + +bool HMTRP::dataAvailable(unsigned int millis) +{ + if (m_ttyFd == -1) + return false; + + struct timeval timeout; + + timeout.tv_sec = 0; + timeout.tv_usec = millis * 1000; + + int nfds; + fd_set readfds; + + FD_ZERO(&readfds); + + FD_SET(m_ttyFd, &readfds); + + if (select(m_ttyFd + 1, &readfds, NULL, NULL, &timeout) > 0) + return true; // data is ready + else + return false; +} + +int HMTRP::readData(char *buffer, size_t len, int millis) +{ + if (m_ttyFd == -1) + return(-1); + + // if specified, wait to see if input shows up, otherwise block + if (millis >= 0) + { + if (!dataAvailable(millis)) + return 0; // timed out + } + + int rv = read(m_ttyFd, buffer, len); + + if (rv < 0) + cerr << __FUNCTION__ << ": read failed: " << strerror(errno) << endl; + + return rv; +} + +int HMTRP::writeData(char *buffer, size_t len) +{ + if (m_ttyFd == -1) + return(-1); + + int rv = write(m_ttyFd, buffer, len); + + if (rv < 0) + { + cerr << __FUNCTION__ << ": write failed: " << strerror(errno) << endl; + return rv; + } + + tcdrain(m_ttyFd); + + return rv; +} + +bool HMTRP::setupTty(speed_t baud) +{ + if (m_ttyFd == -1) + return(false); + + struct termios termio; + + // get current modes + tcgetattr(m_ttyFd, &termio); + + // setup for a 'raw' mode. 81N, no echo or special character + // handling, such as flow control. + cfmakeraw(&termio); + + // set our baud rates + cfsetispeed(&termio, baud); + cfsetospeed(&termio, baud); + + // make it so + if (tcsetattr(m_ttyFd, TCSAFLUSH, &termio) < 0) + { + cerr << __FUNCTION__ << ": tcsetattr failed: " << strerror(errno) << endl; + return false; + } + + return true; +} + +bool HMTRP::checkOK() +{ + char buf[4]; + + int rv = readData(buf, 4, defaultDelay); + + if (rv != 4) + { + cerr << __FUNCTION__ << ": failed to receive OK response, rv = " + << rv << ", expected 4" << endl; + return false; + } + + // looking for "OK\r\n" + if (buf[0] == 'O' && buf[1] == 'K' && + buf[2] == '\r' && buf[3] == '\n') + return true; + else + return false; +} + +bool HMTRP::reset() +{ + char pkt[3]; + + pkt[0] = HMTRP_START1; + pkt[1] = HMTRP_START2; + pkt[2] = RESET; + + writeData(pkt, 3); + + return checkOK(); +} + +bool HMTRP::getConfig(uint32_t *freq, uint32_t *dataRate, + uint16_t *rxBandwidth, uint8_t *modulation, + uint8_t *txPower, uint32_t *uartBaud) +{ + char pkt[3]; + pkt[0] = HMTRP_START1; + pkt[1] = HMTRP_START2; + pkt[2] = GET_CONFIG; + + writeData(pkt, 3); + usleep(100000); + + // now read back a 16 byte response + char buf[16]; + int rv = readData(buf, 16, defaultDelay); + + if (rv != 16) + { + cerr << __FUNCTION__ << ": failed to receive correct response: rv = " + << rv << ", expected 16" << endl; + return false; + } + + // now decode + if (freq) + { + *freq = ( ((buf[0] & 0xff) << 24) | + ((buf[1] & 0xff) << 16) | + ((buf[2] & 0xff) << 8) | + (buf[3] & 0xff) ); + } + + if (dataRate) + { + *dataRate = ( ((buf[4] & 0xff) << 24) | + ((buf[5] & 0xff) << 16) | + ((buf[6] & 0xff) << 8) | + (buf[7] & 0xff) ); + } + + if (rxBandwidth) + { + *rxBandwidth = ( ((buf[8] & 0xff) << 8) | + (buf[9] & 0xff) ); + } + + if (modulation) + { + *modulation = buf[10] & 0xff; + } + + if (txPower) + { + *txPower = buf[11] & 0xff; + } + + if (uartBaud) + { + *uartBaud = ( ((buf[12] & 0xff) << 24) | + ((buf[13] & 0xff) << 16) | + ((buf[14] & 0xff) << 8) | + (buf[15] & 0xff) ); + } + + return true; +} + +bool HMTRP::setFrequency(uint32_t freq) +{ + char pkt[7]; + + pkt[0] = HMTRP_START1; + pkt[1] = HMTRP_START2; + pkt[2] = SET_FREQUENCY; + + pkt[3] = ( ((freq & 0xff000000) >> 24) & 0xff ); + pkt[4] = ( ((freq & 0x00ff0000) >> 16) & 0xff ); + pkt[5] = ( ((freq & 0x0000ff00) >> 8) & 0xff ); + pkt[6] = ( (freq & 0x000000ff) & 0xff ); + + writeData(pkt, 7); + + return checkOK(); +} + +bool HMTRP::setRFDataRate(uint32_t rate) +{ + // Valid values are between 1200-115200 + + if (rate < 1200 || rate > 115200) + { + cerr << __FUNCTION__ << "Valid values are between 1200-115200." << endl; + return false; + } + + char pkt[7]; + + pkt[0] = HMTRP_START1; + pkt[1] = HMTRP_START2; + pkt[2] = SET_RF_DATARATE; + + pkt[3] = ( ((rate & 0xff000000) >> 24) & 0xff ); + pkt[4] = ( ((rate & 0x00ff0000) >> 16) & 0xff ); + pkt[5] = ( ((rate & 0x0000ff00) >> 8) & 0xff ); + pkt[6] = ( (rate & 0x000000ff) & 0xff ); + + writeData(pkt, 7); + + return checkOK(); +} + +bool HMTRP::setRXBandwidth(uint16_t rxBand) +{ + // Valid values are between 30-620 (in Khz) + + if (rxBand < 30 || rxBand > 620) + { + cerr << __FUNCTION__ << "Valid values are between 30-620." << endl; + return false; + } + + char pkt[5]; + + pkt[0] = HMTRP_START1; + pkt[1] = HMTRP_START2; + pkt[2] = SET_RX_BW; + + pkt[3] = ( ((rxBand & 0xff00) >> 8) & 0xff ); + pkt[4] = ( rxBand & 0xff ); + + writeData(pkt, 5); + + return checkOK(); +} + +bool HMTRP::setFrequencyModulation(uint8_t modulation) +{ + // Valid values are between 10-160 (in Khz) + + if (modulation < 10 || modulation > 160) + { + cerr << __FUNCTION__ << "Valid values are between 10-160." << endl; + return false; + } + + char pkt[4]; + + pkt[0] = HMTRP_START1; + pkt[1] = HMTRP_START2; + pkt[2] = SET_FREQ_MODULATION; + + pkt[3] = modulation; + + writeData(pkt, 4); + + return checkOK(); +} + +bool HMTRP::setTransmitPower(uint8_t power) +{ + // Valid values are between 0-7 + + if (power > 7) + { + cerr << __FUNCTION__ << "Valid values are between 0-7." << endl; + return false; + } + + char pkt[4]; + + pkt[0] = HMTRP_START1; + pkt[1] = HMTRP_START2; + pkt[2] = SET_TX_POWER; + + pkt[3] = power; + + writeData(pkt, 4); + + return checkOK(); +} + +bool HMTRP::setUARTSpeed(uint32_t speed) +{ + // Valid values are between 1200-115200 + + if (speed < 1200 || speed > 115200) + { + cerr << __FUNCTION__ << "Valid values are between 1200-115200." << endl; + return false; + } + + char pkt[7]; + + pkt[0] = HMTRP_START1; + pkt[1] = HMTRP_START2; + pkt[2] = SET_UART_SPEED; + + pkt[3] = ( ((speed & 0xff000000) >> 24) & 0xff ); + pkt[4] = ( ((speed & 0x00ff0000) >> 16) & 0xff ); + pkt[5] = ( ((speed & 0x0000ff00) >> 8) & 0xff ); + pkt[6] = ( (speed & 0x000000ff) & 0xff ); + + writeData(pkt, 7); + + return checkOK(); +} + + +bool HMTRP::getRFSignalStrength(uint8_t *strength) +{ + if (!strength) + return false; + + char pkt[3]; + pkt[0] = HMTRP_START1; + pkt[1] = HMTRP_START2; + pkt[2] = GET_RF_SIGNAL_STR; + + writeData(pkt, 3); + usleep(100000); + + // now read back a 1 byte response + char buf; + int rv = readData(&buf, 1, defaultDelay); + + if (rv != 1) + { + cerr << __FUNCTION__ << ": failed to receive correct response: rv = " + << rv << ", expected 1" << endl; + return false; + } + + // now decode + *strength = (uint8_t)buf; + + return true; +} + +bool HMTRP::getModSignalStrength(uint8_t *strength) +{ + if (!strength) + return false; + + char pkt[3]; + pkt[0] = HMTRP_START1; + pkt[1] = HMTRP_START2; + pkt[2] = GET_MOD_SIGNAL_STR; + + writeData(pkt, 3); + usleep(100000); + + // now read back a 1 byte response + char buf; + int rv = readData(&buf, 1, defaultDelay); + + if (rv != 1) + { + cerr << __FUNCTION__ << ": failed to receive correct response: rv = " + << rv << ", expected 1" << endl; + return false; + } + + // now decode + *strength = (uint8_t)buf; + + return true; +} + diff --git a/src/hmtrp/hmtrp.h b/src/hmtrp/hmtrp.h new file mode 100644 index 00000000..473ac1c9 --- /dev/null +++ b/src/hmtrp/hmtrp.h @@ -0,0 +1,240 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define HMTRP_DEFAULT_UART 0 + +namespace upm { + + /** + * @brief C++ API for the HMTRP Serial RF Pro + * + * UPM support for the HMTRP Serial RF Pro. This was tested + * specifically with the Grove Serial RF Pro module. In theory, + * this class should work with the following devices: + * + * HM-TRP-433: 414000000-454000000Hz + * HM-TRP-470: 450000000-490000000Hz + * HM-TRP-868: 849000000-889000000Hz + * HM-TRP-915: 895000000-935000000Hz + * + * The only difference being the transmit and receive frequencies + * supported. + * + * By default, the device will simply send and receive any data + * presented on it's UART interface. It can be placed into a + * configuration mode by grounding the CONFIG pin on the module. + * + * @ingroup grove uart radio + * @snippet hmtrp.cxx Interesting + */ + class HMTRP { + public: + + // HMTRP opcodes + typedef enum { RESET = 0xf0, + GET_CONFIG = 0xe1, + SET_FREQUENCY = 0xd2, + SET_RF_DATARATE = 0xc3, // 1200-115200 (baud) + SET_RX_BW = 0xb4, // 30-620 (Khz) + SET_FREQ_MODULATION = 0xa5, // 10-160 (KHz) + SET_TX_POWER = 0x96, // 0-7 + SET_UART_SPEED = 0x1e, // recommended not to change + GET_RF_SIGNAL_STR = 0xa7, + GET_MOD_SIGNAL_STR = 0x78 + } HMTRP_OPCODE_T; + + /** + * HMTRP Serial RF Pro module constructor + * + * @param uart default uart to use (0 or 1) + */ + HMTRP(int uart=HMTRP_DEFAULT_UART); + + /** + * HMTRP Serial RF Pro module Destructor + */ + ~HMTRP(); + + /** + * Check to see if there is data available for reading + * + * @param millis number of milliseconds to wait, 0 means no wait (default). + * @return true if there is data available to be read + */ + bool dataAvailable(unsigned int millis=0); + + /** + * read any available data into a user-supplied buffer. + * + * @param buffer the buffer to hold the data read + * @param len the length of the buffer + * @param millis maxim time in milliseconds to wait for input. -1 means + * wait forever (default). + * @return the number of bytes read, 0 if timed out and millis >= 0 + */ + int readData(char *buffer, size_t len, int millis=-1); + + /** + * write the data in buffer to the device + * + * @param buffer the buffer to hold the data read + * @param len the length of the buffer + * @return the number of bytes written + */ + int writeData(char *buffer, size_t len); + + /** + * setup the proper tty i/o modes and the baudrate. The default + * baud rate is 9600 (B9600). + * + * @param baud the desired baud rate. + * @return true if successful + */ + bool setupTty(speed_t baud=B9600); + + /** + * Look for and verify an OK response. This will look like "OK\r\n" + * + * @return true if OK received + */ + bool checkOK(); + + /** + * reset the device to default parameters, except for UART baud rate + * + * @return true if successful + */ + bool reset(); + + /** + * Query the radio to determine it's configuration + * + * @param freq operating frequency + * @param dataRate tx/rx bit rate + * @param rxBandwidth receiving bandwidth in Khz + * @param modulation modulation frequency in Khz + * @param txPower transmission power (1-7) + * @param uartBaud UART baud rate + * @return true if successful + */ + bool getConfig(uint32_t *freq, uint32_t *dataRate, uint16_t *rxBandwidth, + uint8_t *modulation, uint8_t *txPower, uint32_t *uartBaud); + + /** + * set the frequency. Note, this is limited depending on which + * HM-TRP device you are using. Consult the datasheet. + * + * @param freq operating frequency + * @return true if successful + */ + bool setFrequency(uint32_t freq); + + /** + * set the RF data transmission rate. Valid values are between + * 1200-115200. + * + * @param rate radio transmission rate in baud (1200-115200) + * @return true if successful + */ + bool setRFDataRate(uint32_t rate); + + /** + * set the RX bandwidth. Valid values are between 30-620 (in Khz) + * + * @param rxBand set receive bandwidth (30-620) Khz + * @return true if successful + */ + bool setRXBandwidth(uint16_t rxBand); + + /** + * set the frequency modulation. Valid values are between 10-160 (in Khz) + * + * @param modulation frequency modulation to use (10-160) Khz + * @return true if successful + */ + bool setFrequencyModulation(uint8_t modulation); + + /** + * set the transmit power level. Valid values are between 0-7, + * with 7 being maximum power. + * + * @param power power level to use during transmit. Vaild values + * are between 0-7. + * @return true if successful + */ + bool setTransmitPower(uint8_t power); + + /** + * set the configured baud rate of the UART. It is strongly + * recommended that you do not change this or you may lose the + * ability to communicate with the module. Valid values are 1200-115200. + * + * @param speed desired baud rate to configure the device to use. + * Valid values are between 1200-115200. + * @return true if successful + */ + bool setUARTSpeed(uint32_t speed); + + /** + * get the RF signal strength. + * + * @param strength the returned strength + * @return true if successful + */ + bool getRFSignalStrength(uint8_t *strength); + + /** + * get the Modulation signal strength. + * + * @param strength the returned strength + * @return true if successful + */ + bool getModSignalStrength(uint8_t *strength); + + + private: + mraa_uart_context m_uart; + int m_ttyFd; + }; +} + + diff --git a/src/hmtrp/jsupm_hmtrp.i b/src/hmtrp/jsupm_hmtrp.i new file mode 100644 index 00000000..ff176b88 --- /dev/null +++ b/src/hmtrp/jsupm_hmtrp.i @@ -0,0 +1,34 @@ +%module jsupm_hmtrp +%include "../upm.i" +%include "../carrays_uint8_t.i" +%include "../carrays_uint16_t.i" +%include "../carrays_uint32_t.i" + +// Adding this typemap because SWIG is converting uint8, uint16, and uint32 into a short by default +// This forces SWIG to convert it correctly +%typemap(in) uint8_t * { + void *argp = 0 ; + int res = SWIG_ConvertPtr($input, &argp, SWIGTYPE_p_uint8Array, 0 | 0 ); + $1 = (uint8_t *)(argp); +} + +%typemap(in) uint16_t * { + void *argp = 0 ; + int res = SWIG_ConvertPtr($input, &argp, SWIGTYPE_p_uint16Array, 0 | 0 ); + $1 = (uint16_t *)(argp); +} + +%typemap(in) uint32_t * { + void *argp = 0 ; + int res = SWIG_ConvertPtr($input, &argp, SWIGTYPE_p_uint32Array, 0 | 0 ); + $1 = (uint32_t *)(argp); +} + +%{ + #include "hmtrp.h" + speed_t int_B9600 = B9600; +%} + +%include "hmtrp.h" +speed_t int_B9600 = B9600; +%array_class(char, charArray); diff --git a/src/hmtrp/pyupm_hmtrp.i b/src/hmtrp/pyupm_hmtrp.i new file mode 100644 index 00000000..25575637 --- /dev/null +++ b/src/hmtrp/pyupm_hmtrp.i @@ -0,0 +1,9 @@ +%module pyupm_hmtrp +%include "../upm.i" + +%feature("autodoc", "3"); + +%include "hmtrp.h" +%{ + #include "hmtrp.h" +%}