mirror of
https://github.com/bdring/Grbl_Esp32.git
synced 2025-09-02 10:53:01 +02:00
Implemented most of the Uart functionality as a proof-of-principle. Not tested or being used; this is mainly for checking if important parts are missing in the api.
This commit is contained in:
@@ -116,7 +116,7 @@ void run_once() {
|
||||
// This can exit on a system abort condition, in which case run_once()
|
||||
// is re-executed by an enclosing loop.
|
||||
protocol_main_loop();
|
||||
} catch (AssertionFailed ex) {
|
||||
} catch (const AssertionFailed& ex) {
|
||||
// This means something is terribly broken:
|
||||
grbl_sendf(CLIENT_ALL, "Critical error: %s", ex.stackTrace.c_str());
|
||||
}
|
||||
|
@@ -8,6 +8,9 @@
|
||||
|
||||
#if defined PIN_DEBUG && defined ESP32
|
||||
# include "Pins/DebugPinDetail.h"
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
# include "Grbl.h" // grbl_sendf
|
||||
#endif
|
||||
|
||||
@@ -125,7 +128,7 @@ Pin Pin::create(const String& str) {
|
||||
}
|
||||
}
|
||||
|
||||
} catch (AssertionFailed& ex) { // We shouldn't get here under normal circumstances.
|
||||
} catch (const AssertionFailed& ex) { // We shouldn't get here under normal circumstances.
|
||||
#ifdef PIN_DEBUG
|
||||
# ifdef ESP32
|
||||
grbl_sendf(CLIENT_ALL, "Failed. Details: %s\r\n", ex.stackTrace.c_str());
|
||||
|
33
Grbl_Esp32/src/PinUsers/LimitedResource.h
Normal file
33
Grbl_Esp32/src/PinUsers/LimitedResource.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace PinUsers {
|
||||
/// <summary>
|
||||
/// Helper class that to manage 'Count' resources. Resources can be claimed and released at
|
||||
/// any time. This helper class keeps track of a bitmap that holds the resources.
|
||||
/// </summary>
|
||||
template <int Count>
|
||||
class LimitedResource {
|
||||
static_assert(Count > 0, "Resource count cannot be 0 or negative.");
|
||||
|
||||
// We do +32 instead of +31 because 0 should round to 1. Worse case we loose 1 uint.
|
||||
uint32_t _claimed[(Count + 31) / 32];
|
||||
|
||||
public:
|
||||
inline void forceClaim(int index) { _claimed[index / 32] |= (1 << (index % 32)); }
|
||||
|
||||
inline int tryClaim() {
|
||||
for (int i = 0; i < Count; ++i) {
|
||||
auto bit = _claimed[i / 32] & (uint32_t(1) << (i % 32));
|
||||
if (bit == 0) {
|
||||
_claimed[i / 32] |= (uint32_t(1) << (i % 32));
|
||||
return bit;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline void release(int index) { _claimed[index / 32] &= ~(uint32_t(1) << (index % 32)); }
|
||||
};
|
||||
}
|
107
Grbl_Esp32/src/PinUsers/Uart.cpp
Normal file
107
Grbl_Esp32/src/PinUsers/Uart.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#include "Uart.h"
|
||||
|
||||
#include "../Pin.h"
|
||||
#include "../Pins/PinOptionsParser.h"
|
||||
#include "../Assert.h"
|
||||
#include "LimitedResource.h"
|
||||
#include <driver/uart.h>
|
||||
|
||||
namespace PinUsers {
|
||||
|
||||
// Native UART in the ESP32
|
||||
class NativeUart : public UartDetail {
|
||||
static LimitedResource<2>& UartResources() {
|
||||
// The ESP32 chip has three UART controllers (UART0, UART1, and UART2), but
|
||||
// UART0 is used for Serial0. In other words, we can only make 1 and 2 available.
|
||||
|
||||
static LimitedResource<2> instances_;
|
||||
return instances_;
|
||||
}
|
||||
|
||||
Pin tx_;
|
||||
Pin rx_;
|
||||
Pin rts_;
|
||||
|
||||
uart_port_t uartPort_;
|
||||
|
||||
public:
|
||||
NativeUart(Pin tx, Pin rx, Pin rts, Pins::PinOptionsParser& options, Pins::PinOptionsParser& userOptions) :
|
||||
tx_(tx), rx_(rx), rts_(rts), uartPort_(UART_NUM_MAX) {
|
||||
// Validate if claiming the resources will err:
|
||||
Assert(tx.capabilities().has(Pin::Capabilities::Native | Pin::Capabilities::UART | Pin::Capabilities::Output));
|
||||
Assert(rx.capabilities().has(Pin::Capabilities::Native | Pin::Capabilities::UART | Pin::Capabilities::Input));
|
||||
Assert(rts.capabilities().has(Pin::Capabilities::Native | Pin::Capabilities::UART | Pin::Capabilities::Output));
|
||||
|
||||
// Iterate options:
|
||||
uart_config_t uart_config = { 0 };
|
||||
int bufferSize = 128;
|
||||
for (auto opt : options) {
|
||||
// if (opt.is("baud")) { baudRate = opt.valueInt(); }
|
||||
// if (opt.is("mode")) { mode = opt.valueString(); /* 8N1 etc */ }
|
||||
// if (opt.is("bufsize")) { mode = opt.valueString(); /* 128 etc */ }
|
||||
// if (opt.is("protocol")) { protocol= opt.valueString(); /* RS485 etc */ }
|
||||
// etc...
|
||||
}
|
||||
for (auto opt : userOptions) {
|
||||
// if (opt.is("baud")) { baudRate = opt.valueInt(); }
|
||||
// if (opt.is("mode")) { mode = opt.valueString(); /* 8N1 etc */ }
|
||||
// etc...
|
||||
}
|
||||
|
||||
int uartIndex = UartResources().tryClaim();
|
||||
Assert(uartIndex >= 0);
|
||||
uartPort_ = static_cast<uart_port_t>(uartIndex + 1);
|
||||
|
||||
// We have everything we need. Set it up:
|
||||
|
||||
auto txn = tx_.getNative(Pin::Capabilities::UART | Pin::Capabilities::Output);
|
||||
auto rxn = rx_.getNative(Pin::Capabilities::UART | Pin::Capabilities::Output);
|
||||
auto rtsn = rts_.getNative(Pin::Capabilities::UART | Pin::Capabilities::Output);
|
||||
|
||||
Assert(uart_param_config(uartPort_, &uart_config) == ESP_OK, "Uart parameter set failed.");
|
||||
Assert(uart_set_pin(uartPort_, txn, rxn, rtsn, UART_PIN_NO_CHANGE) == ESP_OK, "Uart parameter set failed.");
|
||||
Assert(uart_driver_install(uartPort_, bufferSize * 2, 0, 0, NULL, 0) == ESP_OK, "Uart driver install failed.");
|
||||
|
||||
// TODO FIXME: We should set the UART mode somewhere better suited than here:
|
||||
if (uart_set_mode(uartPort_, UART_MODE_RS485_HALF_DUPLEX) != ESP_OK) {
|
||||
uart_driver_delete(uartPort_);
|
||||
uartPort_ = UART_NUM_MAX;
|
||||
|
||||
Assert(false, "UART set mode failed");
|
||||
}
|
||||
}
|
||||
|
||||
int write(const uint8_t* ptr, int bytes) override {
|
||||
// Flush the UART and write the data:
|
||||
uart_flush(uartPort_);
|
||||
return uart_write_bytes(uartPort_, reinterpret_cast<const char*>(ptr), bytes);
|
||||
}
|
||||
|
||||
int read(uint8_t* ptr, int bytes, int ticksToWait) override {
|
||||
// Read the response
|
||||
return uart_read_bytes(uartPort_, ptr, bytes, ticksToWait);
|
||||
}
|
||||
|
||||
~NativeUart() override {
|
||||
// Tear down the uart, give back all resources.
|
||||
if (uartPort_ != UART_NUM_MAX) {
|
||||
uart_driver_delete(uartPort_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Uart::Uart(Pin tx, Pin rx, Pin rts, String config, String userConfig) {
|
||||
Pins::PinOptionsParser configParser(config.begin(), config.end());
|
||||
Pins::PinOptionsParser userConfigParser(userConfig.begin(), userConfig.end());
|
||||
|
||||
// Decide on the RX pin what to do:
|
||||
if (rx.capabilities().has(Pin::Capabilities::Native))
|
||||
{
|
||||
this->_detail = new NativeUart(tx, rx, rts, configParser, userConfigParser);
|
||||
}
|
||||
else {
|
||||
Assert(false, "Pin is not supported for UART.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
125
Grbl_Esp32/src/PinUsers/Uart.h
Normal file
125
Grbl_Esp32/src/PinUsers/Uart.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Pin.h"
|
||||
#include <WString.h>
|
||||
#include "../Assert.h"
|
||||
|
||||
namespace PinUsers {
|
||||
class UartDetail {
|
||||
public:
|
||||
virtual int write(const uint8_t* ptr, int bytes) = 0;
|
||||
virtual int read(uint8_t* ptr, int bytes, int ticksToWait) = 0;
|
||||
|
||||
virtual ~UartDetail() {}
|
||||
};
|
||||
|
||||
class Uart {
|
||||
Pin _tx;
|
||||
Pin _rx;
|
||||
Pin _rts;
|
||||
|
||||
UartDetail* _detail;
|
||||
|
||||
public:
|
||||
Uart() : _tx(Pin::UNDEFINED), _rx(Pin::UNDEFINED), _rts(Pin::UNDEFINED), _detail(nullptr) {}
|
||||
Uart(Pin tx, Pin rx, Pin rts, String config, String userConfig);
|
||||
|
||||
// TODO FIXME: If _detail is null is currently asserted. We can also just 'do nothing', which might
|
||||
// be easier in the application.
|
||||
|
||||
// Writes a buffer to the uart. Returns the number of _bytes_ written
|
||||
template <typename T>
|
||||
int writePartial(const T& buffer, int byteOffset = 0) {
|
||||
writePartial(&buffer, 1, byteOffset);
|
||||
}
|
||||
|
||||
// Writes a buffer to the uart. Returns the number of _bytes_ written
|
||||
template <typename T>
|
||||
int writePartial(const T* bufferArray, int numberElements, int byteOffset = 0) {
|
||||
Assert(_detail != nullptr, "Uart is not initialized; cannot write to it.");
|
||||
auto byteBuf = reinterpret_cast<const uint8_t*>(bufferArray);
|
||||
return _detail->write(byteBuf + byteOffset, sizeof(T) * numberElements - byteOffset);
|
||||
}
|
||||
|
||||
// Writes a buffer to the uart. This continues while it can write. If writing succeeded, true is
|
||||
// returned, otherwise false.
|
||||
template <typename T>
|
||||
bool write(const T& buffer) {
|
||||
return write(&buffer, 1);
|
||||
}
|
||||
|
||||
// Writes a buffer to the uart. This continues while it can write. If writing succeeded, true is
|
||||
// returned, otherwise false.
|
||||
template <typename T>
|
||||
bool write(const T* buffer, int numberElements) {
|
||||
auto index = 0;
|
||||
auto limit = sizeof(T) * numberElements;
|
||||
while (index < limit) {
|
||||
int size = writePartial(buffer, numberElements, index);
|
||||
index += size;
|
||||
|
||||
if (size == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reads a buffer from the uart. If ticks elapsed, stops reading. Returns the number of bytes
|
||||
// that was read.
|
||||
template <typename T>
|
||||
int readPartial(T* bufferArray, int numberElements, int offset = 0, int ticksToWait = 0) {
|
||||
Assert(_detail != nullptr, "Uart is not initialized; cannot write to it.");
|
||||
|
||||
auto byteArray = reinterpret_cast<uint8_t*>(bufferArray) + offset;
|
||||
auto bytes = sizeof(T) * numberElements - offset;
|
||||
return _detail->read(byteArray, bytes, ticksToWait);
|
||||
}
|
||||
|
||||
// Reads a buffer from the uart. If ticks elapsed, stops reading. Returns the number of bytes
|
||||
// that was read.
|
||||
template <typename T>
|
||||
int readPartial(T& buffer, int offset = 0, int ticksToWait = 0) {
|
||||
return readPartial(&buffer, 1, offset, ticksToWait);
|
||||
}
|
||||
|
||||
// Reads a buffer from the uart within the given time. The return value is 'true' if this succeeded
|
||||
// and 'false' if it failed or gave a partial result.
|
||||
template <typename T>
|
||||
bool readOnce(T* bufferArray, int numberElements, int ticksToWait = 0) {
|
||||
auto bytesRead = readPartial(bufferArray, numberElements, 0, ticksToWait);
|
||||
return bytesRead == (numberElements * sizeof(T));
|
||||
}
|
||||
|
||||
// Reads a buffer from the uart within the given time. The return value is 'true' if this succeeded
|
||||
// and 'false' if it failed or gave a partial result.
|
||||
template <typename T>
|
||||
bool readOnce(T& buffer, int ticksToWait = 0) {
|
||||
return readOnce(&buffer, 1, ticksToWait);
|
||||
}
|
||||
|
||||
// Reads a buffer from the uart. While data is returned, this keeps on reading until the buffer is
|
||||
// full. If no data is returned anymore, or if the buffer is full, this returns 'true' if successul,
|
||||
// or 'false' otherwise
|
||||
template <typename T>
|
||||
bool readBlocking(T* bufferArray, int numberElements, int ticksToWait = 0) {
|
||||
int offset = 0;
|
||||
int limit = sizeof(T) * numberElements;
|
||||
while (offset < limit) {
|
||||
auto bytesRead = readPartial(bufferArray, numberElements, offset, ticksToWait);
|
||||
if (bytesRead == 0) { break; }
|
||||
offset += bytesRead;
|
||||
}
|
||||
return offset == limit;
|
||||
}
|
||||
|
||||
// Reads a buffer from the uart within the given time. The return value is 'true' if this succeeded
|
||||
// and 'false' if it failed or gave a partial result.
|
||||
template <typename T>
|
||||
bool readBlocking(T& buffer, int offset = 0, int ticksToWait = 0) {
|
||||
return readBlocking(&buffer, 1, ticksToWait);
|
||||
}
|
||||
|
||||
inline ~Uart() { delete _detail; }
|
||||
};
|
||||
}
|
@@ -80,7 +80,7 @@ void TestFactory::runAll() {
|
||||
|
||||
current->run();
|
||||
printf("Passed.\r\n");
|
||||
} catch (AssertionFailed& ex) {
|
||||
} catch (const AssertionFailed& ex) {
|
||||
setColor(12);
|
||||
printf("FAILED!\r\n");
|
||||
printf(ex.stackTrace.c_str());
|
||||
|
Reference in New Issue
Block a user