diff --git a/src/shared/radio/CC3135/CC3135.cpp b/src/shared/radio/CC3135/CC3135.cpp index 5124be5ee064891a1cdb787e8da6e88bab6bd167..15680adf1f101411513e6758000405e7ccb6d5d5 100644 --- a/src/shared/radio/CC3135/CC3135.cpp +++ b/src/shared/radio/CC3135/CC3135.cpp @@ -25,6 +25,17 @@ #include <kernel/scheduler/scheduler.h> #include <utils/Debug.h> +#define TRY(expr) \ + do \ + { \ + Boardcore::CC3135::Error result = (expr); \ + if (result != Boardcore::CC3135::Error::NO_ERROR) \ + { \ + TRACE("[cc3135] NWP error@ %s\n", __FUNCTION__); \ + return result; \ + } \ + } while (0) + using namespace Boardcore::CC3135Defs; using namespace miosix; @@ -33,20 +44,38 @@ namespace Boardcore CC3135::CC3135(std::unique_ptr<ICC3135Iface> &&iface) : iface(std::move(iface)) { - // Start internal thread - this->start(); irq_wait_thread = thread; } -DeviceVersion CC3135::getVersion() +CC3135::Error CC3135::init(bool wait_for_init) { - DeviceVersion result = {}; + if (wait_for_init) + { + DeviceInitInfo init_info = {}; + TRY(readPacketSync(OPCODE_DEVICE_INITCOMPLETE, Buffer::from(&init_info), + Buffer::null())); + + TRACE( + "[cc3135] Init completed:\n" + "- Status: %8x\n" + "- Chip Id: %lx\n" + "- More Data: %8x\n", + init_info.status, init_info.chip_id, init_info.more_data); + } - devigeGet(1, 12, Buffer::from(&result)); - return result; + // Start internal thread + this->start(); + + return Error::NO_ERROR; +} + +CC3135::Error CC3135::getVersion(DeviceVersion &version) +{ + version = {}; + return devigeGet(1, 12, Buffer::from<DeviceVersion>(&version)); } -void CC3135::devigeGet(uint8_t set_id, uint8_t option, Buffer result) +CC3135::Error CC3135::devigeGet(uint8_t set_id, uint8_t option, Buffer result) { DeviceSetGet tx_command = {}; tx_command.device_set_id = set_id; @@ -54,21 +83,21 @@ void CC3135::devigeGet(uint8_t set_id, uint8_t option, Buffer result) DeviceSetGet rx_command = {}; - inoutPacketSync(OPCODE_DEVICE_DEVICEGET, Buffer::from(&tx_command), - Buffer::null(), OPCODE_DEVICE_DEVICEGETRESPONSE, - Buffer::from(&rx_command), result); + return inoutPacketSync(OPCODE_DEVICE_DEVICEGET, Buffer::from(&tx_command), + Buffer::null(), OPCODE_DEVICE_DEVICEGETRESPONSE, + Buffer::from(&rx_command), result); } -void CC3135::setMode(CC3135Defs::Mode mode) +CC3135::Error CC3135::setMode(CC3135Defs::Mode mode) { WlanSetMode tx_command = {}; tx_command.mode = mode; BasicResponse rx_command = {}; - inoutPacketSync(OPCODE_WLAN_SET_MODE, Buffer::from(&tx_command), - Buffer::null(), OPCODE_WLAN_SET_MODE_RESPONSE, - Buffer::from(&rx_command), Buffer::null()); + return inoutPacketSync(OPCODE_WLAN_SET_MODE, Buffer::from(&tx_command), + Buffer::null(), OPCODE_WLAN_SET_MODE_RESPONSE, + Buffer::from(&rx_command), Buffer::null()); } void CC3135::handleIrq() @@ -136,28 +165,7 @@ void CC3135::defaultPacketHandler(CC3135Defs::ResponseHeader header) size_t len = header.inner.len; - switch (header.inner.opcode) - { - case OPCODE_DEVICE_INITCOMPLETE: - { - DeviceInitInfo result = {}; - safeRead(len, Buffer::from(&result)); - - TRACE( - "[cc3135] Init completen:\n" - "- Status: %8x\n" - "- Chip Id: %lx\n" - "- More Data: %8x\n", - result.status, result.chip_id, result.more_data); - break; - } - - default: - break; - } - // Dummy read rest of the data - // TODO: Add async commands if (len > 0) dummyRead(len); } @@ -165,7 +173,6 @@ void CC3135::defaultPacketHandler(CC3135Defs::ResponseHeader header) void CC3135::run() { // TODO: Implement a way to stop this thread - while (true) { waitForIrq(); @@ -176,53 +183,68 @@ void CC3135::run() Lock<FastMutex> lock(iface_mutex); ResponseHeader header; - readHeader(&header); + Error result = readHeader(&header); - defaultPacketHandler(header); + if (result != Error::NO_ERROR) + { + TRACE("[cc3135] NWP error!\n"); + } + else + { + defaultPacketHandler(header); + } } } } -void CC3135::inoutPacketSync(CC3135Defs::OpCode tx_opcode, - CC3135::Buffer tx_command, - CC3135::Buffer tx_payload, - CC3135Defs::OpCode rx_opcode, - CC3135::Buffer rx_command, - CC3135::Buffer rx_payload) +CC3135::Error CC3135::inoutPacketSync(CC3135Defs::OpCode tx_opcode, + CC3135::Buffer tx_command, + CC3135::Buffer tx_payload, + CC3135Defs::OpCode rx_opcode, + CC3135::Buffer rx_command, + CC3135::Buffer rx_payload) { installAsServiceThread(); // Lock the device interface Lock<FastMutex> lock(iface_mutex); - writePacket(tx_opcode, tx_command, tx_payload); + TRY(writePacket(tx_opcode, tx_command, tx_payload)); - readPacket(rx_opcode, rx_command, rx_payload); + TRY(readPacket(rx_opcode, rx_command, rx_payload)); restoreDefaultServiceThread(); + + return Error::NO_ERROR; } -void CC3135::readPacketSync(CC3135Defs::OpCode opcode, CC3135::Buffer command, - CC3135::Buffer payload) +CC3135::Error CC3135::readPacketSync(CC3135Defs::OpCode opcode, + CC3135::Buffer command, + CC3135::Buffer payload) { installAsServiceThread(); // Lock the device interface Lock<FastMutex> lock(iface_mutex); - readPacket(opcode, command, payload); + TRY(readPacket(opcode, command, payload)); restoreDefaultServiceThread(); + + return Error::NO_ERROR; } -void CC3135::writePacketSync(CC3135Defs::OpCode opcode, CC3135::Buffer command, - CC3135::Buffer payload) +CC3135::Error CC3135::writePacketSync(CC3135Defs::OpCode opcode, + CC3135::Buffer command, + CC3135::Buffer payload) { // Lock the device interface Lock<FastMutex> lock(iface_mutex); - writePacket(opcode, command, payload); + TRY(writePacket(opcode, command, payload)); + + return Error::NO_ERROR; } -void CC3135::readPacket(OpCode opcode, CC3135::Buffer command, - CC3135::Buffer payload) +CC3135::Error CC3135::readPacket(OpCode opcode, CC3135::Buffer command, + CC3135::Buffer payload) { while (true) { @@ -232,7 +254,7 @@ void CC3135::readPacket(OpCode opcode, CC3135::Buffer command, // Locking the interface is not needed ResponseHeader header = {}; - readHeader(&header); + TRY(readHeader(&header)); if (header.inner.opcode != opcode) { @@ -253,25 +275,34 @@ void CC3135::readPacket(OpCode opcode, CC3135::Buffer command, break; } } + + return Error::NO_ERROR; } -void CC3135::writePacket(OpCode opcode, CC3135::Buffer command, - CC3135::Buffer payload) +CC3135::Error CC3135::writePacket(OpCode opcode, CC3135::Buffer command, + CC3135::Buffer payload) { RequestHeader header{opcode, static_cast<uint16_t>(command.len + payload.len)}; - writeHeader(&header); + TRY(writeHeader(&header)); if (command.len > 0) iface->write(command.ptr, command.len); if (payload.len > 0) iface->write(payload.ptr, payload.len); + + return Error::NO_ERROR; } -void CC3135::readHeader(ResponseHeader *header) +CC3135::Error CC3135::readHeader(ResponseHeader *header) { + // 20 kernel ticks, or 100ms + const int TIMEOUT = 2000; + + long long start = getTick(); + // 1. Write CNYS pattern (only if SPI) if (iface->is_spi()) { @@ -293,8 +324,10 @@ void CC3135::readHeader(ResponseHeader *header) // 3. Scan for device SYNC while (true) { - // Reads in SPI are always more than 4 bytes + if ((getTick() - start) > TIMEOUT) + return Error::NWP_TIMEOUT; + // Reads in SPI are always more than 4 bytes bool found = false; int i; for (i = 0; i < 4; i++) @@ -303,11 +336,6 @@ void CC3135::readHeader(ResponseHeader *header) uint32_t sync; memcpy(&sync, &buf[i], 4); - if (sync == 0x0a7b2d01) - { - // BRUH - } - if (n2hSyncPatternMatch(sync, tx_seq_num)) { found = true; @@ -334,6 +362,9 @@ void CC3135::readHeader(ResponseHeader *header) memcpy(&sync, &buf[0], 4); while (n2hSyncPatternMatch(sync, tx_seq_num)) { + if ((getTick() - start) > TIMEOUT) + return Error::NWP_TIMEOUT; + memmove(&buf[0], &buf[4], 4); iface->read(&buf[4], 4); @@ -348,9 +379,11 @@ void CC3135::readHeader(ResponseHeader *header) // 6. Adjust for bigger response header header->inner.len -= sizeof(ResponseHeader) - sizeof(GenericHeader); + + return Error::NO_ERROR; } -void CC3135::writeHeader(RequestHeader *header) +CC3135::Error CC3135::writeHeader(RequestHeader *header) { // 1. Write SYNC pattern if (iface->is_spi()) @@ -370,17 +403,25 @@ void CC3135::writeHeader(RequestHeader *header) // 2. Write body iface->write(reinterpret_cast<uint8_t *>(header), sizeof(RequestHeader)); + + return Error::NO_ERROR; } void CC3135::dummyRead(size_t n) { - uint8_t dummy[n]; - iface->read(dummy, n); + // Avoid HUGE stack allocations + uint8_t dummy[256]; + + while (n > 0) + { + iface->read(dummy, std::min(n, sizeof(dummy))); + n -= std::min(n, sizeof(dummy)); + } } void CC3135::safeRead(size_t &len, Buffer buffer) { - if (buffer.len > 0) + if (buffer.len > 0 && len > 0) { iface->read(buffer.ptr, std::min(len, buffer.len)); len -= std::min(len, buffer.len); diff --git a/src/shared/radio/CC3135/CC3135.h b/src/shared/radio/CC3135/CC3135.h index 31d18cdaa3b486aee8fac758837a7da1bde890db..8a569d72efd2ebcc98cb84429ffacbc2cba9595c 100644 --- a/src/shared/radio/CC3135/CC3135.h +++ b/src/shared/radio/CC3135/CC3135.h @@ -43,13 +43,22 @@ namespace Boardcore class CC3135 : ActiveObject { public: + enum class Error + { + NO_ERROR, //< No error occured. + NWP_TIMEOUT, //< The NWP did not respond. + NWP_STATUS_NON_ZERO, //< The NWD returned a non-zero status code. + }; + explicit CC3135(std::unique_ptr<ICC3135Iface> &&iface); + CC3135::Error init(bool wait_for_init); + void handleIrq(); - CC3135Defs::DeviceVersion getVersion(); + CC3135::Error getVersion(CC3135Defs::DeviceVersion &version); - void setMode(CC3135Defs::Mode mode); + CC3135::Error setMode(CC3135Defs::Mode mode); private: //! Simple buffer for scatter/gather IO @@ -72,7 +81,7 @@ private: void defaultPacketHandler(CC3135Defs::ResponseHeader header); - void devigeGet(uint8_t set_id, uint8_t option, Buffer result); + CC3135::Error devigeGet(uint8_t set_id, uint8_t option, Buffer result); // Functions dedicated to interrupt servicing @@ -86,26 +95,29 @@ private: // Functions for high level IO //! Write a packet in output and wait for a packet in input - void inoutPacketSync(CC3135Defs::OpCode tx_opcode, Buffer tx_command, - Buffer tx_payload, CC3135Defs::OpCode rx_opcode, - Buffer rx_command, Buffer rx_payload); + CC3135::Error inoutPacketSync(CC3135Defs::OpCode tx_opcode, + Buffer tx_command, Buffer tx_payload, + CC3135Defs::OpCode rx_opcode, + Buffer rx_command, Buffer rx_payload); //! Read packet in input, with proper synchronization. - void readPacketSync(CC3135Defs::OpCode opcode, Buffer command, - Buffer payload); + CC3135::Error readPacketSync(CC3135Defs::OpCode opcode, Buffer command, + Buffer payload); //! Write a packet in output, with proper synchronization. - void writePacketSync(CC3135Defs::OpCode opcode, Buffer command, - Buffer payload); + CC3135::Error writePacketSync(CC3135Defs::OpCode opcode, Buffer command, + Buffer payload); // Functions for low level IO //! Read a single packet. - void readPacket(CC3135Defs::OpCode opcode, Buffer command, Buffer payload); + CC3135::Error readPacket(CC3135Defs::OpCode opcode, Buffer command, + Buffer payload); //! Write a single packet. - void writePacket(CC3135Defs::OpCode opcode, Buffer command, Buffer payload); + CC3135::Error writePacket(CC3135Defs::OpCode opcode, Buffer command, + Buffer payload); //! Read a packet header. - void readHeader(CC3135Defs::ResponseHeader *header); + CC3135::Error readHeader(CC3135Defs::ResponseHeader *header); //! Write a packet header. - void writeHeader(CC3135Defs::RequestHeader *header); + CC3135::Error writeHeader(CC3135Defs::RequestHeader *header); //! Read dummy n bytes. void dummyRead(size_t n); diff --git a/src/tests/drivers/CC3135/test-cc3135.cpp b/src/tests/drivers/CC3135/test-cc3135.cpp index 47e575d3c4bce62e6f42dadd116e4bd3c9a8a6a4..f3e2e034b3a3185bf2b3387b70db1f2e6287bd98 100644 --- a/src/tests/drivers/CC3135/test-cc3135.cpp +++ b/src/tests/drivers/CC3135/test-cc3135.cpp @@ -28,6 +28,14 @@ using namespace Boardcore; using namespace miosix; +#define CHECK(expr) \ + do \ + { \ + Boardcore::CC3135::Error result = (expr); \ + if (result != Boardcore::CC3135::Error::NO_ERROR) \ + printf("[cc3135] NWP error!\n"); \ + } while (0) + /* Connection diagram: cc3135:CC_SPI_CS -> stm32:pa1 @@ -170,6 +178,13 @@ int main() initBoard(); +#ifdef CC3135_HIB + // Reset CC3135 + hib::low(); + Thread::sleep(100); + hib::high(); +#endif + #ifdef CC3135_SPI SPIBus bus(CC3135_SPI); GpioPin cs_pin = cs::getPin(); @@ -186,22 +201,29 @@ int main() std::unique_ptr<ICC3135Iface> iface(new CC3135Uart(CC3135_UART)); #endif + Thread::sleep(5000); + printf("[cc3135] Initializing...\n"); cc3135 = new CC3135(std::move(iface)); - printf("[cc3135] Initialization complete!\n"); -#ifdef CC3135_HIB - // Reset CC3135 - hib::low(); - Thread::sleep(100); - hib::high(); -#endif + cc3135->handleIrq(); + + if (cc3135->init(true) != CC3135::Error::NO_ERROR) + { + printf("[cc3135] Failed to start cc3135, retrying...\n"); + Thread::sleep(2000); + return; + + // miosix::reboot(); + } + + printf("[cc3135] Initialization complete!\n"); - Thread::sleep(500); - // cc3135->setMode(CC3135Defs::ROLE_AP); + // CHECK(cc3135->setMode(CC3135Defs::ROLE_STA)); // Thread::sleep(500); - auto version = cc3135->getVersion(); + CC3135Defs::DeviceVersion version = {}; + CHECK(cc3135->getVersion(version)); printf( "[cc3135] Chip Id: %lx\n" "[cc3135] Fw version: %u.%u.%u.%u\n" @@ -216,4 +238,6 @@ int main() while (true) ; + // Thread::sleep(3000); + // miosix::reboot(); }