diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index e2e3a614..de28c088 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -327,6 +327,7 @@ add_example (ecezo) add_example (mb704x) add_example (rf22-server) add_example (rf22-client) +add_example (mcp2515) # These are special cases where you specify example binary, source file and module(s) include_directories (${PROJECT_SOURCE_DIR}/src) @@ -369,3 +370,4 @@ if (OPENZWAVE_FOUND) add_custom_example (tzemt400-example-cxx tzemt400.cxx ozw) endif() add_custom_example (nmea_gps_i2c_example-cxx nmea_gps_i2c.cxx nmea_gps) +add_custom_example (mcp2515-txrx-example-cxx mcp2515-txrx.cxx mcp2515) diff --git a/examples/c++/mcp2515-txrx.cxx b/examples/c++/mcp2515-txrx.cxx new file mode 100644 index 00000000..fb876688 --- /dev/null +++ b/examples/c++/mcp2515-txrx.cxx @@ -0,0 +1,125 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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 +#include + +#include "mcp2515.hpp" + +using namespace std; + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + + +int main(int argc, char **argv) +{ + signal(SIGINT, sig_handler); + + // by default we just receive packets + bool do_tx = false; + + // if an argument is given, we will transmit packets + if (argc > 1) + do_tx = true; +//! [Interesting] + + // NOTE: This example assumes that only two devices are connected + // to the CAN bus, and that both devices are running this example; + // one in TX (transmit) mode, and one in RX (receive) mode. + + // If this is not the case, then in rx mode you may see other + // packets from other devices, or not, depending on whether the + // speed is correct for the network. In tx mode, errors may be + // generated on the bus, especially if the CAN bus speed does not + // match the rest of the network. + + // You should start the receiver example first. The transmitter + // example will fail after about 5 seconds (timeout) of not being + // able to transmit a message. + + // Instantiate a MCP2515 on SPI bus 0 using a hw CS pin (-1). + upm::MCP2515 *sensor = new upm::MCP2515(0, 9); + + // By default, after initialization, the baud rate is set to + // 50Kbps, and the mode is NORMAL, so we don't need to set any of + // that here. + + // our TX payload. If transmitting, the first number will be + // incremented (and rollover) on each transmission. + string myPayload = "01234567"; + + while (shouldRun) + { + if (do_tx) + { + cout << "Loading a packet of 8 numbers (0-7) into a TX buffer..." + << endl; + sensor->loadTXBuffer(MCP2515_TX_BUFFER0, 0, false, false, + myPayload); + + // now lets try to transmit it + cout << "Transmitting packet..." << endl; + sensor->transmitBuffer(MCP2515_TX_BUFFER0, true); + + myPayload[0]++; + cout << "Transmit successful" << endl; + cout << endl; + + upm_delay_ms(500); + } + else + { + // RX mode + // Look for a packet waiting for us in RXB0 + if (sensor->rxStatusMsgs() == MCP2515_RXMSG_RXB0) + { + cout << "Packet received in RXB0, decoding..." << endl; + + // now lets retrieve and print it + sensor->getRXMsg(MCP2515_RX_BUFFER0); + + sensor->printMsg(); + cout << endl; + } + + upm_delay_ms(100); + } + } + + cout << "Exiting..." << endl; + + delete sensor; +//! [Interesting] + + return 0; +} diff --git a/examples/c++/mcp2515.cxx b/examples/c++/mcp2515.cxx new file mode 100644 index 00000000..3cc77924 --- /dev/null +++ b/examples/c++/mcp2515.cxx @@ -0,0 +1,79 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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 "mcp2515.hpp" + +using namespace std; + +int main(int argc, char **argv) +{ +//! [Interesting] + + // Instantiate a MCP2515 on SPI bus 0 using a hw CS pin (-1). + upm::MCP2515 *sensor = new upm::MCP2515(0, -1); + + cout << "Setting loopback mode..." << endl; + + // set the mode to loopback mode. In loopback mode, transmitted + // packets are sent directly to an appropriate receive buffer + // without actually going out onto the CAN bus. + sensor->setOpmode(MCP2515_OPMODE_LOOPBACK); + + // lets build up a packet and try loading it (8 bytes max). + string myPayload = "01234567"; + cout << "Loading a packet of 8 numbers (0-7) into a TX buffer..." << endl; + sensor->loadTXBuffer(MCP2515_TX_BUFFER0, 0, false, false, myPayload); + + // now lets try to transmit it + cout << "Transmitting packet..." << endl; + sensor->transmitBuffer(MCP2515_TX_BUFFER0, true); + + cout << "Transmit successful" << endl; + + // There should now be a packet waiting for us in RXB0 + if (sensor->rxStatusMsgs() == MCP2515_RXMSG_RXB0) + { + cout << "Packet received in RXB0, decoding..." << endl; + + // now lets retrieve and print it + sensor->getRXMsg(MCP2515_RX_BUFFER0); + + sensor->printMsg(); + } + else + { + cout << "No packet found, how strange." << endl; + } + + cout << "Exiting..." << endl; + + delete sensor; +//! [Interesting] + + return 0; +} diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index dd08f195..8eb8e86b 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -141,6 +141,7 @@ add_example (ms5803) add_example (ims) add_example (ecezo) add_example (mb704x) +add_example (mcp2515) # Custom examples add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps) @@ -149,3 +150,4 @@ add_custom_example (lcm1602-parallel-example-c lcm1602-parallel.c lcm1602) add_custom_example (rpr220-intr-example-c rpr220-intr.c rpr220) add_custom_example (md-stepper-example-c md-stepper.c md) add_custom_example (button_intr-example-c button_intr.c button) +add_custom_example (mcp2515-txrx-example-c mcp2515-txrx.c mcp2515) diff --git a/examples/c/mcp2515-txrx.c b/examples/c/mcp2515-txrx.c new file mode 100644 index 00000000..971bd9ac --- /dev/null +++ b/examples/c/mcp2515-txrx.c @@ -0,0 +1,144 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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 + +#include "mcp2515.h" + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main(int argc, char **argv) +{ + signal(SIGINT, sig_handler); + + // by default we just receive packets + bool do_tx = false; + + // if an argument is given, we will transmit packets + if (argc > 1) + do_tx = true; +//! [Interesting] + + // NOTE: This example assumes that only two devices are connected + // to the CAN bus, and that both devices are running this example; + // one in TX (transmit) mode, and one in RX (receive) mode. + + // If this is not the case, then in rx mode you may see other + // packets from other devices, or not, depending on whether the + // speed is correct for the network. In tx mode, errors may be + // generated on the bus, especially if the CAN bus speed does not + // match the rest of the network. + + // You should start the receiver example first. The transmitter + // example will fail after about 5 seconds (timeout) of not being + // able to transmit a message. + + // Instantiate a MCP2515 on SPI bus 0 using a hw CS pin (-1). + mcp2515_context sensor = mcp2515_init(0, -1); + + if (!sensor) + { + printf("mcp2515_init() failed\n"); + return 1; + } + + // By default, after initialization, the baud rate is set to + // 50Kbps, and the mode is NORMAL, so we don't need to set any of + // that here. + + if (!do_tx) + printf("RX mode, waiting for packets...\n"); + + // our TX payload. If transmitting, the first number will be + // incremented (and rollover) on each transmission. + uint8_t myPayload[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + + while (shouldRun) + { + if (do_tx) + { + // lets build up a packet and try loading it. + printf("Loading a packet of 8 numbers into a tx buffer...\n"); + if (mcp2515_load_tx_buffer(sensor, MCP2515_TX_BUFFER0, 0, + false, false, myPayload, 8)) + { + printf("mcp2515_load_tx_buffer() failed\n"); + return 1; + } + + // now lets try to transmit it + printf("Transmitting packet...\n"); + upm_result_t rv = 0; + if ((rv = mcp2515_transmit_buffer(sensor, MCP2515_TX_BUFFER0, + true))) + { + printf("mcp2515_transmit_buffer() failed with code %d\n", rv); + return 1; + } + + // increment the first number for each transmission + myPayload[0]++; + printf("Transmit successful\n\n"); + upm_delay_ms(500); + } + else + { + // RX mode + // Look for a packet waiting for us in RXB0 + if (mcp2515_rx_status_msgs(sensor) == MCP2515_RXMSG_RXB0) + { + printf("Packet received in RXB0, decoding...\n"); + + // now lets retrieve it + MCP2515_MSG_T msg; + if (mcp2515_get_rx_msg(sensor, MCP2515_RX_BUFFER0, &msg)) + { + printf("mcp2515_get_rx_msg() failed\n"); + return 1; + } + mcp2515_print_msg(sensor, &msg); + printf("\n"); + } + + upm_delay_ms(100); + } + + } + + printf("Exiting...\n"); + + mcp2515_close(sensor); +//! [Interesting] + + return 0; +} diff --git a/examples/c/mcp2515.c b/examples/c/mcp2515.c new file mode 100644 index 00000000..e21cf8aa --- /dev/null +++ b/examples/c/mcp2515.c @@ -0,0 +1,101 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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 "mcp2515.h" + +int main(int argc, char **argv) +{ +//! [Interesting] + + // Instantiate a MCP2515 on SPI bus 0 using a hw CS pin (-1). + mcp2515_context sensor = mcp2515_init(0, -1); + + if (!sensor) + { + printf("mcp2515_init() failed\n"); + return 1; + } + + printf("Setting loopback mode...\n"); + + // set the mode to loopback mode. In loopback mode, transmitted + // packets are sent directly to an appropriate receive buffer + // without actually going out onto the CAN bus. + if (mcp2515_set_opmode(sensor, MCP2515_OPMODE_LOOPBACK)) + { + printf("mcp2515_set_opmode(loopback) failed.\n"); + return 1; + } + + // lets build up a packet and try loading it. + uint8_t myPayload[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + printf("Loading a packet of 8 numbers (0-7) into a TX buffer...\n"); + if (mcp2515_load_tx_buffer(sensor, MCP2515_TX_BUFFER0, 0, false, false, + myPayload, 8)) + { + printf("mcp2515_load_tx_buffer() failed\n"); + return 1; + } + + // now lets try to transmit it + printf("Transmitting packet...\n"); + upm_result_t rv = 0; + if ((rv = mcp2515_transmit_buffer(sensor, MCP2515_TX_BUFFER0, true))) + { + printf("mcp2515_transmit_buffer() failed with code %d\n", rv); + return 1; + } + + printf("Transmit successful\n"); + + // There should now be a packet waiting for us in RXB0 + if (mcp2515_rx_status_msgs(sensor) == MCP2515_RXMSG_RXB0) + { + printf("Packet received in RXB0, decoding...\n"); + + // now lets retrieve it + MCP2515_MSG_T msg; + if (mcp2515_get_rx_msg(sensor, MCP2515_RX_BUFFER0, &msg)) + { + printf("mcp2515_get_rx_msg() failed\n"); + return 1; + } + + mcp2515_print_msg(sensor, &msg); + } + else + { + printf("No packet found, how strange.\n"); + } + + printf("Exiting...\n"); + + mcp2515_close(sensor); +//! [Interesting] + + return 0; +} diff --git a/examples/java/CMakeLists.txt b/examples/java/CMakeLists.txt index 19f919be..3e7b40f4 100644 --- a/examples/java/CMakeLists.txt +++ b/examples/java/CMakeLists.txt @@ -160,6 +160,7 @@ add_example(MS5803_Example ms5803) add_example(ECEZO_Example ecezo) add_example(IMS_Example ims) add_example(MB704X_Example mb704x) +add_example(MCP2515_Example mcp2515) add_example_with_path(Jhd1313m1_lcdSample lcd i2clcd) add_example_with_path(Jhd1313m1Sample lcd i2clcd) @@ -181,3 +182,4 @@ if (OPENZWAVE_FOUND) add_example_with_path(TZEMT400_Example ozw ozw) endif() add_example_with_path(NMEAGPS_I2C_Example nmea_gps nmea_gps) +add_example_with_path(MCP2515_TXRX_Example mcp2515 mcp2515) diff --git a/examples/java/MCP2515_Example.java b/examples/java/MCP2515_Example.java new file mode 100644 index 00000000..50062ec7 --- /dev/null +++ b/examples/java/MCP2515_Example.java @@ -0,0 +1,73 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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. + */ + +import upm_mcp2515.MCP2515; + +public class MCP2515_Example +{ + public static void main(String[] args) throws InterruptedException + { +// ! [Interesting] + + // Instantiate a MCP2515 on SPI bus 0 using a hw CS pin (-1). + MCP2515 sensor = new MCP2515(0, -1); + + // set the mode to loopback mode. In loopback mode, transmitted + // packets are sent directly to an appropriate receive buffer + // without actually going out onto the CAN bus. + sensor.setOpmode(upm_mcp2515.MCP2515_OPMODE_T.MCP2515_OPMODE_LOOPBACK); + + // lets build up a packet and try loading it (8 bytes max). + String myPayload = "01234567"; + System.out.println("Loading a packet of 8 numbers (0-7) into a TX buffer..."); + sensor.loadTXBuffer(upm_mcp2515.MCP2515_TX_BUFFER_T.MCP2515_TX_BUFFER0, + 0, false, false, myPayload); + + // now lets try to transmit it + System.out.println("Transmitting packet..."); + sensor.transmitBuffer(upm_mcp2515.MCP2515_TX_BUFFER_T.MCP2515_TX_BUFFER0, + true); + + System.out.println("Transmit successful"); + + // There should now be a packet waiting for us in RXB0 + if (sensor.rxStatusMsgs() == upm_mcp2515.MCP2515_RXMSG_T.MCP2515_RXMSG_RXB0) + { + System.out.println("Packet received in RXB0, decoding..."); + + // now lets retrieve and print it + sensor.getRXMsg(upm_mcp2515.MCP2515_RX_BUFFER_T.MCP2515_RX_BUFFER0); + + sensor.printMsg(); + } + else + { + System.out.println("No packet found, how strange."); + } + + System.out.println("Exiting..."); + +// ! [Interesting] + } +} diff --git a/examples/java/MCP2515_TXRX_Example.java b/examples/java/MCP2515_TXRX_Example.java new file mode 100644 index 00000000..81e4e7a3 --- /dev/null +++ b/examples/java/MCP2515_TXRX_Example.java @@ -0,0 +1,94 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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. + */ + +import upm_mcp2515.MCP2515; + +public class MCP2515_TXRX_Example +{ + public static void main(String[] args) throws InterruptedException + { +// ! [Interesting] + + // by default we just receive packets + Boolean do_tx = false; + if (args.length > 0) + do_tx = true; + + // Instantiate a MCP2515 on SPI bus 0 using a hw CS pin (-1). + MCP2515 sensor = new MCP2515(0, -1); + + // NOTE: This example assumes that only two devices are connected + // to the CAN bus, and that both devices are running this example; + // one in TX (transmit) mode, and one in RX (receive) mode. + + // If this is not the case, then in rx mode you may see other + // packets from other devices, or not, depending on whether the + // speed is correct for the network. In tx mode, errors may be + // generated on the bus, especially if the CAN bus speed does not + // match the rest of the network. + + // You should start the receiver example first. The transmitter + // example will fail after about 5 seconds (timeout) of not being + // able to transmit a message. + + while (true) + { + if (do_tx) + { + // lets build up a packet and try loading it (8 bytes max). + String myPayload = "01234567"; + System.out.println("Loading a packet of 8 numbers (0-7) into a TX buffer..."); + sensor.loadTXBuffer(upm_mcp2515.MCP2515_TX_BUFFER_T.MCP2515_TX_BUFFER0, + 0, false, false, myPayload); + + // now lets try to transmit it + System.out.println("Transmitting packet..."); + sensor.transmitBuffer(upm_mcp2515.MCP2515_TX_BUFFER_T.MCP2515_TX_BUFFER0, + true); + + System.out.println("Transmit successful"); + System.out.println(); + Thread.sleep(500); + } + else + { + // There should now be a packet waiting for us in RXB0 + if (sensor.rxStatusMsgs() == upm_mcp2515.MCP2515_RXMSG_T.MCP2515_RXMSG_RXB0) + { + System.out.println("Packet received in RXB0, decoding..."); + + // now lets retrieve and print it + sensor.getRXMsg(upm_mcp2515.MCP2515_RX_BUFFER_T.MCP2515_RX_BUFFER0); + + sensor.printMsg(); + System.out.println(); + } + + Thread.sleep(100); + } + } + +// ! [Interesting] + } +} diff --git a/examples/javascript/mcp2515-txrx.js b/examples/javascript/mcp2515-txrx.js new file mode 100644 index 00000000..73ecf61c --- /dev/null +++ b/examples/javascript/mcp2515-txrx.js @@ -0,0 +1,94 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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. + */ + +var sensorObj = require('jsupm_mcp2515'); + +// Instantiate a MCP2515 on SPI bus 0 using a hw CS pin (-1). +var sensor = new sensorObj.MCP2515(0, -1); + +// NOTE: This example assumes that only two devices are connected +// to the CAN bus, and that both devices are running this example; +// one in TX (transmit) mode, and one in RX (receive) mode. + +// If this is not the case, then in rx mode you may see other +// packets from other devices, or not, depending on whether the +// speed is correct for the network. In tx mode, errors may be +// generated on the bus, especially if the CAN bus speed does not +// match the rest of the network. + +// You should start the receiver example first. The transmitter +// example will fail after about 5 seconds (timeout) of not being +// able to transmit a message. + +function transmit(sensor) +{ + // lets build up a packet and try loading it (8 bytes max). + var myPayload = "01234567"; + console.log("Loading a packet of 8 numbers (0-7) into a TX buffer..."); + sensor.loadTXBuffer(sensorObj.MCP2515_TX_BUFFER0, + 0, false, false, myPayload); + + // now lets try to transmit it + console.log("Transmitting packet..."); + sensor.transmitBuffer(sensorObj.MCP2515_TX_BUFFER0, true); + + console.log("Transmit successful"); + console.log(); +} + +function receive(sensor) +{ + // There should now be a packet waiting for us in RXB0 + if (sensor.rxStatusMsgs() == sensorObj.MCP2515_RXMSG_RXB0) + { + console.log("Packet received in RXB0, decoding..."); + + // now lets retrieve and print it + sensor.getRXMsg(sensorObj.MCP2515_RX_BUFFER0); + + sensor.printMsg(); + console.log(); + } +} + +// by default we just receive packets +if (process.argv.length > 2) +{ + // transmit mode + interval = setInterval(function() { transmit(sensor); }, 500); +} +else +{ + // receive mode + interval = setInterval(function() { receive(sensor); }, 100); +} + +process.on('SIGINT', function() +{ + sensor = null; + sensorObj.cleanUp(); + sensorObj = null; + console.log("Exiting..."); + process.exit(0); +}); diff --git a/examples/javascript/mcp2515.js b/examples/javascript/mcp2515.js new file mode 100644 index 00000000..160ae077 --- /dev/null +++ b/examples/javascript/mcp2515.js @@ -0,0 +1,66 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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. + */ + +var sensorObj = require('jsupm_mcp2515'); + +// Instantiate a MCP2515 on SPI bus 0 using a hw CS pin (-1). +var sensor = new sensorObj.MCP2515(0, -1); + +// set the mode to loopback mode. In loopback mode, transmitted +// packets are sent directly to an appropriate receive buffer +// without actually going out onto the CAN bus. +sensor.setOpmode(sensorObj.MCP2515_OPMODE_LOOPBACK); + +// lets build up a packet and try loading it (8 bytes max). +var myPayload = "01234567"; +console.log("Loading a packet of 8 numbers (0-7) into a TX buffer..."); +sensor.loadTXBuffer(sensorObj.MCP2515_TX_BUFFER0, 0, false, false, myPayload); + +// now lets try to transmit it +console.log("Transmitting packet..."); +sensor.transmitBuffer(sensorObj.MCP2515_TX_BUFFER0, true); + +console.log("Transmit successful"); + +// There should now be a packet waiting for us in RXB0 +if (sensor.rxStatusMsgs() == sensorObj.MCP2515_RXMSG_RXB0) +{ + console.log("Packet received in RXB0, decoding..."); + + // now lets retrieve and print it + sensor.getRXMsg(sensorObj.MCP2515_RX_BUFFER0); + + sensor.printMsg(); +} +else +{ + console.log("No packet found, how strange."); +} + +console.log("Exiting..."); + +sensor = null; +sensorObj.cleanUp(); +sensorObj = null; +process.exit(0); diff --git a/examples/python/mcp2515-txrx.py b/examples/python/mcp2515-txrx.py new file mode 100755 index 00000000..0e933570 --- /dev/null +++ b/examples/python/mcp2515-txrx.py @@ -0,0 +1,99 @@ +#!/usr/bin/python +# Author: Jon Trulson +# Copyright (c) 2016 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. + +from __future__ import print_function +import time, sys, signal, atexit +from upm import pyupm_mcp2515 as MCP2515 + +def main(): + # Instantiate a MCP2515 on SPI bus 0 using a hw CS pin (-1). + sensor = MCP2515.MCP2515(0, -1) + + ## Exit handlers ## + # This function stops python from printing a stacktrace when you + # hit control-C + def SIGINTHandler(signum, frame): + raise SystemExit + + # This function lets you run code on exit, including functions from sensor + def exitHandler(): + print("Exiting") + sys.exit(0) + + # Register exit handlers + atexit.register(exitHandler) + signal.signal(signal.SIGINT, SIGINTHandler) + + # by default we just receive packets + do_tx = False; + if (len(sys.argv) > 1): + do_tx = True + + # NOTE: This example assumes that only two devices are connected + # to the CAN bus, and that both devices are running this example; + # one in TX (transmit) mode, and one in RX (receive) mode. + + # If this is not the case, then in rx mode you may see other + # packets from other devices, or not, depending on whether the + # speed is correct for the network. In tx mode, errors may be + # generated on the bus, especially if the CAN bus speed does not + # match the rest of the network. + + # You should start the receiver example first. The transmitter + # example will fail after about 5 seconds (timeout) of not being + # able to transmit a message. + + # By default, after initialization, the baud rate is set to + # 50Kbps, and the mode is NORMAL, so we don't need to set any of + # that here. + + while (True): + if (do_tx): + print("Loading a packet of 8 numbers (0-7) into a TX buffer...") + myPayload = "01234567"; + sensor.loadTXBuffer(MCP2515.MCP2515_TX_BUFFER0, 0, False, + False, myPayload); + + # now lets try to transmit it + print("Transmitting packet...") + sensor.transmitBuffer(MCP2515.MCP2515_TX_BUFFER0, True) + + print("Transmit successful") + print() + time.sleep(.5) + else: + # RX mode + # Look for a packet waiting for us in RXB0 + if (sensor.rxStatusMsgs() == MCP2515.MCP2515_RXMSG_RXB0): + print("Packet received in RXB0, decoding...") + + # now lets retrieve and print it + sensor.getRXMsg(MCP2515.MCP2515_RX_BUFFER0) + + sensor.printMsg(); + print() + + print("Exiting...") + +if __name__ == '__main__': + main() diff --git a/examples/python/mcp2515.py b/examples/python/mcp2515.py new file mode 100755 index 00000000..5a228c0d --- /dev/null +++ b/examples/python/mcp2515.py @@ -0,0 +1,79 @@ +#!/usr/bin/python +# Author: Jon Trulson +# Copyright (c) 2016 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. + +from __future__ import print_function +import time, sys, signal, atexit +from upm import pyupm_mcp2515 as MCP2515 + +def main(): + # Instantiate a MCP2515 on SPI bus 0 using a hw CS pin (-1). + sensor = MCP2515.MCP2515(0, -1) + + ## Exit handlers ## + # This function stops python from printing a stacktrace when you + # hit control-C + def SIGINTHandler(signum, frame): + raise SystemExit + + # This function lets you run code on exit, including functions from sensor + def exitHandler(): + print("Exiting") + sys.exit(0) + + # Register exit handlers + atexit.register(exitHandler) + signal.signal(signal.SIGINT, SIGINTHandler) + + print("Setting loopback mode...") + + # set the mode to loopback mode. In loopback mode, transmitted + # packets are sent directly to an appropriate receive buffer + # without actually going out onto the CAN bus. + sensor.setOpmode(MCP2515.MCP2515_OPMODE_LOOPBACK); + + # lets build up a packet and try loading it (8 bytes max). + myPayload = "01234567"; + print("Loading a packet of 8 numbers (0-7) into a TX buffer...") + sensor.loadTXBuffer(MCP2515.MCP2515_TX_BUFFER0, 0, False, False, myPayload); + + # now lets try to transmit it + print("Transmitting packet...") + sensor.transmitBuffer(MCP2515.MCP2515_TX_BUFFER0, True); + + print("Transmit successful") + + # There should now be a packet waiting for us in RXB0 + if (sensor.rxStatusMsgs() == MCP2515.MCP2515_RXMSG_RXB0): + print("Packet received in RXB0, decoding...") + + # now lets retrieve and print it + sensor.getRXMsg(MCP2515.MCP2515_RX_BUFFER0); + + sensor.printMsg(); + else: + print("No packet found, how strange.") + + print("Exiting...") + +if __name__ == '__main__': + main() diff --git a/src/mcp2515/CMakeLists.txt b/src/mcp2515/CMakeLists.txt new file mode 100644 index 00000000..92c40a45 --- /dev/null +++ b/src/mcp2515/CMakeLists.txt @@ -0,0 +1,8 @@ +upm_mixed_module_init (NAME mcp2515 + DESCRIPTION "CAN bus controller" + C_HDR mcp2515.h mcp2515_regs.h + C_SRC mcp2515.c + CPP_HDR mcp2515.hpp + CPP_SRC mcp2515.cxx + CPP_WRAPS_C + REQUIRES mraa) diff --git a/src/mcp2515/javaupm_mcp2515.i b/src/mcp2515/javaupm_mcp2515.i new file mode 100644 index 00000000..0cd3e645 --- /dev/null +++ b/src/mcp2515/javaupm_mcp2515.i @@ -0,0 +1,25 @@ +%module javaupm_mcp2515 +%include "../upm.i" +%include "typemaps.i" +%include "arrays_java.i" +%include "../java_buffer.i" +%include "std_string.i" +%include "../carrays_uint8_t.i" + +%include "mcp2515_regs.h" +%include "mcp2515.hpp" +%{ + #include "mcp2515.hpp" +%} + + +%pragma(java) jniclasscode=%{ + static { + try { + System.loadLibrary("javaupm_mcp2515"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. \n" + e); + System.exit(1); + } + } +%} diff --git a/src/mcp2515/jsupm_mcp2515.i b/src/mcp2515/jsupm_mcp2515.i new file mode 100644 index 00000000..4578b6d8 --- /dev/null +++ b/src/mcp2515/jsupm_mcp2515.i @@ -0,0 +1,13 @@ +%module jsupm_mcp2515 +%include "../upm.i" +%include "cpointer.i" +%include "std_string.i" +%include "../carrays_uint8_t.i" + +%pointer_functions(float, floatp); + +%include "mcp2515_regs.h" +%include "mcp2515.hpp" +%{ + #include "mcp2515.hpp" +%} diff --git a/src/mcp2515/license.txt b/src/mcp2515/license.txt new file mode 100644 index 00000000..ccbbd2d0 --- /dev/null +++ b/src/mcp2515/license.txt @@ -0,0 +1,51 @@ +The table of CNF1-3 valuses used to set the CAN bus baudrate were +taken from the Seeed studio code at: + +https://github.com/Seeed-Studio/CAN_BUS_Shield/ + +/* + mcp_can.cpp + 2012 Copyright (c) Seeed Technology Inc. All right reserved. + + Author:Loovee + 2014-1-16 + + Contributor: + + Cory J. Fowler + Latonita + Woodward1 + Mehtajaghvi + BykeBlast + TheRo0T + Tsipizic + ralfEdmund + Nathancheek + BlueAndi + Adlerweb + Btetz + Hurvajs + xboxpro1 + + The MIT License (MIT) + + Copyright (c) 2013 Seeed Technology Inc. + + 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. +*/ diff --git a/src/mcp2515/mcp2515.c b/src/mcp2515/mcp2515.c new file mode 100644 index 00000000..c9639824 --- /dev/null +++ b/src/mcp2515/mcp2515.c @@ -0,0 +1,1112 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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 "mcp2515.h" + +#include +#include + +// in ms +#define MCP2515_MAX_TIMEOUT (5000) + +// static array of cnf1-3 value for setting speed. These values were +// taken from the Seeed code at: +// https://github.com/Seeed-Studio/CAN_BUS_Shield/ + +struct _mcp2515_config { + uint8_t cnf1; + uint8_t cnf2; + uint8_t cnf3; +}; + +// NOTE: These indexes must match the enum MCP2515_SPEED_T values in +// mcp2515_regs.h! Add any new values to the end, with a corresponding +// enum value in MCP2515_SPEED_T. +static struct _mcp2515_config mcp2515_configs[] = { + { 0x3f, 0xff, 0x87 }, // 0 - 5kbps + { 0x1f, 0xff, 0x87 }, // 1 - 10kbps + { 0x0f, 0xff, 0x87 }, // 2 - 20kbps + { 0x0f, 0xba, 0x07 }, // 3 - 25kbps + { 0x0f, 0xf1, 0x85 }, // 4 - 31k25kbps + { 0x09, 0xbe, 0x07 }, // 5 - 33kbps + { 0x07, 0xff, 0x87 }, // 6 - 40kbps + { 0x07, 0xfa, 0x87 }, // 7 - 50kbps + { 0x03, 0xff, 0x87 }, // 8 - 80kbps + { 0x03, 0xbe, 0x07 }, // 9 - 83kbps + + { 0x03, 0xad, 0x07 }, // 10 - 95kbps + { 0x03, 0xfa, 0x87 }, // 11 - 100kbps + { 0x03, 0xf0, 0x86 }, // 12 - 125kbps + { 0x01, 0xfa, 0x87 }, // 13 - 200kbps + { 0x41, 0xf1, 0x85 }, // 14 - 250kbps + { 0x00, 0xf0, 0x86 }, // 15 - 500kbps + { 0x00, 0xa0, 0x04 }, // 16 - 666kbps + { 0x00, 0xd0, 0x82 }, // 17 - 1000kbps +}; + +// For SPI, these are our CS on/off functions, if needed +static void mcp2515_cs_on(const mcp2515_context dev) +{ + assert(dev != NULL); + + if (dev->gpio) + mraa_gpio_write(dev->gpio, 0); +} + +static void mcp2515_cs_off(const mcp2515_context dev) +{ + assert(dev != NULL); + + if (dev->gpio) + mraa_gpio_write(dev->gpio, 1); +} + +// convert an integer id into the 4-byte breakout format used by the +// device. +static void mcp2515_int_to_id(const mcp2515_context dev, int id, bool ext, + bool is_filter, MCP2515_ID_T *did) +{ + assert(dev != NULL); + assert(did != NULL); + + // mask off all but the lower 29 bits + id &= 0x1fffffff; + + did->SIDH = (id >> 3) & 0xff; + did->SIDL = ((id & 0x07) << 5); + did->EID8 = 0; + did->EID0 = 0; + + // This is a sort of special case (ext vs. filter). When using + // this function to create a filter, but the msg type is standard, + // the filtering/masking engine can use the first 16 bits of + // extended filter data (EID8, EID0) to compare against the first + // 16 bits of the data payload (D0 and D1). For a standard id, + // the extended bits 16 and 17 are ignored, so we only include + // these (along with the extended bit) on true extended ids + // regardless of filtering. + if (ext || is_filter) + { + if (ext) + { + // add ext bits 17 and 16 + did->SIDL |= ((id & 0x18000000) >> 27) & 0x03; + // set the extended id bit + did->SIDL |= MCP2515_SIDL_EXIDE; + } + // now fill in the extended bits + did->EID8 = (id >> 19) & 0xff; + did->EID0 = (id >> 11) & 0xff; + } +} + +// convert the 4-byte breakout format used by the device into an integer id +static int mcp2515_id_to_int(const mcp2515_context dev, bool *ext, + MCP2515_ID_T *did) +{ + assert(dev != NULL); + assert(did != NULL); + + int id = 0; + *ext = false; + + id |= (did->SIDH << 3); + id |= (did->SIDL >> 5) & 0x07; + + // is it an extended id? + if (did->SIDL & MCP2515_SIDL_EXIDE) + { + *ext = true; + id |= ((did->SIDL & 0x03) << 27); + + id |= (did->EID8 << 19); + id |= (did->EID0 << 11); + } + + return id; +} + +// init... +mcp2515_context mcp2515_init(int bus, int cs_pin) +{ + mcp2515_context dev = + (mcp2515_context)malloc(sizeof(struct _mcp2515_context)); + + if (!dev) + return NULL; + + // zero out context + memset((void *)dev, 0, sizeof(struct _mcp2515_context)); + + // make sure MRAA is initialized + int mraa_rv; + if ((mraa_rv = mraa_init()) != MRAA_SUCCESS) + { + printf("%s: mraa_init() failed (%d).\n", __FUNCTION__, mraa_rv); + mcp2515_close(dev); + return NULL; + } + + if (!(dev->spi = mraa_spi_init(bus))) + { + printf("%s: mraa_spi_init() failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + // Only create cs context if we are actually using a valid pin. + // A hardware controlled pin should specify cs as -1. + if (cs_pin >= 0) + { + if (!(dev->gpio = mraa_gpio_init(cs_pin))) + { + printf("%s: mraa_gpio_init() failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + mraa_gpio_dir(dev->gpio, MRAA_GPIO_OUT); + mcp2515_cs_off(dev); + } + + if (mraa_spi_mode(dev->spi, MRAA_SPI_MODE0)) + { + printf("%s: mraa_spi_mode() failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + if (mraa_spi_frequency(dev->spi, 10000000)) + { + printf("%s: mraa_spi_frequency() failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + // reset + if (mcp2515_reset(dev)) + { + printf("%s: mcp2515_reset() failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + // make sure the mode is config (should be after a reset), set a + // default speed, and then set normal mode. + if (mcp2515_set_opmode(dev, MCP2515_OPMODE_CONFIG)) + { + printf("%s: mcp2515_set_opmode(config) failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + if (mcp2515_set_speed(dev, MCP2515_SPEED_50KBPS)) + { + printf("%s: mcp2515_set_speed() failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + // clear all filters and masks + if (mcp2515_set_filter(dev, MCP2515_RX_FILTER0, false, 0) + || mcp2515_set_filter(dev, MCP2515_RX_FILTER1, false, 0) + || mcp2515_set_filter(dev, MCP2515_RX_FILTER2, false, 0) + || mcp2515_set_filter(dev, MCP2515_RX_FILTER3, false, 0) + || mcp2515_set_filter(dev, MCP2515_RX_FILTER4, false, 0) + || mcp2515_set_filter(dev, MCP2515_RX_FILTER5, false, 0)) + { + printf("%s: mcp2515_set_filter() failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + if (mcp2515_set_mask(dev, MCP2515_RX_MASK0, false, 0) + || mcp2515_set_mask(dev, MCP2515_RX_MASK1, false, 0)) + { + printf("%s: mcp2515_set_mask() failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + // set the mode for any filter. With the above settings, all + // packets will be received since all of the mode bits are 0, so + // the filter bits are ignored. + if (mcp2515_set_rx_buffer_mode(dev, MCP2515_RX_BUFFER0, + MCP2515_RXMODE_ANY_FILTER) + || mcp2515_set_rx_buffer_mode(dev, MCP2515_RX_BUFFER1, + MCP2515_RXMODE_ANY_FILTER)) + { + printf("%s: mcp2515_set_rx_buffer_mode() failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + // turn off all interrupt enables + if (mcp2515_set_intr_enables(dev, 0)) + { + printf("%s: mcp2515_set_intr_enables() failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + // switch to normal operating mode + if (mcp2515_set_opmode(dev, MCP2515_OPMODE_NORMAL)) + { + printf("%s: mcp2515_set_opmode(normal) failed.\n", __FUNCTION__); + mcp2515_close(dev); + return NULL; + } + + return dev; +} + +void mcp2515_close(mcp2515_context dev) +{ + assert(dev != NULL); + + mcp2515_uninstall_isr(dev); + + if (dev->spi) + mraa_spi_stop(dev->spi); + + if (dev->gpio) + mraa_gpio_close(dev->gpio); + + free(dev); +} + +// bus read and write functions +upm_result_t mcp2515_bus_read(const mcp2515_context dev, uint8_t cmd, + uint8_t *args, unsigned int arglen, + uint8_t *data, uint8_t len) +{ + int buflen = len + 1 + arglen; + uint8_t sbuf[buflen]; + + memset((void *)sbuf, 0, buflen); + + int index = 0; + sbuf[index++] = cmd; + + if (args && arglen) + { + for (int i=0; ispi, sbuf, sbuf, buflen)) + { + mcp2515_cs_off(dev); + printf("%s: mraa_spi_transfer_buf() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + mcp2515_cs_off(dev); + + // now copy it into user buffer + for (int i=0; ispi, sbuf, sbuf, len + 1)) + { + mcp2515_cs_off(dev); + printf("%s: mraa_spi_transfer_buf() failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + mcp2515_cs_off(dev); + + return UPM_SUCCESS; +} + +upm_result_t mcp2515_write_reg(const mcp2515_context dev, uint8_t reg, + uint8_t value) +{ + assert(dev != NULL); + + uint8_t arg[2]; // reg addr, value + + arg[0] = reg; + arg[1] = value; + + return mcp2515_bus_write(dev, MCP2515_CMD_WRITE, arg, 2); +} + +upm_result_t mcp2515_write_regs(const mcp2515_context dev, uint8_t reg, + uint8_t *buffer, int len) +{ + assert(dev != NULL); + assert(buffer != NULL); + + int writeLen = len + 1; + uint8_t arg[1+len]; // reg addr, data... + + arg[0] = reg; + + for (int i=0; i MCP2515_MAX_PAYLOAD_DATA) + len = MCP2515_MAX_PAYLOAD_DATA; + if (len < 0) + len = 0; + + packet.DLC = (len & _MCP2515_TXBDLC_MASK) << _MCP2515_TXBDLC_SHIFT; + + if (rtr) + packet.DLC |= MCP2515_TXBDLC_RTR; + + // now the payload + for (int i=0; i> _MCP2515_RXSTATUS_RXMSG_SHIFT; + + return buffers; +} + +MCP2515_MSGTYPE_T mcp2515_rx_status_msg_type(const mcp2515_context dev) +{ + assert(dev != NULL); + + upm_result_t rv; + uint8_t rx_status_byte; + if ((rv = mcp2515_bus_read(dev, MCP2515_CMD_RX_STATUS, NULL, 0, + &rx_status_byte, 1))) + return rv; + + MCP2515_MSGTYPE_T msgtype = + (rx_status_byte & + (_MCP2515_RXSTATUS_MSGTYPE_MASK << _MCP2515_RXSTATUS_MSGTYPE_SHIFT)) + >> _MCP2515_RXSTATUS_MSGTYPE_SHIFT; + + return msgtype; +} + +MCP2515_FILTERMATCH_T mcp2515_rx_status_filtermatch(const mcp2515_context dev) +{ + assert(dev != NULL); + + upm_result_t rv; + uint8_t rx_status_byte; + if ((rv = mcp2515_bus_read(dev, MCP2515_CMD_RX_STATUS, NULL, 0, + &rx_status_byte, 1))) + return rv; + + MCP2515_FILTERMATCH_T fm = + (rx_status_byte & + (_MCP2515_RXSTATUS_FILTERMATCH_MASK + << _MCP2515_RXSTATUS_FILTERMATCH_SHIFT)) + >> _MCP2515_RXSTATUS_FILTERMATCH_SHIFT; + + return fm; +} + +upm_result_t mcp2515_get_rx_msg(const mcp2515_context dev, + MCP2515_RX_BUFFER_T bufnum, + MCP2515_MSG_T *msg) +{ + assert(dev != NULL); + assert(msg != NULL); + + uint8_t cmd = 0; + uint8_t rxbctrl_reg = 0; + switch (bufnum) + { + case MCP2515_RX_BUFFER0: + cmd = MCP2515_CMD_READ_RXBUF_RXB0SIDH; + rxbctrl_reg = MCP2515_REG_RXB0CTRL; + break; + + case MCP2515_RX_BUFFER1: + cmd = MCP2515_CMD_READ_RXBUF_RXB1SIDH; + rxbctrl_reg = MCP2515_REG_RXB1CTRL; + break; + + default: + return UPM_ERROR_INVALID_PARAMETER; + } + + // first see if we have a message waiting + MCP2515_RXMSG_T rxmsgs = mcp2515_rx_status_msgs(dev); + bool msgavail = false; + if (rxmsgs == MCP2515_RXMSG_BOTH) + msgavail = true; + else if (rxmsgs == MCP2515_RXMSG_RXB0 && bufnum == MCP2515_RX_BUFFER0) + msgavail = true; + else if (rxmsgs == MCP2515_RXMSG_RXB1 && bufnum == MCP2515_RX_BUFFER1) + msgavail = true; + + // nope + if (!msgavail) + return UPM_ERROR_NO_RESOURCES; + + // get the control reg + upm_result_t rv; + uint8_t rxbctrl; + if ((rv = mcp2515_read_reg(dev, rxbctrl_reg, &rxbctrl))) + return rv; + + // go ahead and grab the message and fill in the details + memset(msg, 0, sizeof(MCP2515_MSG_T)); + if ((rv = mcp2515_bus_read(dev, cmd, NULL, 0, + msg->pkt.data, MCP2515_MAX_PKT_DATA))) + { + printf("mcp2515_bus_read failed\n"); + return UPM_ERROR_OPERATION_FAILED; + } + + // if we are here, we got the packet, so decode and determine some + // things. + + // id & ext + MCP2515_ID_T did; + did.SIDH = msg->pkt.SIDH; + did.SIDL = msg->pkt.SIDL; + did.EID8 = msg->pkt.EID8; + did.EID0 = msg->pkt.EID0; + + msg->id = mcp2515_id_to_int(dev, &(msg->ext), &did); + + // rtr + if (!msg->ext) + { + // The RTR flag bit is the same for both the RXB0CTRL and + // RXB1CTRL registers, so it's safe to just compare against + // the first regardless of the buffer we are interested in. + if (rxbctrl & MCP2515_RXB0CTRL_RXRTR) + msg->rtr = true; + } + else + { + // ext message stores rtr separately + if (msg->pkt.DLC & MCP2515_RXBDLC_RTR) + msg->rtr = true; + } + + // filter num + if (bufnum == MCP2515_RX_BUFFER0) + { + if (rxbctrl & MCP2515_RXB0CTRL_FILHIT) + msg->filter_num = 1; + else + msg->filter_num = 0; + + } + else + { + msg->filter_num = + (int)((rxbctrl & + (_MCP2515_RXB1CTRL_FILHIT_MASK + << _MCP2515_RXB1CTRL_FILHIT_SHIFT)) + >> _MCP2515_RXB1CTRL_FILHIT_SHIFT); + } + + // now the payload length + msg->len = ((msg->pkt.DLC & (_MCP2515_RXBDLC_MASK << _MCP2515_RXBDLC_SHIFT)) + >> _MCP2515_RXBDLC_SHIFT); + + + return UPM_SUCCESS; +} + +void mcp2515_print_msg(const mcp2515_context dev, MCP2515_MSG_T *msg) +{ + assert(dev != NULL); + assert(msg != NULL); + + // print it out + printf("id %08x ext %d rtr %d filt %d len %d\n", + msg->id, msg->ext, msg->rtr, msg->filter_num, msg->len); + printf("\tpayload: "); + for (int i=0; ilen; i++) + printf("0x%02x ", msg->pkt.data[MCP2515_PKT_D0 + i]); + printf("\n"); +} + +upm_result_t mcp2515_abort_tx(const mcp2515_context dev, + MCP2515_TX_BUFFER_T bufnum) +{ + assert(dev != NULL); + + uint8_t reg; + switch (bufnum) + { + case MCP2515_TX_BUFFER0: + reg = MCP2515_REG_TXB0CTRL; + break; + + case MCP2515_TX_BUFFER1: + reg = MCP2515_REG_TXB1CTRL; + break; + + case MCP2515_TX_BUFFER2: + reg = MCP2515_REG_TXB2CTRL; + break; + + default: + return UPM_ERROR_INVALID_PARAMETER; + } + + // Clear the TXREQ bit. + return mcp2515_bit_modify(dev, reg, MCP2515_TXBCTRL_TXREQ, 0); +} + +upm_result_t mcp2515_install_isr(const mcp2515_context dev, int pin, + void (*isr)(void *), void *arg) +{ + assert(dev != NULL); + + mcp2515_uninstall_isr(dev); + + if ( !(dev->intr = mraa_gpio_init(pin)) ) + { + printf("%s: mraa_gpio_init failed.\n", __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + mraa_gpio_dir(dev->intr, MRAA_GPIO_IN); + + // install our interrupt handler + mraa_gpio_isr(dev->intr, MRAA_GPIO_EDGE_FALLING, + isr, arg); + + return UPM_SUCCESS; +} + +void mcp2515_uninstall_isr(const mcp2515_context dev) +{ + assert(dev != NULL); + + if (!dev->intr) + return; + + mraa_gpio_isr_exit(dev->intr); + mraa_gpio_close(dev->intr); + dev->intr = NULL; +} + +upm_result_t mcp2515_set_intr_enables(const mcp2515_context dev, + uint8_t enables) +{ + assert(dev != NULL); + + return mcp2515_write_reg(dev, MCP2515_REG_CANINTE, enables); +} + +upm_result_t mcp2515_get_intr_flags(const mcp2515_context dev, uint8_t *flags) +{ + assert(dev != NULL); + + return mcp2515_read_reg(dev, MCP2515_REG_CANINTF, flags); +} + +upm_result_t mcp2515_set_intr_flags(const mcp2515_context dev, uint8_t flags) +{ + assert(dev != NULL); + + return mcp2515_bit_modify(dev, MCP2515_REG_CANINTF, flags, 0xff); +} + +upm_result_t mcp2515_clear_intr_flags(const mcp2515_context dev, uint8_t flags) +{ + assert(dev != NULL); + + return mcp2515_bit_modify(dev, MCP2515_REG_CANINTF, flags, 0); +} + +upm_result_t mcp2515_get_error_flags(const mcp2515_context dev, uint8_t *flags) +{ + assert(dev != NULL); + + return mcp2515_read_reg(dev, MCP2515_REG_EFLG, flags); +} + +upm_result_t mcp2515_clear_error_flags(const mcp2515_context dev, + uint8_t flags) +{ + assert(dev != NULL); + + return mcp2515_bit_modify(dev, MCP2515_REG_EFLG, flags, 0); +} diff --git a/src/mcp2515/mcp2515.cxx b/src/mcp2515/mcp2515.cxx new file mode 100644 index 00000000..d797dcff --- /dev/null +++ b/src/mcp2515/mcp2515.cxx @@ -0,0 +1,253 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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 + +#include "mcp2515.hpp" + +using namespace upm; +using namespace std; + +MCP2515::MCP2515(int bus, int csPin) : + m_mcp2515(mcp2515_init(bus, csPin)) +{ + if (!m_mcp2515) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_init() failed"); +} + +MCP2515::~MCP2515() +{ + mcp2515_close(m_mcp2515); +} + +void MCP2515::reset() +{ + if (mcp2515_reset(m_mcp2515)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_reset() failed"); +} + +void MCP2515::setOpmode(MCP2515_OPMODE_T opmode) +{ + if (mcp2515_set_opmode(m_mcp2515, opmode)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_set_opmode() failed"); +} + +void MCP2515::setSpeed(MCP2515_SPEED_T speed) +{ + if (mcp2515_set_speed(m_mcp2515, speed)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_set_speed() failed"); +} + +void MCP2515::loadTXBuffer(MCP2515_TX_BUFFER_T bufnum, int id, bool ext, + bool rtr, std::string payload) +{ + if (mcp2515_load_tx_buffer(m_mcp2515, bufnum, id, ext, rtr, + (uint8_t *)payload.data(), payload.size())) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_load_tx_buffer() failed"); + +} + +void MCP2515::transmitBuffer(MCP2515_TX_BUFFER_T bufnum, bool wait) +{ + if (mcp2515_transmit_buffer(m_mcp2515, bufnum, wait)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_transmit_buffer() failed"); +} + +bool MCP2515::isTXBufferFree(MCP2515_TX_BUFFER_T bufnum) +{ + return mcp2515_tx_buffer_is_free(m_mcp2515, bufnum); +} + +MCP2515_TX_BUFFER_T MCP2515::findFreeTXBuffer() +{ + return mcp2515_find_free_tx_buffer(m_mcp2515); +} + +void MCP2515::setTXBufferPriority(MCP2515_TX_BUFFER_T bufnum, + MCP2515_TXP_T priority) +{ + if (mcp2515_set_tx_buffer_priority(m_mcp2515, bufnum, priority)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_set_tx_buffer_priority() failed"); +} + +void MCP2515::abortTX(MCP2515_TX_BUFFER_T bufnum) +{ + if (mcp2515_abort_tx(m_mcp2515, bufnum)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_abort_tx() failed"); +} + +void MCP2515::setRXBufferMode(MCP2515_RX_BUFFER_T bufnum, MCP2515_RXMODE_T rxm) +{ + if (mcp2515_set_rx_buffer_mode(m_mcp2515, bufnum, rxm)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_set_rx_buffer_mode() failed"); +} + +MCP2515_RXMSG_T MCP2515::rxStatusMsgs() +{ + return mcp2515_rx_status_msgs(m_mcp2515); +} + +MCP2515_MSGTYPE_T MCP2515::rxStatusMsgType() +{ + return mcp2515_rx_status_msg_type(m_mcp2515); +} + +MCP2515_FILTERMATCH_T MCP2515::rxStatusFiltermatch() +{ + return mcp2515_rx_status_filtermatch(m_mcp2515); +} + +upm_result_t MCP2515::getRXMsg(MCP2515_RX_BUFFER_T bufnum) +{ + return mcp2515_get_rx_msg(m_mcp2515, bufnum, &m_message); +} + +void MCP2515::printMsg() +{ + mcp2515_print_msg(m_mcp2515, &m_message); +} + +void MCP2515::installISR(int pin, void (*isr)(void *), void *arg) +{ + if (mcp2515_install_isr(m_mcp2515, pin, isr, arg)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_install_isr() failed"); +} + +void MCP2515::uninstallISR() +{ + mcp2515_uninstall_isr(m_mcp2515); +} + +void MCP2515::setIntrEnables(uint8_t enables) +{ + if (mcp2515_set_intr_enables(m_mcp2515, enables)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_set_intr_enables() failed"); +} + +uint8_t MCP2515::getIntrFlags() +{ + uint8_t flags = 0; + if (mcp2515_get_intr_flags(m_mcp2515, &flags)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_get_intr_flags() failed"); + return flags; +} + +void MCP2515::setIntrFlags(uint8_t flags) +{ + if (mcp2515_set_intr_flags(m_mcp2515, flags)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_set_intr_flags() failed"); +} + +void MCP2515::clearIntrFlags(uint8_t flags) +{ + if (mcp2515_clear_intr_flags(m_mcp2515, flags)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_clear_intr_flags() failed"); +} + +uint8_t MCP2515::getErrorFlags() +{ + uint8_t flags = 0; + if (mcp2515_get_error_flags(m_mcp2515, &flags)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_get_error_flags() failed"); + return flags; +} + +void MCP2515::clearErrorFlags(uint8_t flags) +{ + if (mcp2515_clear_error_flags(m_mcp2515, flags)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_clear_error_flags() failed"); +} + +void MCP2515::setFilter(MCP2515_RX_FILTER_T filter, bool ext, int id) +{ + if (mcp2515_set_filter(m_mcp2515, filter, ext, id)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_set_filter() failed"); +} + +void MCP2515::setMask(MCP2515_RX_MASK_T mask, bool ext, int id) +{ + if (mcp2515_set_mask(m_mcp2515, mask, ext, id)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_set_mask() failed"); +} + +string MCP2515::busRead(uint8_t cmd, std::string args, int datalen) +{ + uint8_t data[datalen]; + + if (mcp2515_bus_read(m_mcp2515, cmd, (uint8_t *)args.data(), args.size(), + data, datalen)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_bus_read() failed"); + return string((char *)data, datalen); +} + +void MCP2515::busWrite(uint8_t cmd, std::string data) +{ + if (mcp2515_bus_write(m_mcp2515, cmd, (uint8_t *)data.data(), data.size())) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_bus_write() failed"); +} + +void MCP2515::writeReg(uint8_t reg, uint8_t value) +{ + if (mcp2515_write_reg(m_mcp2515, reg, value)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_write_reg() failed"); +} + +void MCP2515::writeRegs(uint8_t reg, std::string buffer) +{ + if (mcp2515_write_regs(m_mcp2515, reg, (uint8_t *)buffer.data(), + buffer.size())) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_write_regs() failed"); +} + +void MCP2515::bitModify(uint8_t addr, uint8_t mask, uint8_t value) +{ + if (mcp2515_bit_modify(m_mcp2515, addr, mask, value)) + throw std::runtime_error(string(__FUNCTION__) + + ": mcp2515_bit_modify() failed"); +} diff --git a/src/mcp2515/mcp2515.h b/src/mcp2515/mcp2515.h new file mode 100644 index 00000000..889c78fb --- /dev/null +++ b/src/mcp2515/mcp2515.h @@ -0,0 +1,525 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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 + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @file mcp2515 + * @library mcp2515 + * @brief C API for the MCP2515 CAN bus controller + * + * @include mcp2515.c + * @include mcp2515_regs.c + */ + + /** + * Device context + */ + typedef struct _mcp2515_context { + mraa_spi_context spi; + + // CS pin, if we are using one + mraa_gpio_context gpio; + + // interrupt, if enabled + mraa_gpio_context intr; + } *mcp2515_context; + + /** + * MCP2515 initializer + * + * @param bus spi bus to use + * @param cs_pin The GPIO pin to use for Chip Select (CS). Pass + * pass -1 if your CS is handled automatically by your SPI + * implementation (Edison). + * @return an initialized device context on success, NULL on error. + */ + mcp2515_context mcp2515_init(int bus, int cs_pin); + + /** + * MCP2515 close + * + * @param dev Device context. + */ + void mcp2515_close(mcp2515_context dev); + + /** + * Reset the device. + * + * @param dev Device context. + * @return UPM result. + */ + upm_result_t mcp2515_reset(const mcp2515_context dev); + + /** + * Set the operating mode of the device. After initialization + * (mcp2515_init()), the device mode will be set to NORMAL. Note + * that some operations require the device to be placed into CONFIG + * mode. This function will wait until the selected mode has been + * entered. + * + * @param dev Device context. + * @param opmode One of the MCP2515_OPMODE_T values. + * @return UPM result. + */ + upm_result_t mcp2515_set_opmode(const mcp2515_context dev, + MCP2515_OPMODE_T opmode); + + /** + * Set the baud rate of the CAN bus. All devices on a given CAN + * bus must be operating at the correct speed. The device must be + * switched into CONFIG mode bofore this function will have any + * effect. On initialization (mcp2515_init()), the default CAN + * bus speed will be set to 50Kbps. + * + * @param dev Device context. + * @param speed One of the MCP2515_SPEED_T values. + * @return UPM result. + */ + upm_result_t mcp2515_set_speed(const mcp2515_context dev, + MCP2515_SPEED_T speed); + + /** + * Load a transmit buffer with the id, payload, and other + * information. This function does not actually transmit the + * buffer. There are 3 TX buffers available. The buffer must be + * free (ie: not awaiting transmit) before it can be loaded. Once + * a TX buffer has been successfully loaded, it can be transmitted + * with the mcp2515_transmit_buffer() function. + * + * @param dev Device context. + * @param bufnum The buffer to load. One of the + * MCP2515_TX_BUFFER_T values. + * @param id The integer representation of the CAN bus ID. + * @param ext True if the ID is an extended identifier, false otherwise. + * @param rtr True if this is a Remote Transfer Request, false otherwise. + * @param payload A pointer to an array of bytes that make up the + * payload to send. + * @param len The length of the payload. The length is limited to + * 8. + * @return UPM result. + */ + upm_result_t mcp2515_load_tx_buffer(const mcp2515_context dev, + MCP2515_TX_BUFFER_T bufnum, + int id, bool ext, bool rtr, + uint8_t *payload, int len); + + /** + * Transmit a buffer already loaded by mcp2515_load_tx_buffer(). + * + * @param dev Device context. + * @param bufnum The buffer to transmit. One of the + * MCP2515_TX_BUFFER_T values. + * @param wait True if the function should wait until transmission + * is complete before returning, false otherwise. + * @return UPM result. + */ + upm_result_t mcp2515_transmit_buffer(const mcp2515_context dev, + MCP2515_TX_BUFFER_T bufnum, + bool wait); + + /** + * Determine whether a TX buffer is available for use or not. A TX + * buffer is unavailable if a transmit request is pending on it, + * but transmission has not yet completed. + * + * @param dev Device context. + * @param bufnum The buffer to check. One of the + * MCP2515_TX_BUFFER_T values. + * @return True if the buffer is availabe, false otherwise. + */ + bool mcp2515_tx_buffer_is_free(const mcp2515_context dev, + MCP2515_TX_BUFFER_T bufnum); + + /** + * Find a free TX buffer and return it. + * + * @param dev Device context. + * @return One of the MCP2515_TX_BUFFER_T values. If no buffers + * are available, MCP2515_TX_NO_BUFFERS will be returned. + */ + MCP2515_TX_BUFFER_T mcp2515_find_free_tx_buffer(const mcp2515_context dev); + + /** + * Set the transmit priority of a TX buffer. Higher priority + * buffers are always transmitted before lower priority buffers. + * This function can be called on a buffer at any time prior to + * actual transmission. + * + * @param dev Device context. + * @param bufnum The buffer to set priority for. One of the + * MCP2515_TX_BUFFER_T values. + * @param priority The priority to set for the buffer. One of the + * MCP2515_TXP_T values. + * @return UPM result. + */ + upm_result_t mcp2515_set_tx_buffer_priority(const mcp2515_context dev, + MCP2515_TX_BUFFER_T bufnum, + MCP2515_TXP_T priority); + + /** + * Abort a transmission that has been queued, but not yet + * completed. This will also free up the TX buffer for future + * use. Note, if you abort a transmission, but transmission has + * already started, this call will have no effect, and the buffer + * will complete transmission. + * + * @param dev Device context. + * @param bufnum The buffer to abort. One of the + * MCP2515_TX_BUFFER_T values. + * @return UPM result. + */ + upm_result_t mcp2515_abort_tx(const mcp2515_context dev, + MCP2515_TX_BUFFER_T bufnum); + + /** + * Set the mode for an RX buffer. The mode specifies, at a high + * level, what packets should be captured from the bus and placed + * into an RX buffer. See the datasheet for details, but the + * default, MCP2515_RXMODE_ANY_FILTER, should be sufficient in + * most cases. It is also possible to use this to restrict the + * types of CAN ids accepted (extended only, standard only) as + * well as a debug ANY_NOFILTER mode. + * + * @param dev Device context. + * @param bufnum The buffer to set the mode for. One of the + * MCP2515_RX_BUFFER_T values. + * @param rxm The mode to set. One of the MCP2515_RXMODE_T values. + * @return UPM result. + */ + upm_result_t mcp2515_set_rx_buffer_mode(const mcp2515_context dev, + MCP2515_RX_BUFFER_T bufnum, + MCP2515_RXMODE_T rxm); + + /** + * Return a bitmask indicating which of the 2 RX buffers have + * packets waiting in them. This can be 0 (no packets), 1(RXB0), + * 2(RXB1), or 3 (RXB0 and RXB1). This information is retrieved + * using the MCP2515_CMD_RX_STATUS command. + * + * @param dev Device context. + * @return A bitmask indicating which RX buffers (if any) have + * packets in them. One of the MCP2515_RXMSG_T values. + */ + MCP2515_RXMSG_T mcp2515_rx_status_msgs(const mcp2515_context dev); + + /** + * Return the message type present in one of the RX buffers. RXB0 + * has the highest priority, so if both RX buffers are full, this + * function will only return data for the packet in RXB0. This + * information is retrieved using the MCP2515_CMD_RX_STATUS + * command. + * + * @param dev Device context. + * @return One of the MCP2515_MSGTYPE_T values. + */ + MCP2515_MSGTYPE_T mcp2515_rx_status_msg_type(const mcp2515_context dev); + + /** + * Return the filter that matched an RX buffer. RXB0 has the + * highest priority, so if both RX buffers are full, this function + * will only return data for the packet in RXB0. This information + * is retrieved using the MCP2515_CMD_RX_STATUS command. + * + * @param dev Device context. + * @return One of the MCP2515_FILTERMATCH_T values. + */ + MCP2515_FILTERMATCH_T mcp2515_rx_status_filtermatch(const mcp2515_context dev); + + /** + * This function retrieves a message from the specified RX buffer. + * The message (MCP2515_MSG_T) contains all of the data in the + * packet, including id, rtr, ext, payload and payload length. In + * addition, after retrieving the message, the RX buffer is freed + * to receive further data from the CAN bus. + * + * @param dev Device context. + * @param bufnum The buffer to retrieve. One of the + * MCP2515_RX_BUFFER_T values. + * @param msg A pointer to a MCP2515_MSG_T, which will be filled + * with the decoded contents of the RX buffer. + * @return UPM result. + */ + upm_result_t mcp2515_get_rx_msg(const mcp2515_context dev, + MCP2515_RX_BUFFER_T bufnum, + MCP2515_MSG_T *msg); + + /** + * This is a utility function that accepts a MCP2515_MSG_T and + * prints out it's decoded contents. This is of primary + * importance for debugging, and to simplify the examples + * somewhat. + * + * The output will look similar to: + * + * id 00000000 ext 0 rtr 0 filt 0 len 8 + * payload: 0xc8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 + * + * @param dev Device context. + * @param msg A pointer to a MCP2515_MSG_T containing the data to + * be printed out. + */ + void mcp2515_print_msg(const mcp2515_context dev, MCP2515_MSG_T *msg); + + /** + * Installs an interrupt service routine (ISR) to be called when + * an interrupt occurs. + * + * @param dev Device context. + * @param pin GPIO pin to use as the interrupt pin. + * @param fptr Pointer to a function to be called on interrupt. + * @param arg Pointer to an object to be supplied as an + * argument to the ISR. + * @return UPM result. + */ + upm_result_t mcp2515_install_isr(const mcp2515_context dev, int pin, + void (*isr)(void *), void *arg); + + /** + * Uninstalls the previously installed ISR + * + * @param dev Device context. + */ + void mcp2515_uninstall_isr(const mcp2515_context dev); + + /** + * Set the interrupt enables register. + * + * @param dev Device context. + * @param enables A bitmask of interrupts to enable from + * MCP2515_CANINT_BITS_T. + * @return UPM result. + */ + upm_result_t mcp2515_set_intr_enables(const mcp2515_context dev, + uint8_t enables); + + /** + * Retrieve the interrupt flags register. + * + * @param dev Device context. + * @param flags A pointer to a bitmask that will be filled with + * values from MCP2515_CANINT_BITS_T, indicating which interrupt + * flags are set. + * @return UPM result. + */ + upm_result_t mcp2515_get_intr_flags(const mcp2515_context dev, + uint8_t *flags); + + /** + * This function allows you to set specific interrupt flags. If + * the corresponding interrupt enable is set, an interrupt will be + * generated. + * + * @param dev Device context. + * @param flags A bitmask of interrupt flags to set, from + * MCP2515_CANINT_BITS_T values. + * @return UPM result. + */ + upm_result_t mcp2515_set_intr_flags(const mcp2515_context dev, + uint8_t flags); + + /** + * This function allows you to clear specific interrupt flags. + * See the datasheet. Some flags cannot be cleared until the + * underlying cause has been corrected. + * + * @param dev Device context. + * @param flags A bitmask of interrupt flags to clear, from + * MCP2515_CANINT_BITS_T values. + * @return UPM result. + */ + upm_result_t mcp2515_clear_intr_flags(const mcp2515_context dev, + uint8_t flags); + + /** + * Retrieve the error flags register + * + * @param dev Device context. + * @param flags A pointer to a uint8_t that will hold the flags + * with values from MCP2515_EFLG_BITS_T. + * @return UPM result. + */ + upm_result_t mcp2515_get_error_flags(const mcp2515_context dev, + uint8_t *flags); + + /** + * Clear error flags. Note, some flags cannot be cleared + * until the underlying issues is resolved. + * + * @param dev Device context. + * @param flags A bitmask of values from MCP2515_EFLG_BITS_T + * specifying the flags to clear. + * @return UPM result. + */ + upm_result_t mcp2515_clear_error_flags(const mcp2515_context dev, + uint8_t flags); + + /** + * This function allows you to set one of the 6 RX filters + * available. Filters 0 and 1 are for RXB0 only, while filters + * 2-5 are for RXB1. See the datasheet for details on how these + * filters (along with the masks) are used to select candidate CAN + * bus data for retrieval from the CAN bus. + * + * These can only be set when the device is in CONFIG mode. + * + * @param dev Device context. + * @param filter One of the 6 MCP2515_RX_FILTER_T values. + * @param ext True if the id is extended, false for standard. + * @param id Integer representation of a CAN bus ID. + * @return UPM result. + */ + upm_result_t mcp2515_set_filter(const mcp2515_context dev, + MCP2515_RX_FILTER_T filter, bool ext, + int id); + + /** + * This function allows you to set one of the 2 RX masks. Mask 0 + * is for RXB0, mask 1 is for RXB1. The masks specify which bits + * in the filters are used for matching CAN bus data. See the + * datasheet for details on how these masks (along with the + * filters) are used to select candidate CAN bus data for retrieval + * from the CAN bus. + * + * These can only be set when the device is in CONFIG mode. + * + * @param dev Device context. + * @param mask One of the 2 MCP2515_RX_MASK_T values. + * @param ext True if the id is extended, false for standard. + * @param id Integer representation of a CAN bus ID. + * @return UPM result. + */ + upm_result_t mcp2515_set_mask(const mcp2515_context dev, + MCP2515_RX_MASK_T mask, bool ext, int id); + + /** + * Perform a bus read. This function is exposed here for those + * users wishing to perform their own low level accesses. This is + * a low level function, and should not be used unless you know + * what you are doing. + * + * @param dev Device context. + * @param cmd The command to send. + * @param args An array of arguments, or NULL. + * @param arglen The number of args, or 0. + * @param data A pointer to a buffer in which data will be read into. + * @param len The number of bytes to read. + * @return UPM result. + */ + upm_result_t mcp2515_bus_read(const mcp2515_context dev, uint8_t cmd, + uint8_t *args, unsigned int arglen, + uint8_t *data, uint8_t len); + + /** + * Perform a bus write. This function is exposed here for those + * users wishing to perform their own low level accesses. This is + * a low level function, and should not be used unless you know + * what you are doing. + * + * @param dev Device context + * @param cmd The command to send. + * @param data A pointer to a buffer containing data to write. + * @param len The number of bytes to write. + * @return UPM Status + */ + upm_result_t mcp2515_bus_write(const mcp2515_context dev, uint8_t cmd, + uint8_t *data, uint8_t len); + + /** + * Write to a specific register. This function is exposed here + * for those users wishing to perform their own low level + * accesses. This is a low level function, and should not be used + * unless you know what you are doing. + * + * @param dev Device context + * @param reg The register to write to. + * @param value The byte to write. + * @return UPM Status + */ + upm_result_t mcp2515_write_reg(const mcp2515_context dev, uint8_t reg, + uint8_t value); + + /** + * Write to multiple consecutive registers. This function is + * exposed here for those users wishing to perform their own low + * level accesses. This is a low level function, and should not + * be used unless you know what you are doing. + * + * @param dev Device context + * @param reg The register to start writing to. + * @param buffer A pointer to an array of bytes to write. + * @param len The number of bytes to write. + * @return UPM Status + */ + upm_result_t mcp2515_write_regs(const mcp2515_context dev, uint8_t reg, + uint8_t *buffer, int len); + + /** + * Read a register. This function is exposed here for those users + * wishing to perform their own low level accesses. This is a low + * level function, and should not be used unless you know what you + * are doing. + * + * @param dev Device context + * @param reg The register to read. + * @param buffer A pointer to a a byte where the value will be placed. + * @return UPM Status + */ + upm_result_t mcp2515_read_reg(const mcp2515_context dev, uint8_t reg, + uint8_t *value); + + /** + * Perform a bit modify operation on a register. Only certain + * registers support this method of access - check the datasheet. + * This function is exposed here for those users wishing to + * perform their own low level accesses. This is a low level + * function, and should not be used unless you know what you are + * doing. + * + * @param dev Device context + * @param addr The address of the register to access. + * @param mask A bitmask used to mask off value bits. + * @param value The value to write (bits masked by mask). + * @return UPM Status + */ + upm_result_t mcp2515_bit_modify(const mcp2515_context dev, uint8_t addr, + uint8_t mask, uint8_t value); + +#ifdef __cplusplus +} +#endif diff --git a/src/mcp2515/mcp2515.hpp b/src/mcp2515/mcp2515.hpp new file mode 100644 index 00000000..49117e2d --- /dev/null +++ b/src/mcp2515/mcp2515.hpp @@ -0,0 +1,522 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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 "mcp2515.h" + +namespace upm { + + /** + * @brief MCP2515 Can bus controller + * @defgroup mcp2515 libupm-mcp2515 + * @ingroup spi gpio + */ + + /** + * @library mcp2515 + * @sensor mcp2515 + * @comname MCP2515 CAN bus controller + * @man seeed + * @con spi gpio + * @web https://www.seeedstudio.com/CANBUS-Shield-p-2256.html + * + * @brief API for the MCP2515 CAN bus controller + * + * The MCP2515 is a stand-alone CAN controller developed to + * simplify applications that require interfacing with a CAN bus. + * + * This driver was developed using the Grove CAN bus shield + * version 1.2. + * + * An example using the loopback mode. + * @snippet mcp2515.cxx Interesting + * A simple transmit and receive example. + * @snippet mcp2515-txrx.cxx Interesting + */ + class MCP2515 { + public: + + /** + * MCP2515 constructor. + * + * @param bus spi bus to use + * @param cs_pin The GPIO pin to use for Chip Select (CS). Pass + * pass -1 if your CS is handled automatically by your SPI + * implementation (Edison). + */ + MCP2515(int bus, int csPin); + + /** + * MCP2515 Destructor + */ + ~MCP2515(); + + /** + * Reset the device. + * + */ + void reset(); + + /** + * Set the operating mode of the device. After initialization, + * the device mode will be set to NORMAL. Note that some + * operations require the device to be placed into CONFIG mode. + * This function will wait until the selected mode has been + * entered. + * + * @param opmode One of the MCP2515_OPMODE_T values. + */ + void setOpmode(MCP2515_OPMODE_T opmode); + + /** + * Set the baud rate of the CAN bus. All devices on a given + * CAN bus must be operating at the correct speed. The device + * must be switched into CONFIG mode bofore this function will + * have any effect. On initialization, the default CAN bus + * speed will be set to 50Kbps. + * + * @param speed One of the MCP2515_SPEED_T values. + */ + void setSpeed(MCP2515_SPEED_T speed); + + /** + * Load a transmit buffer with the id, payload, and other + * information. This function does not actually transmit the + * buffer. There are 3 TX buffers available. The buffer must be + * free (ie: not awaiting transmit) before it can be loaded. Once + * a TX buffer has been successfully loaded, it can be transmitted + * with the TransmitBuffer() method. + * + * @param bufnum The buffer to load. One of the + * MCP2515_TX_BUFFER_T values. + * @param id The integer representation of the CAN bus ID. + * @param ext True if the ID is an extended identifier, false otherwise. + * @param rtr True if this is a Remote Transfer Request, false + * otherwise. + * @param payload A string containing the payload bytes. + * Maximum length is 8. + */ + void loadTXBuffer(MCP2515_TX_BUFFER_T bufnum, + int id, bool ext, bool rtr, + std::string payload); + + /** + * Transmit a buffer already loaded by loadTXBuffer(). + * + * @param bufnum The buffer to transmit. One of the + * MCP2515_TX_BUFFER_T values. + * @param wait True if the function should wait until transmission + * is complete before returning, false otherwise. + */ + void transmitBuffer(MCP2515_TX_BUFFER_T bufnum, bool wait); + + /** + * Determine whether a TX buffer is available for use or not. A TX + * buffer is unavailable if a transmit request is pending on it, + * but transmission has not yet completed. + * + * @param bufnum The buffer to check. One of the + * MCP2515_TX_BUFFER_T values. + * @return True if the buffer is availabe, false otherwise. + */ + bool isTXBufferFree(MCP2515_TX_BUFFER_T bufnum); + + /** + * Find a free TX buffer and return it. + * + * @return One of the MCP2515_TX_BUFFER_T values. If no buffers + * are available, MCP2515_TX_NO_BUFFERS will be returned. + */ + MCP2515_TX_BUFFER_T findFreeTXBuffer(); + + /** + * Set the transmit priority of a TX buffer. Higher priority + * buffers are always transmitted before lower priority buffers. + * This function can be called on a buffer at any time prior to + * actual transmission. + * + * @param bufnum The buffer to set priority for. One of the + * MCP2515_TX_BUFFER_T values. + * @param priority The priority to set for the buffer. One of the + * MCP2515_TXP_T values. + */ + void setTXBufferPriority(MCP2515_TX_BUFFER_T bufnum, + MCP2515_TXP_T priority); + + /** + * Abort a transmission that has been queued, but not yet + * completed. This will also free up the TX buffer for future + * use. Note, if you abort a transmission, but transmission has + * already started, this call will have no effect, and the buffer + * will complete transmission. + * + * @param bufnum The buffer to abort. One of the + * MCP2515_TX_BUFFER_T values. + */ + void abortTX(MCP2515_TX_BUFFER_T bufnum); + + /** + * Set the mode for an RX buffer. The mode specifies, at a high + * level, what packets should be captured from the bus and placed + * into an RX buffer. See the datasheet for details, but the + * default, MCP2515_RXMODE_ANY_FILTER, should be sufficient in + * most cases. It is also possible to use this to restrict the + * types of CAN ids accepted (extended only, standard only) as + * well as a debug ANY_NOFILTER mode. + * + * @param bufnum The buffer to set the mode for. One of the + * MCP2515_RX_BUFFER_T values. + * @param rxm The mode to set. One of the MCP2515_RXMODE_T values. + */ + void setRXBufferMode(MCP2515_RX_BUFFER_T bufnum, + MCP2515_RXMODE_T rxm); + + /** + * Return a bitmask indicating which of the 2 RX buffers have + * packets waiting in them. This can be 0 (no packets), 1(RXB0), + * 2(RXB1), or 3 (RXB0 and RXB1). This information is retrieved + * using the MCP2515_CMD_RX_STATUS command. + * + * @return A bitmask indicating which RX buffers (if any) have + * packets in them. One of the MCP2515_RXMSG_T values. + */ + MCP2515_RXMSG_T rxStatusMsgs(); + + /** + * Return the message type present in one of the RX buffers. RXB0 + * has the highest priority, so if both RX buffers are full, this + * function will only return data for the packet in RXB0. This + * information is retrieved using the MCP2515_CMD_RX_STATUS + * command. + * + * @return One of the MCP2515_MSGTYPE_T values. + */ + MCP2515_MSGTYPE_T rxStatusMsgType(); + + /** + * Return the filter that matched an RX buffer. RXB0 has the + * highest priority, so if both RX buffers are full, this function + * will only return data for the packet in RXB0. This information + * is retrieved using the MCP2515_CMD_RX_STATUS command. + * + * @return One of the MCP2515_FILTERMATCH_T values. + */ + MCP2515_FILTERMATCH_T rxStatusFiltermatch(); + + /** + * This function retrieves a message from the specified RX + * buffer. The message (MCP2515_MSG_T) contains all of the + * data in the packet, including id, rtr, ext, payload and + * payload length. In addition, after retrieving the message, + * the RX buffer is freed to receive further data from the CAN + * bus. The message is stored within the class. + * + * @param bufnum The buffer to retrieve. One of the + * MCP2515_RX_BUFFER_T values. + */ + upm_result_t getRXMsg(MCP2515_RX_BUFFER_T bufnum); + + /** + * This is a utility function prints the current (last + * received) messages decoded contents. This is of + * primary importance for debugging, and to simplify the + * examples somewhat. + * + * The output will look similar to: + * + * id 00000000 ext 0 rtr 0 filt 0 len 8 + * payload: 0xc8 0x01 0x02 0x03 0x04 0x05 0x06 0x07 + * + */ + void printMsg(); + + + /** + * This method returns the id of a received message. It will + * only be valid after a successful completion of rxGetMsg(). + * + * @return ID of the last received message. + */ + int msgGetID() + { + return m_message.id; + } + + /** + * This method returns the RTR flag of a received message. It will + * only be valid after a successful completion of rxGetMsg(). + * + * @return True if the message has the RTR flag set, false otherwise. + */ + bool msgGetRTR() + { + return m_message.rtr; + } + + /** + * This method returns the EXT (extended ID) flag of a + * received message. It will only be valid after a successful + * completion of rxGetMsg(). + * + * @return True if the message has an extended ID, false otherwise. + */ + bool msgGetEXT() + { + return m_message.ext; + } + + /** + * This method returns the filter number that caused the + * message to be stored in the RX buffer. It will only be + * valid after a successful completion of rxGetMsg(). + * + * @return The filter number that was matched. + */ + int msgGetFilterNum() + { + return m_message.filter_num; + } + + /** + * This method returns the length of the payload of the RX + * buffer. It will only be valid after a successful + * completion of rxGetMsg(). + * + * @return Length of the payload in bytes, max 8. + */ + int msgGetPayloadLen() + { + return m_message.len; + } + + /** + * This method returns the contents of the payload in the last + * received message. It will only be valid after a successful + * completion of rxGetMsg(). + * + * @return String containing the payload. + */ + std::string msgGetPayload() + { + return std::string((char *)m_message.pkt.data, m_message.len); + } + +#if defined(SWIGJAVA) || defined(JAVACALLBACK) + void installISR(int pin, jobject runnable) + { + installISR(pin, mraa_java_isr_callback, runnable); + } +#else + /** + * Installs an interrupt service routine (ISR) to be called when + * an interrupt occurs. + * + * @param pin GPIO pin to use as the interrupt pin. + * @param fptr Pointer to a function to be called on interrupt. + * @param arg Pointer to an object to be supplied as an + * argument to the ISR. + */ + void installISR(int pin, void (*isr)(void *), void *arg); +#endif + + /** + * Uninstalls the previously installed ISR + * + * @param dev Device context. + */ + void uninstallISR(); + + /** + * Set the interrupt enables register. + * + * @param enables A bitmask of interrupts to enable from + * MCP2515_CANINT_BITS_T. + */ + void setIntrEnables(uint8_t enables); + + /** + * Retrieve the interrupt flags register. + * + * @return A bitmask that will be filled with values from + * MCP2515_CANINT_BITS_T, indicating which interrupt flags are + * set. + */ + uint8_t getIntrFlags(); + + /** + * This function allows you to set specific interrupt flags. If + * the corresponding interrupt enable is set, an interrupt will be + * generated. + * + * @param flags A bitmask of interrupt flags to set, from + * MCP2515_CANINT_BITS_T values. + */ + void setIntrFlags(uint8_t flags); + + /** + * This function allows you to clear specific interrupt flags. + * See the datasheet. Some flags cannot be cleared until the + * underlying cause has been corrected. + * + * @param flags A bitmask of interrupt flags to clear, from + * MCP2515_CANINT_BITS_T values. + */ + void clearIntrFlags(uint8_t flags); + + /** + * Retrieve the error flags register + * + * @return A bitmask that will be filled with values from + * MCP2515_EFLG_BITS_T, indicating which error flags are set. + */ + uint8_t getErrorFlags(); + + /** + * Clear error flags. Note, some flags cannot be cleared + * until the underlying issues is resolved. + * + * @return A bitmask of values from MCP2515_EFLG_BITS_T, + * indicating which error flags to clear. + */ + void clearErrorFlags(uint8_t flags); + + /** + * This function allows you to set one of the 6 RX filters + * available. Filters 0 and 1 are for RXB0 only, while filters + * 2-5 are for RXB1. See the datasheet for details on how these + * filters (along with the masks) are used to select candidate CAN + * bus data for retrieval from the CAN bus. + * + * These can only be set when the device is in CONFIG mode. + * + * @param filter One of the 6 MCP2515_RX_FILTER_T values. + * @param ext True if the id is extended, false for standard. + * @param id Integer representation of a CAN bus ID. + */ + void setFilter(MCP2515_RX_FILTER_T filter, bool ext, int id); + + /** + * This function allows you to set one of the 2 RX masks. Mask 0 + * is for RXB0, mask 1 is for RXB1. The masks specify which bits + * in the filters are used for matching CAN bus data. See the + * datasheet for details on how these masks (along with the + * filters) are used to select candidate CAN bus data for retrieval + * from the CAN bus. + * + * These can only be set when the device is in CONFIG mode. + * + * @param mask One of the 2 MCP2515_RX_MASK_T values. + * @param ext True if the id is extended, false for standard. + * @param id Integer representation of a CAN bus ID. + */ + void setMask(MCP2515_RX_MASK_T mask, bool ext, int id); + + + protected: + mcp2515_context m_mcp2515; + + // We operate only on this message (for received messages) to + // simplify SWIG accesses. + MCP2515_MSG_T m_message; + + /** + * Perform a bus read. This function is exposed here for those + * users wishing to perform their own low level accesses. This is + * a low level function, and should not be used unless you know + * what you are doing. + * + * @param cmd The command to send. + * @param args String containing arguments, or empty for no arguments. + * @param datalen The length of the data to read. + * @return A string containing the data. + */ + std::string busRead(uint8_t cmd, std::string args, int datalen); + + /** + * Perform a bus write. This function is exposed here for those + * users wishing to perform their own low level accesses. This is + * a low level function, and should not be used unless you know + * what you are doing. + * + * @param cmd The command to send. + * @param data A string containing the data to write. + * @param len The number of bytes to write. + */ + void busWrite(uint8_t cmd, std::string data); + + /** + * Write to a specific register. This function is exposed here + * for those users wishing to perform their own low level + * accesses. This is a low level function, and should not be used + * unless you know what you are doing. + * + * @param reg The register to write to. + * @param value The byte to write. + */ + void writeReg(uint8_t reg, uint8_t value); + + /** + * Write to multiple consecutive registers. This function is + * exposed here for those users wishing to perform their own low + * level accesses. This is a low level function, and should not + * be used unless you know what you are doing. + * + * @param reg The register to start writing to. + * @param buffer A string containing data to write. + */ + void writeRegs(uint8_t reg, std::string buffer); + + /** + * Read a register. This function is exposed here for those users + * wishing to perform their own low level accesses. This is a low + * level function, and should not be used unless you know what you + * are doing. + * + * @param reg The register to read. + * @return The register contents. + */ + uint8_t readReg(uint8_t reg); + + /** + * Perform a bit modify operation on a register. Only certain + * registers support this method of access - check the datasheet. + * This function is exposed here for those users wishing to + * perform their own low level accesses. This is a low level + * function, and should not be used unless you know what you are + * doing. + * + * @param addr The address of the register to access. + * @param mask A bitmask used to mask off value bits. + * @param value The value to write (bits masked by mask). + */ + void bitModify(uint8_t addr, uint8_t mask, uint8_t value); + + private: +#if defined(SWIGJAVA) || defined(JAVACALLBACK) + void installISR(int pin, void (*isr)(void *), void *arg); +#endif + }; +} diff --git a/src/mcp2515/mcp2515_regs.h b/src/mcp2515/mcp2515_regs.h new file mode 100644 index 00000000..b08beb3d --- /dev/null +++ b/src/mcp2515/mcp2515_regs.h @@ -0,0 +1,641 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 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 + +#ifdef __cplusplus +extern "C" { +#endif + +// maximum number of bytes we can send/receive +#define MCP2515_MAX_PAYLOAD_DATA (8) + +// This includes SIDH, SIDL, EID8, EID0, DLC, and 8 payload bytes. +// This represents the non-control components of the RX and TX +// buffers. +#define MCP2515_MAX_PKT_DATA (13) +// Now we break them out for clarity. These are offsets into a +// transmitted or received packet. +#define MCP2515_PKT_SIDH (0) +#define MCP2515_PKT_SIDL (1) +#define MCP2515_PKT_EID8 (2) +#define MCP2515_PKT_EID0 (3) +#define MCP2515_PKT_DLC (4) +#define MCP2515_PKT_D0 (5) +#define MCP2515_PKT_D1 (6) +#define MCP2515_PKT_D2 (7) +#define MCP2515_PKT_D3 (8) +#define MCP2515_PKT_D4 (9) +#define MCP2515_PKT_D5 (10) +#define MCP2515_PKT_D6 (11) +#define MCP2515_PKT_D7 (12) + +// The number of bytes that make up an ID (SIDH, SIDL, EID8, EID0) +#define MCP2515_MAX_ID_BYTES (4) + + // 4 byte SIDH, SIDL, SID8, SID0 id. This is used only for + // converting back and forth from an integer and 4-byte device + // representation of a standard or extended ID. + typedef union { + uint8_t data[MCP2515_MAX_ID_BYTES]; + struct { + uint8_t SIDH; + uint8_t SIDL; + uint8_t EID8; + uint8_t EID0; + }; + } MCP2515_ID_T; + + // 13 byte packet starting at SIDH. This is used to represent + // packets for transmission and reception. + typedef union { + uint8_t data[MCP2515_MAX_PKT_DATA]; + struct { + uint8_t SIDH; // Id data + uint8_t SIDL; + uint8_t EID8; + uint8_t EID0; + uint8_t DLC; // DLC (data length) + uint8_t D0; // start of 8 byte (max) payload + uint8_t D1; + uint8_t D2; + uint8_t D3; + uint8_t D4; + uint8_t D5; + uint8_t D6; + uint8_t D7; + }; + } MCP2515_PKT_T; + + // A received message. This includes the packet, and some decoded + // data (rtr, ext, id, etc. + typedef struct { + int id; + bool rtr; + bool ext; + int filter_num; + int len; + MCP2515_PKT_T pkt; + } MCP2515_MSG_T; + + // Registers + typedef enum { + // 5 RX filters, each composed of SIDH, SIDL, EID8, EID0. We + // only specify the leading (SIDH) address here. + + // first two filters are associated with rxb0 + MCP2515_REG_FILTER0 = 0x00, + MCP2515_REG_FILTER1 = 0x04, + // remaining 4 filters are associated with rxb1 + MCP2515_REG_FILTER2 = 0x08, + MCP2515_REG_FILTER3 = 0x10, + MCP2515_REG_FILTER4 = 0x14, + MCP2515_REG_FILTER5 = 0x18, + + // 2 RX filter mask registers, like above, we only specify the + // SIDH address + + // associated with rxb0 + MCP2515_REG_MASK0 = 0x20, + // associated with rxb1 + MCP2515_REG_MASK1 = 0x24, + + MCP2515_REG_BFPCTL = 0x0c, + MCP2515_REG_TXRTSCTRL = 0x0d, // tx ready-to-send + + // CANSTAT and CANCTRL are aliased in several locations to + // make it easier to get maximum data using burst reads. In + // reality, they are the same register, but we list them all + // anyway for completeness. + + // CANSTAT and aliases + MCP2515_REG_CANSTAT = 0x0e, + MCP2515_REG_CANSTAT_0 = 0x0e, // same as CANSTAT + + MCP2515_REG_CANSTAT_1 = 0x1e, // rest of the aliases + MCP2515_REG_CANSTAT_2 = 0x2e, + MCP2515_REG_CANSTAT_3 = 0x3e, + MCP2515_REG_CANSTAT_4 = 0x4e, + MCP2515_REG_CANSTAT_5 = 0x5e, + MCP2515_REG_CANSTAT_6 = 0x6e, + MCP2515_REG_CANSTAT_7 = 0x7e, + + // CANCTRL and aliases + MCP2515_REG_CANCTRL = 0x0f, + MCP2515_REG_CANCTRL_0 = 0x0f, // same as CANCTRL + + MCP2515_REG_CANCTRL_1 = 0x1f, // rest of the aliases + MCP2515_REG_CANCTRL_2 = 0x2f, + MCP2515_REG_CANCTRL_3 = 0x3f, + MCP2515_REG_CANCTRL_4 = 0x4f, + MCP2515_REG_CANCTRL_5 = 0x5f, + MCP2515_REG_CANCTRL_6 = 0x6f, + MCP2515_REG_CANCTRL_7 = 0x7f, + + MCP2515_REG_TEC = 0x1c, // tx error count + MCP2515_REG_REC = 0x1d, // rx error count + + MCP2515_REG_CNF3 = 0x28, // configuration bytes + MCP2515_REG_CNF2 = 0x29, + MCP2515_REG_CNF1 = 0x2a, + + MCP2515_REG_CANINTE = 0x2b, // intr enables + MCP2515_REG_CANINTF = 0x2c, // intr flags + + MCP2515_REG_EFLG = 0x2a, // error flags + + // Start of the buffer reg ranges for tx and rx buffers. + // There are 3 transmit buffers and 2 rx buffers. You can + // read and write 16 bytes (0x0f) starting at these locations + // to set and/get buffer control bits, message ids, msg + // content, and CANSTAT and CANCTRL regs in one bus transaction. + + // See the datasheet page 61 + MCP2515_REG_TXB0CTRL = 0x30, // tx buffer 0 ctrl + MCP2515_REG_TXB1CTRL = 0x40, // tx buffer 1 ctrl + MCP2515_REG_TXB2CTRL = 0x50, // tx buffer 2 ctrl + + MCP2515_REG_RXB0CTRL = 0x60, // rx buffer 0 ctrl + MCP2515_REG_RXB1CTRL = 0x70 // rx buffer 1 ctrl + } MCP2515_REG_T; + + // MCP2515_REG_CANCTRL bits + typedef enum { + MCP2515_CANCTRL_CLKPRE0 = 0x01, + MCP2515_CANCTRL_CLKPRE1 = 0x02, + _MCP2515_CANCTRL_CLKPRE_MASK = 3, + _MCP2515_CANCTRL_CLKPRE_SHIFT = 0, + + MCP2515_CANCTRL_CLKEN = 0x04, //enable CLKOUT pin + + MCP2515_CANCTRL_OSM = 0x08, // one shot mode + + MCP2515_CANCTRL_ABAT = 0x10, // abort all pending tx + + MCP2515_CANCTRL_REQOP0 = 0x20, // request new operating mode + MCP2515_CANCTRL_REQOP1 = 0x40, + MCP2515_CANCTRL_REQOP2 = 0x80, + _MCP2515_CANCTRL_REQOP_MASK = 7, + _MCP2515_CANCTRL_REQOP_SHIFT = 5, + } MCP2515_CANCTRL_BITS_T; + + // MCP2515_CLKPRE values + typedef enum { + MCP2515_CLKPRE_DIV1 = 0, // sysclk/1 + MCP2515_CLKPRE_DIV2 = 1, // sysclk/2 + MCP2515_CLKPRE_DIV4 = 2, // sysclk/4 + MCP2515_CLKPRE_DIV8 = 3 // sysclk/8 + } MCP2515_CLKPRE_T; + + // MCP2515_OPMODE values. These are the same for the CANCTRL_REQOP and + // CANSTAT_OPMODE bitfields. + typedef enum { + MCP2515_OPMODE_NORMAL = 0, + MCP2515_OPMODE_SLEEP = 1, + MCP2515_OPMODE_LOOPBACK = 2, + MCP2515_OPMODE_LISTENONLY = 3, + MCP2515_OPMODE_CONFIG = 4 + } MCP2515_OPMODE_T; + + // MCP2515_REG_CANSTAT bits + typedef enum { + // 0x01 reserved + + MCP2515_CANSTAT_ICOD0 = 0x02, // intr flag code + MCP2515_CANSTAT_ICOD1 = 0x04, + MCP2515_CANSTAT_ICOD2 = 0x08, + _MCP2515_CANSTAT_ICOD_MASK = 7, + _MCP2515_CANSTAT_ICOD_SHIFT = 1, + + // 0x10 reserved + + MCP2515_CANSTAT_OPMODE0 = 0x20, // request new operating mode + MCP2515_CANSTAT_OPMODE1 = 0x40, + MCP2515_CANSTAT_OPMODE2 = 0x80, + _MCP2515_CANSTAT_OPMODE_MASK = 7, + _MCP2515_CANSTAT_OPMODE_SHIFT = 5, + } MCP2515_CANSTAT_BITS_T; + + // MCP2515_REG_BFPCTL bits, Buffer Pin Control + typedef enum { + MCP2515_BFPCTL_B0BFM = 0x01, // opmode bit + MCP2515_BFPCTL_B1BFM = 0x02, + + MCP2515_BFPCTL_B0BFE = 0x04, // func enable bit + MCP2515_BFPCTL_B1BFE = 0x08, + + MCP2515_BFPCTL_B0BFS = 0x10, // pin state (output mode only) + MCP2515_BFPCTL_B1BFS = 0x20, + + // 0x40-0x080 reserved + } MCP2515_BFPCTL_BITS_T; + + // MCP2515_REG_TXRTSCTRL bits, TX RTS pin control + typedef enum { + MCP2515_TXRTSCTRL_B0RTSM = 0x01, // pin mode + MCP2515_TXRTSCTRL_B1RTSM = 0x02, + MCP2515_TXRTSCTRL_B2RTSM = 0x04, + + MCP2515_TXRTSCTRL_B0RTS = 0x08, // pin state when in + // input mode + MCP2515_TXRTSCTRL_B1RTS = 0x10, + MCP2515_TXRTSCTRL_B2RTS = 0x20, + + // 0x40-0x80 reserved + } MCP2515_TXRTSCTRL_BITS_T; + + // MCP2515_REG_EFLG bits, Error flags + typedef enum { + MCP2515_EFLG_EWARN = 0x01, // error warning (TEC/REC > 96) + MCP2515_EFLG_RXWAR = 0x02, // rx warning (REC > 96) + MCP2515_EFLG_TXWAR = 0x04, // tx warning (REC > 96) + + MCP2515_EFLG_RXEP = 0x08, // rx error-passive + MCP2515_EFLG_TXEP = 0x10, // tx error-passive + + MCP2515_EFLG_TXBO = 0x20, // tx bus off + + MCP2515_EFLG_RX0OVR = 0x40, // rx buf 0 overflow + MCP2515_EFLG_RX1OVR = 0x80, // rx buf 1 overflow + } MCP2515_EFLG_BITS_T; + + // MCP2515_REG_CANINTE and MCP2515_REG_CANINTF bits, interrupt + // enables and flags. We use the same enum here as the two regs + // have the same bits. + typedef enum { + MCP2515_CANINT_RX0I = 0x01, // rx buf 0 full + MCP2515_CANINT_RX1I = 0x02, // rx buf 1 full + + MCP2515_CANINT_TX0I = 0x04, // tx buf 1 empty + MCP2515_CANINT_TX1I = 0x08, // tx buf 2 empty + MCP2515_CANINT_TX2I = 0x10, // tx buf 3 empty + + MCP2515_CANINT_ERRI = 0x20, // error intr + MCP2515_CANINT_WAKI = 0x40, // wakeup intr + + MCP2515_CANINT_MERR = 0x80 // msg error + } MCP2515_CANINT_BITS_T; + + // MCP2515_REG_TXBCTRL, TX control for tx buffers 0 (0x30), 1 + // (0x40), and 2 (0x50) + typedef enum { + MCP2515_TXBCTRL_TXP0 = 0x01, // message priority + MCP2515_TXBCTRL_TXP1 = 0x02, + _MCP2515_TXBCTRL_TXP_MASK = 3, + _MCP2515_TXBCTRL_TXP_SHIFT = 0, + + // 0x04 reserved + + MCP2515_TXBCTRL_TXREQ = 0x08, // tx request + MCP2515_TXBCTRL_TXERR = 0x10, // tx error detected + MCP2515_TXBCTRL_MLOA = 0x20, // msg lost arbitration + MCP2515_TXBCTRL_ABTF = 0x40 // msg aborted flag + + // 0x80 reserved + } MCP2515_TXBCTRL_BITS_T; + + // MCP2515_TXBCTRL_TXP priority values + typedef enum { + MCP2515_TXP_LOWEST = 0, + MCP2515_TXP_LOW = 1, + MCP2515_TXP_HIGH = 2, + MCP2515_TXP_HIGHEST = 3 + } MCP2515_TXP_T; + + // MCP2515_TXBDLC bits, (addresses 0x35, 0x45, 0x55) + typedef enum { + MCP2515_TXBDLC_DLC0 = 0x01, // data length code + MCP2515_TXBDLC_DLC1 = 0x02, // max is 8 bytes + MCP2515_TXBDLC_DLC2 = 0x04, + MCP2515_TXBDLC_DLC3 = 0x08, + _MCP2515_TXBDLC_MASK = 15, + _MCP2515_TXBDLC_SHIFT = 0, + + // 0x10-0x20 reserved + + MCP2515_TXBDLC_RTR = 0x40, // remote + // transmission + // request bit + + // 0x80 reserved + } MCP2515_TXBDLC_BITS_T; + + // MCP2515_REG_RXB0CTRL, RX control for rx buffer 0 (0x60) + typedef enum { + MCP2515_RXB0CTRL_FILHIT = 0x01, // which filter was hit + + MCP2515_RXB0CTRL_BUKT1 = 0x02, // readonly version of BUKT + MCP2515_RXB0CTRL_BUKT = 0x04, // rollover enable (to rx1) + + MCP2515_RXB0CTRL_RXRTR = 0x08, // RTR request + + // 0x10 reserved + + MCP2515_RXB0CTRL_RXMODE0 = 0x20, // rx buf mode bits + MCP2515_RXB0CTRL_RXMODE1 = 0x40, + _MCP2515_RXB0CTRL_RXMODE_MASK = 3, + _MCP2515_RXB0CTRL_RXMODE_SHIFT = 5 + + // 0x80 reserved + } MCP2515_RXB0CTRL_BITS_T; + + // These values determine whether the filters are used and what + // kinds of messages to accept. They are the same for both rx + // buffers. + typedef enum { + MCP2515_RXMODE_ANY_FILTER = 0, // std/ext based on filter + MCP2515_RXMODE_STANDARD_FILTER = 1, // standard only, filter + MCP2515_RXMODE_EXTENDED_FILTER = 2, // extended only, filter + MCP2515_RXMODE_ANY_NOFILTER = 3 // any, no filter + } MCP2515_RXMODE_T; + + // MCP2515_REG_RXB1CTRL, RX control for rx buffer 1 (0x70) + typedef enum { + MCP2515_RXB1CTRL_FILHIT0 = 0x01, // which filter was hit + MCP2515_RXB1CTRL_FILHIT1 = 0x02, // for a rollover, this can + MCP2515_RXB1CTRL_FILHIT2 = 0x04, // be filter 0 or 1 too. + _MCP2515_RXB1CTRL_FILHIT_MASK = 7, + _MCP2515_RXB1CTRL_FILHIT_SHIFT = 0, + + MCP2515_RXB1CTRL_RXRTR = 0x08, // RTR request + + // 0x10 reserved + + MCP2515_RXB1CTRL_RXMODE0 = 0x20, // rx buf mode bits + MCP2515_RXB1CTRL_RXMODE1 = 0x40, + _MCP2515_RXB1CTRL_RXMODE_MASK = 3, + _MCP2515_RXB1CTRL_RXMODE_SHIFT = 5 + + // 0x80 reserved + } MCP2515_RXB1CTRL_BITS_T; + + // MCP2515_RXB1CTRL_FILHIT values for rx buffer 1 + typedef enum { + MCP2515_FILHIT_F0 = 0, // filter 0 hit (only if bukt) + MCP2515_FILHIT_F1 = 1, // filter 1 hit (only if bukt) + MCP2515_FILHIT_F2 = 2, // filter 2 hit + MCP2515_FILHIT_F3 = 3, + MCP2515_FILHIT_F4 = 4, + MCP2515_FILHIT_F5 = 5 + } MCP2515_FILHIT_T; + + // Valid CANBUS speeds. These are precomputed and represented in + // a table in mcp2515.c. It is a requirement that the enum values + // below correspond to the indexes in the speed table. Keep them + // in sync! Add any new values to the end of this enum, and to + // the corresponding table in mcp2515.c. + // + // These values are valid only for 16Mhz clocks. + typedef enum { + MCP2515_SPEED_5KBPS = 0, + MCP2515_SPEED_10KBPS = 1, + MCP2515_SPEED_20KBPS = 2, + MCP2515_SPEED_25KBPS = 3, + MCP2515_SPEED_31_25KBPS = 4, // 31.25kbps + MCP2515_SPEED_33KBPS = 5, + MCP2515_SPEED_40KBPS = 6, + MCP2515_SPEED_50KBPS = 7, + MCP2515_SPEED_80KBPS = 8, + MCP2515_SPEED_83KBPS = 9, + + MCP2515_SPEED_95KBPS = 10, + MCP2515_SPEED_100KBPS = 11, + MCP2515_SPEED_125KBPS = 12, + MCP2515_SPEED_200KBPS = 13, + MCP2515_SPEED_250KBPS = 14, + MCP2515_SPEED_500KBPS = 15, + MCP2515_SPEED_666KBPS = 16, + MCP2515_SPEED_1000KBPS = 17 + } MCP2515_SPEED_T; + + // MCP2515_RXBDLC bits, (addresses 0x65, 0x75) + typedef enum { + MCP2515_RXBDLC_DLC0 = 0x01, // data length code + MCP2515_RXBDLC_DLC1 = 0x02, // max is 8 bytes + MCP2515_RXBDLC_DLC2 = 0x04, + MCP2515_RXBDLC_DLC3 = 0x08, + _MCP2515_RXBDLC_MASK = 15, + _MCP2515_RXBDLC_SHIFT = 0, + + // 0x10-0x20 reserved + + MCP2515_RXBDLC_RTR = 0x40, // remote + // transmission + // request bit, if + // extended id + + // 0x80 reserved + } MCP2515_RXBDLC_BITS_T; + + // SPI commands - these are commands sent to the device to start + // certain operations. The datasheet specifies that after CS is + // active, the first byte must be the command byte. It is not + // possible to send multiple commands in a single transaction + // (a CS On/CS Off sequence). + typedef enum { + MCP2515_CMD_RESET = 0xc0, + + MCP2515_CMD_READ = 0x03, + + // These commands allows the specification of a read buffer. + // The real command is 0x90. The lower nibble is 0mn0, + // where m and n specify the 4 locations to start reading + // from. In this list, we will enumerate all of them. + // + // n m cmd real hex addr + // ------------------------------ + // 0 0 RXB0SIDH 0x61 + // 0 1 RXB0D0 0x66 + // 1 0 RXB1SIDH 0x71 + // 1 1 RXB1D0 0x76 + MCP2515_CMD_READ_RXBUF_RXB0SIDH = 0x90, + MCP2515_CMD_READ_RXBUF_RXB0D0 = 0x92, + MCP2515_CMD_READ_RXBUF_RXB1SIDH = 0x94, + MCP2515_CMD_READ_RXBUF_RXB1D0 = 0x96, + + MCP2515_CMD_WRITE = 0x02, + + // This command allows speedier loading of tx buffer contents. + // The lower nibble is 0b0abc, where abc specifies 6 location + // addresses to start writing to. This works similarly to the + // READ_RXBUF_* commands. + // + // a b c cmd real hex addr + // ---------------------------------- + // 0 0 0 TXB0SIDH 0x31 + // 0 0 1 TXB0D0 0x36 + // 0 1 0 TXB1SIDH 0x41 + // 0 1 1 TXB1D0 0x46 + // 1 0 0 TXB2SIDH 0x51 + // 1 0 1 TXB2D0 0x56 + MCP2515_CMD_LOAD_TXBUF_TXB0SIDH = 0x40, + MCP2515_CMD_LOAD_TXBUF_TXB0D0 = 0x41, + MCP2515_CMD_LOAD_TXBUF_TXB1SIDH = 0x42, + MCP2515_CMD_LOAD_TXBUF_TXB1D0 = 0x43, + MCP2515_CMD_LOAD_TXBUF_TXB2SIDH = 0x44, + MCP2515_CMD_LOAD_TXBUF_TXB2D0 = 0x45, + + // Request to Send. This is a quick way to request the + // sending of tx buffers without having to do a + // read/modify/write register sequence. The lower 3 bits + // indicate which buffer(s) to setup for transmission. + // + // 0x8n Where n is 0b0xxx. bit 0 is for txb 0, bit 1 for txb 1 + // and bit 2 for txb 2. + MCP2515_CMD_RTS = 0x80, + MCP2515_CMD_RTS_BUFFER0 = 0x81, + MCP2515_CMD_RTS_BUFFER1 = 0x82, + MCP2515_CMD_RTS_BUFFER2 = 0x84, + + // return status bits for rx and tx. See MCP2515_RDSTATUS_BITS_T. + MCP2515_CMD_READ_STATUS = 0xa0, + + // returns information on which filters have been matched. + // See MCP2515_RXSTATUS_BITS_T. + MCP2515_CMD_RX_STATUS = 0xb0, + + // This command allows for certain registers to have certain + // bit(s) modified w/o going through a read/modify/write cycle + // of the whole register. See the datasheet - only certain + // registers can be used with this command. + // + // The format for this command is: cmd, addr, mask, value + MCP2515_CMD_BIT_MODIFY = 0x05 + } MCP2515_CMD_T; + + // This bitfield is the contents of the byte returned from a + // CMD_READ_STATUS command. + typedef enum { + MCP2515_RDSTATUS_RX0IF = 0x01, // rx buf 0 full IF + MCP2515_RDSTATUS_RX1IF = 0x02, // rx buf 1 full IF + MCP2515_RDSTATUS_TXB0REQ = 0x04, // TX buf 0 req bit + MCP2515_RDSTATUS_TXB0IF = 0x08, // TX buf 0 empty IF + MCP2515_RDSTATUS_TXB1REQ = 0x10, // TX buf 1 req bit + MCP2515_RDSTATUS_TXB1IF = 0x20, // TX buf 1 empty IF + MCP2515_RDSTATUS_TXB2REQ = 0x40, // TX buf 2 req bit + MCP2515_RDSTATUS_TXB2IF = 0x80 // TX buf 2 empty IF + } MCP2515_RDSTATUS_BITS_T; + + // This bitfield is the contents of the byte returned from a + // CMD_READ_RX_STATUS command. + typedef enum { + MCP2515_RXSTATUS_FILTERMATCH0 = 0x01, + MCP2515_RXSTATUS_FILTERMATCH1 = 0x02, + MCP2515_RXSTATUS_FILTERMATCH2 = 0x04, + _MCP2515_RXSTATUS_FILTERMATCH_MASK = 7, + _MCP2515_RXSTATUS_FILTERMATCH_SHIFT = 0, + + MCP2515_RXSTATUS_MSGTYPE0 = 0x08, + MCP2515_RXSTATUS_MSGTYPE1 = 0x10, + _MCP2515_RXSTATUS_MSGTYPE_MASK = 3, + _MCP2515_RXSTATUS_MSGTYPE_SHIFT = 3, + + // 0x20 is not mentioned in the DS + + MCP2515_RXSTATUS_RXMSG0 = 0x40, + MCP2515_RXSTATUS_RXMSG1 = 0x80, + _MCP2515_RXSTATUS_RXMSG_MASK = 3, + _MCP2515_RXSTATUS_RXMSG_SHIFT = 6 + } MCP2515_RXSTATUS_BITS_T; + + // MCP2515_RXSTATUS_FILTERMATCH values + typedef enum { + MCP2515_FILTERMATCH_RXF0 = 0, + MCP2515_FILTERMATCH_RXF1 = 1, + MCP2515_FILTERMATCH_RXF2 = 2, + MCP2515_FILTERMATCH_RXF3 = 3, + MCP2515_FILTERMATCH_RXF4 = 4, + MCP2515_FILTERMATCH_RXF5 = 5, + MCP2515_FILTERMATCH_RXF0_ROLLOVER = 6, + MCP2515_FILTERMATCH_RXF1_ROLLOVER = 7 + } MCP2515_FILTERMATCH_T; + + // MCP2515_RXSTATUS_MSGTYPE values + typedef enum { + MCP2515_MSGTYPE_STD = 0, // standard + MCP2515_MSGTYPE_STDRF = 1, // standard remote frame + MCP2515_MSGTYPE_EXT = 2, // extended + MCP2515_MSGTYPE_EXTRF = 3 // extended remote frame + } MCP2515_MSGTYPE_T; + + // MCP2515_RXSTATUS_RXMSG values + typedef enum { + MCP2515_RXMSG_NONE = 0, // no msg + MCP2515_RXMSG_RXB0 = 1, // msg in rxb0 + MCP2515_RXMSG_RXB1 = 2, // msg in rxb1 + MCP2515_RXMSG_BOTH = 3 // msg in both + } MCP2515_RXMSG_T; + + // we spell out the SIDL registers as they contain the EXIDE bit. + // The others (SIDL, EID0 and EID8 just contain their respective + // ID bits. + typedef enum { + MCP2515_SIDL_EID16 = 0x01, + MCP2515_SIDL_EID17 = 0x02, + + // 0x04 reserved + + MCP2515_SIDL_EXIDE = 0x08, + + // 0x10 reserved + + MCP2515_SIDL_SID0 = 0x20, + MCP2515_SIDL_SID1 = 0x40, + MCP2515_SIDL_SID2 = 0x80 + } MCP2515_SIDL_T; + + // An enum to specify one of the 3 TX buffers + typedef enum { + MCP2515_TX_BUFFER0 = 0, + MCP2515_TX_BUFFER1 = 1, + MCP2515_TX_BUFFER2 = 2, + // special value indicating no buffers + MCP2515_TX_NO_BUFFERS = 255 + } MCP2515_TX_BUFFER_T; + + // An enum to specify one of the 2 rx buffers + typedef enum { + MCP2515_RX_BUFFER0 = 0, + MCP2515_RX_BUFFER1 = 1 + } MCP2515_RX_BUFFER_T; + + // An enum to specify one of the 6 rx filters + typedef enum { + MCP2515_RX_FILTER0 = 0, + MCP2515_RX_FILTER1 = 1, + MCP2515_RX_FILTER2 = 2, + MCP2515_RX_FILTER3 = 3, + MCP2515_RX_FILTER4 = 4, + MCP2515_RX_FILTER5 = 5 + } MCP2515_RX_FILTER_T; + + // An enum to specify one of the 2 rx masks + typedef enum { + MCP2515_RX_MASK0 = 0, + MCP2515_RX_MASK1 = 1 + } MCP2515_RX_MASK_T; + + +#ifdef __cplusplus +} +#endif diff --git a/src/mcp2515/pyupm_mcp2515.i b/src/mcp2515/pyupm_mcp2515.i new file mode 100644 index 00000000..0559f16b --- /dev/null +++ b/src/mcp2515/pyupm_mcp2515.i @@ -0,0 +1,19 @@ +// Include doxygen-generated documentation +%include "pyupm_doxy2swig.i" +%module pyupm_mcp2515 +%include "../upm.i" +%include "cpointer.i" +%include "std_string.i" +%include "../carrays_uint8_t.i" + +%include "stdint.i" + +%feature("autodoc", "3"); + +%pointer_functions(float, floatp); + +%include "mcp2515_regs.h" +%include "mcp2515.hpp" +%{ + #include "mcp2515.hpp" +%}