Skip to content
Snippets Groups Projects
Commit 58454580 authored by Davide Mor's avatar Davide Mor
Browse files

[cc3135] VERY early version of the driver, barely implemented bidirectional communication

parent 27ba3494
Branches
No related tags found
No related merge requests found
...@@ -276,6 +276,9 @@ add_executable(test-sx1278-serial ...@@ -276,6 +276,9 @@ add_executable(test-sx1278-serial
) )
sbs_target(test-sx1278-serial stm32f429zi_stm32f4discovery) sbs_target(test-sx1278-serial stm32f429zi_stm32f4discovery)
add_executable(test-cc3135 src/tests/drivers/CC3135/test-cc3135.cpp)
sbs_target(test-cc3135 stm32f407vg_stm32f4discovery)
#-----------------------------------------------------------------------------# #-----------------------------------------------------------------------------#
# Tests - Sensors # # Tests - Sensors #
#-----------------------------------------------------------------------------# #-----------------------------------------------------------------------------#
......
...@@ -62,6 +62,7 @@ foreach(OPT_BOARD ${BOARDS}) ...@@ -62,6 +62,7 @@ foreach(OPT_BOARD ${BOARDS})
${SBS_BASE}/src/shared/radio/Xbee/APIFrameParser.cpp ${SBS_BASE}/src/shared/radio/Xbee/APIFrameParser.cpp
${SBS_BASE}/src/shared/radio/Xbee/Xbee.cpp ${SBS_BASE}/src/shared/radio/Xbee/Xbee.cpp
${SBS_BASE}/src/shared/radio/SX1278/SX1278.cpp ${SBS_BASE}/src/shared/radio/SX1278/SX1278.cpp
${SBS_BASE}/src/shared/radio/CC3135/CC3135.cpp
# Scheduler # Scheduler
${SBS_BASE}/src/shared/scheduler/TaskScheduler.cpp ${SBS_BASE}/src/shared/scheduler/TaskScheduler.cpp
......
/* Copyright (c) 2021 Skyward Experimental Rocketry
* Author: Davide Mor
*
* 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 "CC3135.h"
namespace Boardcore
{
using namespace CC3135Defs;
void CC3135Proto::handleIntr()
{
// TODO:
}
void CC3135::dummyRead()
{
uint8_t buf[220];
proto.readPacket(buf);
ResponseHeader header;
memcpy(&header, &buf[0], sizeof(ResponseHeader));
// TRACE("status: %d\n", header.dev_status);
// TRACE("opcode: %s\n", opToStr(header.gen_header.opcode));
// TRACE("len: %d\n", header.gen_header.len);
// TRACE("\n");
// if(header.gen_header.opcode == OPCODE_DEVICE_DEVICEGETRESPONSE) {
// for(int i = 0; i < header.gen_header.len + 4; i++) {
// TRACE("%2x\n", buf[i]);
// }
// }
}
DeviceVersion CC3135::getVersion()
{
DeviceSetGet packet;
packet.gen_header.opcode = OPCODE_DEVICE_DEVICEGET;
packet.device_set_id = 1; // Device get general
packet.option = 12; // Device get version
proto.writePacket((uint8_t *)&packet, sizeof(packet));
return {};
}
//! Get a generic header out of a buffer.
GenericHeader *getHeader(uint8_t *buf) { return (GenericHeader *)(buf); }
void CC3135Proto::readPacket(uint8_t *buf)
{
// 1. Write CNYS pattern (only if SPI)
if (iface->is_spi())
{
SyncPattern sync = H2N_CNYS_PATTERN;
iface->write((uint8_t *)(&sync.short1), SYNC_PATTERN_LEN);
}
// 2. Read initial data from the device
iface->read(&buf[0], 8);
/*
Here the TI driver does some weird stuff.
Also the TI comment is wrong, soooo, I'll just skip that part
*/
// 3. Scan for device SYNC
while (true)
{
// Try and find the SYNC here
uint32_t sync;
memcpy(&sync, &buf[0], 4);
if (n2hSyncPatternMatch(sync, tx_seq_num))
{
// Copy the bytes after the sync to the start
memcpy(&buf[0], &buf[4], 4);
break;
}
// TODO: The TI driver reads 4 bytes at a time, is this also good?
// Shift everything
memmove(&buf[0], &buf[1], 7);
iface->read(&buf[7], 1);
}
// 4. Scan for double syncs
while (true)
{
uint32_t sync;
memcpy(&sync, &buf[0], 4);
if (!n2hSyncPatternMatch(sync, tx_seq_num))
{
break;
}
iface->read(&buf[0], 4);
}
tx_seq_num++;
// 5. Parse generic header
GenericHeader *header = getHeader(&buf[0]);
// 6. Finalize and read rest of the data
if (header->len > 0)
{
// TODO: The TI driver reads a ResponseHeader, violating zero size
size_t aligned_len = alignSize(header->len);
iface->read(&buf[sizeof(GenericHeader)], aligned_len);
}
}
void CC3135Proto::writePacket(uint8_t *buf, size_t size)
{
// 1. Write SYNC pattern
if (iface->is_spi())
{
// Short pattern for SPI
SyncPattern sync = H2N_SYNC_PATTERN;
iface->write((uint8_t *)&sync.short1, SYNC_PATTERN_LEN);
}
else
{
// Long pattern for UART
SyncPattern sync = H2N_SYNC_PATTERN;
iface->write((uint8_t *)&sync.long1, SYNC_PATTERN_LEN * 2);
}
// 2. Setup header length
GenericHeader *header = getHeader(&buf[0]);
header->len = size - sizeof(GenericHeader);
// 3. Write message
iface->write(buf, size);
}
} // namespace Boardcore
/* Copyright (c) 2021 Skyward Experimental Rocketry
* Author: Davide Mor
*
* 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 <memory>
#include "CC3135Defs.h"
#include "CC3135Iface.h"
/*
TODO(davide.mor): Write a small description of the CC3135
*/
namespace Boardcore
{
/**
* @brief Abstraction over the comunication protocol.
*/
class CC3135Proto
{
public:
explicit CC3135Proto(std::unique_ptr<ICC3135Iface> &&iface)
: iface(std::move(iface)), tx_seq_num(0)
{
}
void handleIntr();
void readPacket(uint8_t *buf);
void writePacket(uint8_t *buf, size_t size);
private:
std::unique_ptr<ICC3135Iface> iface;
uint8_t tx_seq_num;
};
class CC3135
{
public:
explicit CC3135(std::unique_ptr<ICC3135Iface> &&iface)
: proto(std::move(iface))
{
}
void handleIntr() { proto.handleIntr(); }
//! Dummy packet read, used to test comunication.
void dummyRead();
//! Retrieve information about the device
CC3135Defs::DeviceVersion getVersion();
private:
CC3135Proto proto;
};
} // namespace Boardcore
/* Copyright (c) 2021 Skyward Experimental Rocketry
* Author: Davide Mor
*
* 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 <cstdint>
#include <cstdlib>
/*
CC3135 Protocol definitions
This definitions come mostly from the TI driver and a bit of RE
*/
namespace Boardcore
{
namespace CC3135Defs
{
//! Synchronous message mask.
constexpr uint16_t OPCODE_SYNC = 1 << 10;
//! Device command opcodes.
enum OpCode : uint16_t
{
OPCODE_DEVICE_INITCOMPLETE = 0x0008,
OPCODE_DEVICE_DEVICEASYNCDUMMY = 0x0063,
OPCODE_DEVICE_DEVICEGETRESPONSE = 0x0466,
OPCODE_DEVICE_DEVICESETRESPONSE = 0x04B7,
OPCODE_WLAN_PROVISIONING_STATUS_ASYNC_EVENT = 0x089A, //< ????
OPCODE_NETAPP_IPACQUIRED = 0x1825, //< ????
OPCODE_DEVICE_DEVICEGET = 0x8466,
OPCODE_DEVICE_DEVICESET = 0x84B7,
};
struct SyncPattern
{
uint32_t long1;
uint16_t short1;
uint8_t byte1;
uint8_t byte2;
};
struct DeviceVersion
{
uint32_t chip_id;
uint8_t fw_version[4];
uint8_t phy_version[4];
uint8_t nwp_version[4];
uint16_t rom_version;
uint16_t _pad;
};
struct GenericHeader
{
OpCode opcode;
uint16_t len;
};
struct ResponseHeader
{
GenericHeader gen_header;
uint8_t tx_pool_count;
uint8_t dev_status;
uint16_t min_max_payload;
uint16_t socket_tx_failure;
uint16_t socket_non_blocking;
};
struct DeviceSetGet
{
GenericHeader gen_header;
uint16_t status;
uint16_t device_set_id;
uint16_t option;
uint16_t config_len;
};
constexpr SyncPattern H2N_SYNC_PATTERN = {0xBBDDEEFF, 0x4321, 0x34, 0x12};
constexpr SyncPattern H2N_CNYS_PATTERN = {0xBBDDEEFF, 0x8765, 0x78, 0x56};
constexpr size_t SYNC_PATTERN_LEN = sizeof(uint32_t);
constexpr uint32_t N2H_SYNC_PATTERN = 0xABCDDCBA;
constexpr uint32_t N2H_SYNC_PATTERN_SEQ_NUM_BITS = 0x00000003;
constexpr uint32_t N2H_SYNC_PATTERN_SEQ_NUM_EXISTS = 0x00000004;
constexpr uint32_t N2H_SYNC_PATTERN_MASK = 0xFFFFFFF8;
constexpr uint32_t N2H_SYNC_SPI_BUGS_MASK = 0x7FFF7F7F; // What?
inline bool n2hSyncPatternMatch(uint32_t sync, uint8_t seq_num)
{
// TODO: Add sequence number
return (sync & N2H_SYNC_SPI_BUGS_MASK & N2H_SYNC_PATTERN_MASK) ==
(N2H_SYNC_PATTERN & N2H_SYNC_SPI_BUGS_MASK & N2H_SYNC_PATTERN_MASK);
}
//! Is this message synchronous?
inline bool isSync(OpCode op) { return op & OPCODE_SYNC; }
//! Align message size.
inline size_t alignSize(size_t size) { return (size + 3) & (~3); }
inline const char *opToStr(OpCode op)
{
switch (op)
{
case OpCode::OPCODE_DEVICE_INITCOMPLETE:
return "OPCODE_DEVICE_INITCOMPLETE";
case OpCode::OPCODE_DEVICE_DEVICEASYNCDUMMY:
return "OPCODE_DEVICE_DEVICEASYNCDUMMY";
case OpCode::OPCODE_DEVICE_DEVICEGETRESPONSE:
return "OPCODE_DEVICE_DEVICEGETRESPONSE";
case OpCode::OPCODE_DEVICE_DEVICESETRESPONSE:
return "OPCODE_DEVICE_DEVICESETRESPONSE";
case OpCode::OPCODE_NETAPP_IPACQUIRED:
return "OPCODE_NETAPP_IPACQUIRED";
case OpCode::OPCODE_WLAN_PROVISIONING_STATUS_ASYNC_EVENT:
return "OPCODE_WLAN_PROVISIONING_STATUS_ASYNC_EVENT";
case OpCode::OPCODE_DEVICE_DEVICEGET:
return "OPCODE_DEVICE_DEVICEGET";
case OpCode::OPCODE_DEVICE_DEVICESET:
return "OPCODE_DEVICE_DEVICESET";
default:
return "<unknown>";
}
}
} // namespace CC3135Defs
} // namespace Boardcore
/* Copyright (c) 2021 Skyward Experimental Rocketry
* Author: Davide Mor
*
* 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 <drivers/spi/SPIDriver.h>
#include <drivers/usart/USART.h>
namespace Boardcore
{
/**
* @brief Abstraction over the kinds of interface of the CC3135
*/
class ICC3135Iface
{
public:
virtual void read(uint8_t *buffer, size_t size) = 0;
virtual void write(uint8_t *buffer, size_t size) = 0;
virtual bool is_spi() = 0;
};
/**
* @brief SPI CC3135 implementation.
*/
class CC3135Spi : public ICC3135Iface
{
public:
explicit CC3135Spi(SPIBusInterface &bus, GpioType cs,
SPIBusConfig config = {})
: slave(bus, cs, config)
{
}
void read(uint8_t *buffer, size_t size) override
{
SPITransaction spi(slave);
spi.read(buffer, size);
}
void write(uint8_t *buffer, size_t size) override
{
SPITransaction spi(slave);
spi.write(buffer, size);
}
bool is_spi() override { return true; }
private:
SPISlave slave;
};
/**
* @brief UART CC3135 implementation.
*/
class CC3135Uart : public ICC3135Iface
{
public:
explicit CC3135Uart(USARTType *usart) : usart(usart, DEFAULT_BAUD)
{
this->usart.init();
}
void read(uint8_t *buffer, size_t size) override
{
usart.read(buffer, size);
}
void write(uint8_t *buffer, size_t size) override
{
usart.write(buffer, size);
}
bool is_spi() override { return false; }
private:
static constexpr USART::Baudrate DEFAULT_BAUD = USART::Baudrate::B115200;
USART usart;
};
} // namespace Boardcore
/* Copyright (c) 2021 Skyward Experimental Rocketry
* Author: Davide Mor
*
* 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 <drivers/interrupt/external_interrupts.h>
#include <radio/CC3135/CC3135.h>
using namespace Boardcore;
using namespace miosix;
/*
Connection diagram:
cc3135:CC_SPI_CS -> stm32:pa1
cc3135:CC_nHIB -> stm32:pc14
cc3135:CC_IRQ -> stm32:pc15
cc3135:CC_SPI_DIN -> stm32:pc12 (SPI3_MOSI)
cc3135:CC_SPI_DOUT -> stm32:pc11 (SPI3_MISO)
cc3135:CC_SPI_CLK -> stm32:pc10 (SPI3_SCK)
*/
using tx = Gpio<GPIOA_BASE, 2>;
using rx = Gpio<GPIOA_BASE, 3>;
using irq = Gpio<GPIOA_BASE, 4>;
using hib = Gpio<GPIOA_BASE, 5>;
#define CC3135_UART USART2
#define CC3135_HIB
CC3135 *cc3135 = nullptr;
void __attribute__((used)) EXTI4_IRQHandlerImpl()
{
if (cc3135)
cc3135->handleIntr();
}
void initBoard()
{
#ifdef CC3135_HIB
{
miosix::FastInterruptDisableLock dLock;
hib::mode(miosix::Mode::OUTPUT);
}
hib::high();
#endif
#ifdef CC3135_UART
{
miosix::FastInterruptDisableLock dLock;
irq::mode(miosix::Mode::INPUT);
tx::mode(miosix::Mode::ALTERNATE);
tx::alternateFunction(7);
rx::mode(miosix::Mode::ALTERNATE);
rx::alternateFunction(7);
}
auto irq_pin = irq::getPin();
enableExternalInterrupt(irq_pin.getPort(), irq_pin.getNumber(),
InterruptTrigger::RISING_EDGE);
#endif
}
int main()
{
initBoard();
#ifdef CC3135_UART
std::unique_ptr<ICC3135Iface> iface(new CC3135Uart(CC3135_UART));
#endif
cc3135 = new CC3135(std::move(iface));
Thread::sleep(200);
cc3135->getVersion();
while (true)
{
cc3135->dummyRead();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment