26#include <kernel/scheduler/scheduler.h>
32using miosix::FastMutex;
45 :
Xbee(bus, {}, cs, attn, rst, txTimeout)
52 : spiXbee(bus, cs, config), attn(attn), rst(rst), txTimeout(txTimeout)
61 if (packetLength > MAX_PACKET_PAYLOAD_LENGTH || packetLength == 0)
63 LOG_ERR(logger,
"Invalid packet length (0< {} <= {})", packetLength,
64 MAX_PACKET_PAYLOAD_LENGTH);
70 uint8_t txFrameId = buildTXRequestFrame(txReq, pkt, packetLength);
72 bool statusTimeout =
true;
74 Lock<FastMutex> l(mutexXbeeCommunication);
87 statusTimeout =
false;
92 LOG_ERR(logger,
"Wrong txStatus ID");
101 if (attn.value() == 0)
107 LOG_ERR(logger,
"TX_STATUS timeout");
121 if (!rxFramesBuffer.isEmpty() || currRxPayloadPointer >= 0)
123 return fillReceiveBuf(buf, bufMaxSize);
127 else if (attn.value() == 0)
129 Lock<FastMutex> l(mutexXbeeCommunication);
132 sendATCommandInternal(
"DB");
133 sendATCommandInternal(
"ER");
140 miosix::FastInterruptDisableLock dLock;
141 receiveThread = miosix::Thread::getCurrentThread();
143 while (receiveThread != 0)
145 receiveThread->IRQwait();
147 miosix::FastInterruptEnableLock eLock(dLock);
148 miosix::Thread::yield();
156 forceRcvReturn =
false;
172 Lock<FastMutex> l(mutexXbeeCommunication);
174 miosix::FastInterruptDisableLock dLock();
175 rst.mode(miosix::Mode::OPEN_DRAIN);
197 if (attn.value() == 0 && readOneFrame() == ParseResult::SUCCESS)
199 handleFrame(parsingApiFrame);
204 miosix::Thread::sleep(5);
210 forceRcvReturn = forceReturn;
211 miosix::FastInterruptDisableLock dLock;
215 receiveThread->IRQwakeup();
224 receiveThread->IRQwakeup();
225 if (receiveThread->IRQgetPriority() >
226 miosix::Thread::IRQgetCurrentThread()->IRQgetPriority())
228 miosix::Scheduler::IRQfindNextThread();
235size_t Xbee::fillReceiveBuf(uint8_t* buf,
size_t bufMaxSize)
237 if (!rxFramesBuffer.isEmpty() && currRxPayloadPointer == -1)
239 Lock<FastMutex> l(mutexRxFrames);
240 currRxFrame = rxFramesBuffer.pop();
241 currRxPayloadPointer = 0;
244 if (currRxPayloadPointer >= 0)
246 size_t lenRemainingData =
250 size_t lenToCopy = min(bufMaxSize, lenRemainingData);
255 currRxPayloadPointer += lenToCopy;
260 currRxPayloadPointer = -1;
271 SPIAcquireLock acq(spiXbee);
272 SPISelectLock sel(spiXbee);
277 result = parser.
parse(spiXbee.
bus.
read(), &parsingApiFrame);
278 }
while (attn.value() == 0 && result == ParseResult::PARSING);
283bool Xbee::readRXFrame()
285 while (attn.value() == 0)
287 if (readOneFrame() == ParseResult::SUCCESS)
289 handleFrame(parsingApiFrame);
298void Xbee::writeFrame(APIFrame& frame)
303 uint8_t txBuf[MAX_API_FRAME_SIZE];
304 size_t txBufSize = frame.toBytes(txBuf);
307 SPITransaction spi(spiXbee);
308 spi.transfer(txBuf, txBufSize);
313 frameListener(frame);
317 for (
unsigned int i = 0; i < txBufSize; i++)
320 if (res == ParseResult::SUCCESS)
321 handleFrame(parsingApiFrame);
325bool Xbee::waitForFrame(uint8_t frameType,
unsigned int pollInterval,
326 long long timeoutTick)
330 if (attn.value() == 0)
332 if (readOneFrame() == ParseResult::SUCCESS)
334 handleFrame(parsingApiFrame);
336 if (parsingApiFrame.
frameType == frameType)
342 miosix::Thread::sleep(pollInterval);
349uint8_t Xbee::buildTXRequestFrame(TXRequestFrame& txReq, uint8_t* pkt,
352 memcpy(txReq.getRFDataPointer(), pkt, packetLength);
353 txReq.setRFDataLength(packetLength);
355 uint8_t txFrameId = getNewFrameID();
357 txReq.setFrameID(txFrameId);
359 txReq.setDestAddress(ADDRESS_BROADCAST);
360 txReq.setBroadcastRadius(0);
365 txReq.calcChecksum();
372 Lock<FastMutex> l(mutexXbeeCommunication);
374 sendATCommandInternal(0, cmd, params, paramsLen);
378 uint8_t* params,
size_t paramsLen,
379 unsigned int timeout)
381 Lock<FastMutex> l(mutexXbeeCommunication);
383 uint8_t txFrameId = sendATCommandInternal(cmd, params, paramsLen);
385 bool success =
false;
407uint8_t Xbee::sendATCommandInternal(
const char* cmd, uint8_t* params,
410 return sendATCommandInternal(getNewFrameID(), cmd, params, paramsLen);
413uint8_t Xbee::sendATCommandInternal(uint8_t txFrameId,
const char* cmd,
414 uint8_t* params,
size_t paramsLen)
418 at.setATCommand(cmd);
419 at.setFrameID(txFrameId);
422 if (paramsLen > MAX_AT_COMMAND_PARAMS_LENGTH)
424 LOG_ERR(logger,
"AT Command payload too large, it was truncated");
425 paramsLen = MAX_AT_COMMAND_PARAMS_LENGTH;
427 at.setParameterSize(paramsLen);
428 memcpy(at.getCommandDataPointer(), params, paramsLen);
439void Xbee::handleFrame(APIFrame& frame)
444 switch (frame.frameType)
448 RXPacketFrame* pf = frame.toFrameType<RXPacketFrame>();
450 Lock<FastMutex>
l(mutexRxFrames);
452 if (rxFramesBuffer.isFull())
455 rxFramesBuffer.put(*pf);
465 ModemStatusFrame* ms = frame.toFrameType<ModemStatusFrame>();
467 switch (ms->getStatus())
470 LOG_DEBUG(logger,
"Modem status: Hardware reset");
473 LOG_DEBUG(logger,
"Modem status: Watchdog timer reset");
480 TXStatusFrame* ts = frame.toFrameType<TXStatusFrame>();
492 logger,
"TX Status Error: {} (retries: {}, RD: {})",
494 ts->getDiscoveryStatus() == 2 ?
"Enabled" :
"Disabled");
505 frameListener(frame);
510 frameListener = listener;
513uint8_t Xbee::getNewFrameID()
515 uint8_t txFrameId = frameIdCounter++;
518 if (frameIdCounter == 0)
#define LOG_ERR(logger,...)
#define LOG_DEBUG(logger,...)
RAII Interface for SPI bus acquisition.
Interface for low level access of a SPI bus as a master.
virtual uint8_t read()=0
Reads 8 bits from the bus.
static StackLogger & getInstance()
StatsResult getStats() const
Return statistics of the elements added so far.
ParseResult parse(uint8_t byte, APIFrame *frame)
Parses a single byte. When this function returns ParseResult:SUCESS, frame contains a valid APIFrame.
void wakeReceiver(bool forceReturn=false)
Wakes the receive function without needing an interrupt.
void setOnFrameReceivedListener(OnFrameReceivedListener listener)
Set the frame received listener, called each time a new APIFrame is received from the device.
ssize_t receive(uint8_t *buf, size_t bufferMaxSize) override
Waits until a new packet is received.
Xbee(SPIBusInterface &bus, GpioType cs, GpioType attn, GpioType rst, long long txTimeout=DEFAULT_TX_TIMEOUT)
Constructs a new instance of the Xbee driver.
void handleATTNInterrupt()
Signals the receive() function that there is new data available. Call this from the ATTN pin interrup...
std::function< void(APIFrame &frame)> OnFrameReceivedListener
void reset()
Hardware resets the Xbee.
void sendATCommand(const char *cmd, uint8_t *params=nullptr, size_t paramsLength=0)
Sends an AT Command to the Xbee (see datasheet) without waiting for a response.
bool send(uint8_t *pkt, size_t packetLength) override
Sends a packet. The function blocks until the packet is sent to the peripheral, but does not wait for...
long long getOldTick()
Get the current time in milliseconds.
@ FTYPE_AT_COMMAND_RESPONSE
APIFrameParser::ParseResult ParseResult
@ MS_WATCHDOG_TIMER_RESET
This file includes all the types the logdecoder script will decode.
SPI Bus configuration for a specific slave.
GpioType cs
Chip select pin.
SPIBusInterface & bus
Bus on which the slave is connected.
FrameType * toFrameType()
uint8_t getFrameID() const
const char * getATCommand() const
uint8_t * getRXDataPointer()
uint16_t getRXDataLength() const
uint8_t getFrameID() const
uint8_t getDeliveryStatus() const
unsigned int frameBufMaxLength
uint8_t lastTxStatusError
unsigned int rxDroppedBuffers
StatsResult timeToSendStats
unsigned int txTimeoutCount