mirror of https://github.com/ArduPilot/ardupilot
255 lines
5.6 KiB
C++
255 lines
5.6 KiB
C++
/*
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <AP_HAL/AP_HAL.h>
|
|
|
|
#if CONFIG_HAL_BOARD == HAL_BOARD_QURT
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include "UDPDriver.h"
|
|
#include <stdio.h>
|
|
#include <AP_HAL/utility/RingBuffer.h>
|
|
#include <AP_Math/AP_Math.h>
|
|
|
|
using namespace QURT;
|
|
|
|
extern const AP_HAL::HAL& hal;
|
|
|
|
void UDPDriver::begin(uint32_t b)
|
|
{
|
|
begin(b, 16384, 16384);
|
|
}
|
|
|
|
void UDPDriver::begin(uint32_t b, uint16_t rxS, uint16_t txS)
|
|
{
|
|
rxS = constrain_int32(rxS, 16384, 30000);
|
|
txS = constrain_int32(txS, 16384, 30000);
|
|
|
|
/*
|
|
allocate the read buffer
|
|
*/
|
|
if (rxS != 0 && (readbuf == nullptr || rxS != readbuf->get_size())) {
|
|
initialised = false;
|
|
if (readbuf != nullptr) {
|
|
delete readbuf;
|
|
}
|
|
readbuf = new ByteBuffer(rxS);
|
|
}
|
|
|
|
/*
|
|
allocate the write buffer
|
|
*/
|
|
if (txS != 0 && (writebuf == nullptr || txS != writebuf->get_size())) {
|
|
initialised = false;
|
|
if (writebuf != nullptr) {
|
|
delete writebuf;
|
|
}
|
|
writebuf = new ByteBuffer(txS);
|
|
}
|
|
|
|
if (readbuf && writebuf) {
|
|
initialised = true;
|
|
}
|
|
}
|
|
|
|
void UDPDriver::end()
|
|
{
|
|
initialised = false;
|
|
if (readbuf) {
|
|
delete readbuf;
|
|
readbuf = nullptr;
|
|
}
|
|
if (writebuf) {
|
|
delete writebuf;
|
|
writebuf = nullptr;
|
|
}
|
|
|
|
}
|
|
|
|
void UDPDriver::flush()
|
|
{
|
|
}
|
|
|
|
bool UDPDriver::is_initialized()
|
|
{
|
|
return initialised;
|
|
}
|
|
|
|
void UDPDriver::set_blocking_writes(bool blocking)
|
|
{
|
|
nonblocking_writes = !blocking;
|
|
}
|
|
|
|
bool UDPDriver::tx_pending()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/* QURT implementations of Stream virtual methods */
|
|
int16_t UDPDriver::available()
|
|
{
|
|
if (!initialised) {
|
|
return 0;
|
|
}
|
|
return readbuf->available();
|
|
}
|
|
|
|
int16_t UDPDriver::txspace()
|
|
{
|
|
if (!initialised) {
|
|
return 0;
|
|
}
|
|
return writebuf->space();
|
|
}
|
|
|
|
int16_t UDPDriver::read()
|
|
{
|
|
uint8_t c;
|
|
if (!initialised) {
|
|
return -1;
|
|
}
|
|
if (!lock.take(HAL_SEMAPHORE_BLOCK_FOREVER)) {
|
|
return 0;
|
|
}
|
|
if (readbuf->empty()) {
|
|
lock.give();
|
|
return -1;
|
|
}
|
|
readbuf->read(&c, 1);
|
|
lock.give();
|
|
return c;
|
|
}
|
|
|
|
/* QURT implementations of Print virtual methods */
|
|
size_t UDPDriver::write(uint8_t c)
|
|
{
|
|
if (!initialised) {
|
|
return 0;
|
|
}
|
|
if (!lock.take(HAL_SEMAPHORE_BLOCK_FOREVER)) {
|
|
return 0;
|
|
}
|
|
|
|
while (writebuf->space() == 0) {
|
|
if (nonblocking_writes) {
|
|
lock.give();
|
|
return 0;
|
|
}
|
|
hal.scheduler->delay_microseconds(1000);
|
|
}
|
|
writebuf->write(&c, 1);
|
|
lock.give();
|
|
return 1;
|
|
}
|
|
|
|
size_t UDPDriver::write(const uint8_t *buffer, size_t size)
|
|
{
|
|
if (!initialised) {
|
|
return 0;
|
|
}
|
|
if (!nonblocking_writes) {
|
|
/*
|
|
use the per-byte delay loop in write() above for blocking writes
|
|
*/
|
|
size_t ret = 0;
|
|
while (size--) {
|
|
if (write(*buffer++) != 1) break;
|
|
ret++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
if (!lock.take(HAL_SEMAPHORE_BLOCK_FOREVER)) {
|
|
return 0;
|
|
}
|
|
size_t ret = writebuf->write(buffer, size);
|
|
lock.give();
|
|
return ret;
|
|
}
|
|
|
|
uint32_t UDPDriver::socket_check(uint8_t *buf, int len, uint32_t *nbytes)
|
|
{
|
|
if (!initialised) {
|
|
return 1;
|
|
}
|
|
if (!writebuf) {
|
|
return 1;
|
|
}
|
|
*nbytes = writebuf->available();
|
|
if (*nbytes == 0) {
|
|
return 1;
|
|
}
|
|
if (*nbytes > len) {
|
|
*nbytes = len;
|
|
}
|
|
uint32_t n = *nbytes;
|
|
if (writebuf->peek(0) != 254) {
|
|
/*
|
|
we have a non-mavlink packet at the start of the
|
|
buffer. Look ahead for a MAVLink start byte, up to 256 bytes
|
|
ahead
|
|
*/
|
|
uint16_t limit = n>256?256:n;
|
|
uint16_t i;
|
|
for (i=0; i<limit; i++) {
|
|
if (writebuf->peek(i) == 254) {
|
|
n = i;
|
|
break;
|
|
}
|
|
}
|
|
// if we didn't find a MAVLink marker then limit the send size to 256
|
|
if (i == limit) {
|
|
n = limit;
|
|
}
|
|
} else {
|
|
// this looks like a MAVLink packet - try to write on
|
|
// packet boundaries when possible
|
|
if (n < 8) {
|
|
n = 0;
|
|
} else {
|
|
// the length of the packet is the 2nd byte, and mavlink
|
|
// packets have a 6 byte header plus 2 byte checksum,
|
|
// giving len+8 bytes
|
|
uint8_t len = writebuf->peek(1);
|
|
if (n < len+8) {
|
|
// we don't have a full packet yet
|
|
n = 0;
|
|
} else if (n > len+8) {
|
|
// send just 1 packet at a time (so MAVLink packets
|
|
// are aligned on UDP boundaries)
|
|
n = len+8;
|
|
}
|
|
}
|
|
}
|
|
|
|
*nbytes = n;
|
|
writebuf->read(buf, *nbytes);
|
|
return 0;
|
|
}
|
|
|
|
uint32_t UDPDriver::socket_input(const uint8_t *buf, int len, uint32_t *nbytes)
|
|
{
|
|
if (!initialised) {
|
|
return 1;
|
|
}
|
|
if (!readbuf) {
|
|
return 1;
|
|
}
|
|
*nbytes = readbuf->write(buf, len);
|
|
return 0;
|
|
}
|
|
#endif // CONFIG_HAL_BOARD
|
|
|