mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-25 20:23:38 +08:00
nsh console running on USB param module running working with i2c and common drivers provided implementation for drv_pwm_output.h i2cdetect working as expected with no device mavlink started succesfully mounts sd card and logger runs logger to file succesfully pwm_servo implemented without using Nuttx lib pwm_out outputs expected waveforms - however currently if the frequency is higher than what the pwm_out driver runs, there will be aliasing, based on how the registers gets resets wifi softap working - Seeing wifi hotspot - cant connect due to wrong password - problems with adjusting ssid and password wifi ssid and password being set accordinglu connected to wifi hotspot with dhpcd - made some changes to nuttx to only build for SoftAP mode, however this was effectivelyy removing the ifdef for STATION mode. Should investigate the coexist option again added ifdef to not use timer 0 when wifi enabled - reverted esp32 rt_timer to make use of timer 0 by default fix setting incorrect bit in hrt timer register - hrt running as expected, but on startup the pwm_out driver starts up at about 200Hz and then rises over a minute or so 250Hz. Not sure if this was present previously, and could be due to Wifi running at time priority on timer 0 pull xtensa compilers in setup.ubuntu.sh revert logger stacksize and cmake argument esp32 chip revision and PX4 UUID implemented spi board reset implemented, formatting checked devkit acts on startup as a wifi bridge for comms - the most usefull setting for the general developer when buying a esp32 devkit - testing Mavlink shell using ./Tools/mavlink_shell.py - todo: Test mavlink messages being forward improve wifi telemetry by increasing prio - Remove power save mode on wifi - increased daemon thread schedule priority to 50 compiles without Nuttx changes - updated compiler settings to match those of nuttx on px4 side add espressif_esp32 to excluded boards ci: allow docker to find xtensa compilers
528 lines
11 KiB
C++
528 lines
11 KiB
C++
/****************************************************************************
|
|
*
|
|
* Copyright (C) 2023 PX4 Development Team. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name PX4 nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <SerialImpl.hpp>
|
|
#include <string.h> // strncpy
|
|
#include <termios.h>
|
|
#include <px4_log.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <poll.h>
|
|
#include <drivers/drv_hrt.h>
|
|
|
|
#define MODULE_NAME "SerialImpl"
|
|
|
|
namespace device
|
|
{
|
|
|
|
SerialImpl::SerialImpl(const char *port, uint32_t baudrate, ByteSize bytesize, Parity parity, StopBits stopbits,
|
|
FlowControl flowcontrol) :
|
|
_baudrate(baudrate),
|
|
_bytesize(bytesize),
|
|
_parity(parity),
|
|
_stopbits(stopbits),
|
|
_flowcontrol(flowcontrol)
|
|
{
|
|
if (validatePort(port)) {
|
|
setPort(port);
|
|
|
|
} else {
|
|
_port[0] = 0;
|
|
}
|
|
}
|
|
|
|
SerialImpl::~SerialImpl()
|
|
{
|
|
if (isOpen()) {
|
|
close();
|
|
}
|
|
}
|
|
|
|
bool SerialImpl::configure()
|
|
{
|
|
/* process baud rate */
|
|
int speed;
|
|
|
|
switch (_baudrate) {
|
|
case 0:
|
|
// special case, if baudrate is 0 it hangs entire system
|
|
PX4_ERR("baudrate not specified");
|
|
return false;
|
|
|
|
case 9600: speed = B9600; break;
|
|
|
|
case 19200: speed = B19200; break;
|
|
|
|
case 38400: speed = B38400; break;
|
|
|
|
case 57600: speed = B57600; break;
|
|
|
|
case 115200: speed = B115200; break;
|
|
|
|
case 230400: speed = B230400; break;
|
|
|
|
#ifndef B460800
|
|
#define B460800 460800
|
|
#endif
|
|
|
|
case 460800: speed = B460800; break;
|
|
|
|
#ifndef B500000
|
|
#define B500000 500000
|
|
#endif
|
|
|
|
case 500000: speed = B500000; break;
|
|
|
|
#ifndef B576000
|
|
#define B576000 576000
|
|
#endif
|
|
|
|
case 576000: speed = B576000; break;
|
|
|
|
#ifndef B921600
|
|
#define B921600 921600
|
|
#endif
|
|
|
|
case 921600: speed = B921600; break;
|
|
|
|
#ifndef B1000000
|
|
#define B1000000 1000000
|
|
#endif
|
|
|
|
case 1000000: speed = B1000000; break;
|
|
|
|
#ifndef B1500000
|
|
#define B1500000 1500000
|
|
#endif
|
|
|
|
case 1500000: speed = B1500000; break;
|
|
|
|
default:
|
|
speed = _baudrate;
|
|
#ifdef CONFIG_ARCH_CHIP_ESP32
|
|
PX4_WARN("Using non-standard baudrate: %u", _baudrate);
|
|
#else
|
|
PX4_WARN("Using non-standard baudrate: %lu", _baudrate);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
struct termios uart_config;
|
|
|
|
int termios_state;
|
|
|
|
/* fill the struct for the new configuration */
|
|
if ((termios_state = tcgetattr(_serial_fd, &uart_config)) < 0) {
|
|
PX4_ERR("ERR: %d (tcgetattr)", termios_state);
|
|
return false;
|
|
}
|
|
|
|
/* properly configure the terminal (see also https://en.wikibooks.org/wiki/Serial_Programming/termios ) */
|
|
|
|
//
|
|
// Input flags - Turn off input processing
|
|
//
|
|
// convert break to null byte, no CR to NL translation,
|
|
// no NL to CR translation, don't mark parity errors or breaks
|
|
// no input parity check, don't strip high bit off,
|
|
// no XON/XOFF software flow control
|
|
//
|
|
uart_config.c_iflag &= ~(IGNBRK | BRKINT | ICRNL |
|
|
INLCR | PARMRK | INPCK | ISTRIP | IXON);
|
|
|
|
//
|
|
// Output flags - Turn off output processing
|
|
//
|
|
// no CR to NL translation, no NL to CR-NL translation,
|
|
// no NL to CR translation, no column 0 CR suppression,
|
|
// no Ctrl-D suppression, no fill characters, no case mapping,
|
|
// no local output processing
|
|
//
|
|
// config.c_oflag &= ~(OCRNL | ONLCR | ONLRET |
|
|
// ONOCR | ONOEOT| OFILL | OLCUC | OPOST);
|
|
uart_config.c_oflag = 0;
|
|
|
|
//
|
|
// No line processing
|
|
//
|
|
// echo off, echo newline off, canonical mode off,
|
|
// extended input processing off, signal chars off
|
|
//
|
|
uart_config.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
|
|
|
|
/* no parity, one stop bit, disable flow control */
|
|
uart_config.c_cflag &= ~(CSTOPB | PARENB | CRTSCTS);
|
|
|
|
/* set baud rate */
|
|
if ((termios_state = cfsetispeed(&uart_config, speed)) < 0) {
|
|
PX4_ERR("ERR: %d (cfsetispeed)", termios_state);
|
|
return false;
|
|
}
|
|
|
|
if ((termios_state = cfsetospeed(&uart_config, speed)) < 0) {
|
|
PX4_ERR("ERR: %d (cfsetospeed)", termios_state);
|
|
return false;
|
|
}
|
|
|
|
if ((termios_state = tcsetattr(_serial_fd, TCSANOW, &uart_config)) < 0) {
|
|
PX4_ERR("ERR: %d (tcsetattr)", termios_state);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SerialImpl::open()
|
|
{
|
|
if (isOpen()) {
|
|
return true;
|
|
}
|
|
|
|
if (!validatePort(_port)) {
|
|
PX4_ERR("Invalid port %s", _port);
|
|
return false;
|
|
}
|
|
|
|
// Open the serial port
|
|
int serial_fd = ::open(_port, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
|
|
|
if (serial_fd < 0) {
|
|
PX4_ERR("failed to open %s err: %d", _port, errno);
|
|
return false;
|
|
}
|
|
|
|
_serial_fd = serial_fd;
|
|
|
|
// Configure the serial port
|
|
if (! configure()) {
|
|
PX4_ERR("failed to configure %s err: %d", _port, errno);
|
|
return false;
|
|
}
|
|
|
|
_open = true;
|
|
|
|
// Do pin operations after port has been opened
|
|
if (_single_wire_mode) {
|
|
setSingleWireMode();
|
|
}
|
|
|
|
if (_swap_rx_tx_mode) {
|
|
setSwapRxTxMode();
|
|
}
|
|
|
|
setInvertedMode(_inverted_mode);
|
|
|
|
return _open;
|
|
}
|
|
|
|
bool SerialImpl::isOpen() const
|
|
{
|
|
return _open;
|
|
}
|
|
|
|
bool SerialImpl::close()
|
|
{
|
|
|
|
if (_serial_fd >= 0) {
|
|
::close(_serial_fd);
|
|
}
|
|
|
|
_serial_fd = -1;
|
|
_open = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
ssize_t SerialImpl::bytesAvailable()
|
|
{
|
|
if (!_open) {
|
|
PX4_ERR("Device not open!");
|
|
return -1;
|
|
}
|
|
|
|
ssize_t bytes_available = 0;
|
|
int ret = ioctl(_serial_fd, FIONREAD, &bytes_available);
|
|
return ret >= 0 ? bytes_available : 0;
|
|
}
|
|
|
|
ssize_t SerialImpl::read(uint8_t *buffer, size_t buffer_size)
|
|
{
|
|
if (!_open) {
|
|
PX4_ERR("Cannot read from serial device until it has been opened");
|
|
return -1;
|
|
}
|
|
|
|
int ret = ::read(_serial_fd, buffer, buffer_size);
|
|
|
|
if (ret < 0) {
|
|
PX4_DEBUG("%s read error %d", _port, ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
ssize_t SerialImpl::readAtLeast(uint8_t *buffer, size_t buffer_size, size_t character_count, uint32_t timeout_ms)
|
|
{
|
|
if (!_open) {
|
|
PX4_ERR("Cannot readAtLeast from serial device until it has been opened");
|
|
return -1;
|
|
}
|
|
|
|
if (buffer_size < character_count) {
|
|
PX4_ERR("%s: Buffer not big enough to hold desired amount of read data", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
const hrt_abstime start_time_us = hrt_absolute_time();
|
|
hrt_abstime timeout_us = timeout_ms * 1000;
|
|
int total_bytes_read = 0;
|
|
|
|
while ((total_bytes_read < (int) character_count) && (hrt_elapsed_time(&start_time_us) < timeout_us)) {
|
|
// Poll for incoming UART data.
|
|
pollfd fds[1];
|
|
fds[0].fd = _serial_fd;
|
|
fds[0].events = POLLIN;
|
|
|
|
hrt_abstime elapsed_time_us = hrt_elapsed_time(&start_time_us);
|
|
|
|
if (elapsed_time_us > timeout_us) { break; }
|
|
|
|
int ret = poll(fds, sizeof(fds) / sizeof(fds[0]), (timeout_us - elapsed_time_us) / 1000);
|
|
|
|
if (ret > 0) {
|
|
if (fds[0].revents & POLLIN) {
|
|
const unsigned sleeptime = character_count * 1000000 / (_baudrate / 10);
|
|
|
|
int err = 0;
|
|
int bytes_available = 0;
|
|
err = ::ioctl(_serial_fd, FIONREAD, (unsigned long)&bytes_available);
|
|
|
|
if (err != 0 || bytes_available < (int)character_count) {
|
|
px4_usleep(sleeptime);
|
|
}
|
|
|
|
ret = read(&buffer[total_bytes_read], buffer_size - total_bytes_read);
|
|
|
|
if (ret > 0) {
|
|
total_bytes_read += ret;
|
|
}
|
|
|
|
} else {
|
|
PX4_ERR("Got a poll error");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return total_bytes_read;
|
|
}
|
|
|
|
ssize_t SerialImpl::write(const void *buffer, size_t buffer_size)
|
|
{
|
|
if (!_open) {
|
|
PX4_ERR("Cannot write to serial device until it has been opened");
|
|
return -1;
|
|
}
|
|
|
|
int written = ::write(_serial_fd, buffer, buffer_size);
|
|
tcdrain(_serial_fd); // Wait until all output is transmitted
|
|
|
|
if (written < 0) {
|
|
PX4_ERR("%s write error %d", _port, written);
|
|
}
|
|
|
|
return written;
|
|
}
|
|
|
|
void SerialImpl::flush()
|
|
{
|
|
if (_open) {
|
|
tcflush(_serial_fd, TCIOFLUSH);
|
|
}
|
|
}
|
|
|
|
const char *SerialImpl::getPort() const
|
|
{
|
|
return _port;
|
|
}
|
|
|
|
bool SerialImpl::validatePort(const char *port)
|
|
{
|
|
return (port && (access(port, R_OK | W_OK) == 0));
|
|
}
|
|
|
|
bool SerialImpl::setPort(const char *port)
|
|
{
|
|
if (_open) {
|
|
PX4_ERR("Cannot set port after port has already been opened");
|
|
return false;
|
|
}
|
|
|
|
if (validatePort(port)) {
|
|
strncpy(_port, port, sizeof(_port) - 1);
|
|
_port[sizeof(_port) - 1] = '\0';
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
uint32_t SerialImpl::getBaudrate() const
|
|
{
|
|
return _baudrate;
|
|
}
|
|
|
|
bool SerialImpl::setBaudrate(uint32_t baudrate)
|
|
{
|
|
// check if already configured
|
|
if ((baudrate == _baudrate) && _open) {
|
|
return true;
|
|
}
|
|
|
|
_baudrate = baudrate;
|
|
|
|
// process baud rate change now if port is already open
|
|
if (_open) {
|
|
return configure();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ByteSize SerialImpl::getBytesize() const
|
|
{
|
|
return _bytesize;
|
|
}
|
|
|
|
bool SerialImpl::setBytesize(ByteSize bytesize)
|
|
{
|
|
return bytesize == ByteSize::EightBits;
|
|
}
|
|
|
|
Parity SerialImpl::getParity() const
|
|
{
|
|
return _parity;
|
|
}
|
|
|
|
bool SerialImpl::setParity(Parity parity)
|
|
{
|
|
return parity == Parity::None;
|
|
}
|
|
|
|
StopBits SerialImpl::getStopbits() const
|
|
{
|
|
return _stopbits;
|
|
}
|
|
|
|
bool SerialImpl::setStopbits(StopBits stopbits)
|
|
{
|
|
return stopbits == StopBits::One;
|
|
}
|
|
|
|
FlowControl SerialImpl::getFlowcontrol() const
|
|
{
|
|
return _flowcontrol;
|
|
}
|
|
|
|
bool SerialImpl::setFlowcontrol(FlowControl flowcontrol)
|
|
{
|
|
return flowcontrol == FlowControl::Disabled;
|
|
}
|
|
|
|
bool SerialImpl::getSingleWireMode() const
|
|
{
|
|
return _single_wire_mode;
|
|
}
|
|
|
|
bool SerialImpl::setSingleWireMode()
|
|
{
|
|
#if defined(TIOCSSINGLEWIRE)
|
|
|
|
if (_open) {
|
|
ioctl(_serial_fd, TIOCSSINGLEWIRE, SER_SINGLEWIRE_ENABLED);
|
|
}
|
|
|
|
_single_wire_mode = true;
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif // TIOCSSINGLEWIRE
|
|
}
|
|
|
|
bool SerialImpl::getSwapRxTxMode() const
|
|
{
|
|
return _swap_rx_tx_mode;
|
|
}
|
|
|
|
bool SerialImpl::setSwapRxTxMode()
|
|
{
|
|
#if defined(TIOCSSWAP)
|
|
|
|
if (_open) {
|
|
ioctl(_serial_fd, TIOCSSWAP, SER_SWAP_ENABLED);
|
|
}
|
|
|
|
_swap_rx_tx_mode = true;
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif // TIOCSSWAP
|
|
}
|
|
|
|
bool SerialImpl::getInvertedMode() const
|
|
{
|
|
return _inverted_mode;
|
|
}
|
|
|
|
bool SerialImpl::setInvertedMode(bool enable)
|
|
{
|
|
#if defined(TIOCSINVERT)
|
|
|
|
if (_open) {
|
|
if (enable) {
|
|
ioctl(_serial_fd, TIOCSINVERT, SER_INVERT_ENABLED_RX | SER_INVERT_ENABLED_TX);
|
|
|
|
} else {
|
|
ioctl(_serial_fd, TIOCSINVERT, 0);
|
|
}
|
|
}
|
|
|
|
_inverted_mode = enable;
|
|
return true;
|
|
#else
|
|
return _inverted_mode == enable;
|
|
#endif // TIOCSINVERT
|
|
}
|
|
|
|
} // namespace device
|