From 72a30ea5f1d69653e96a24493b46b19ab0323fe7 Mon Sep 17 00:00:00 2001 From: susanw1 Date: Thu, 9 Nov 2023 15:38:14 +0000 Subject: [PATCH] [#110] More Uart channel updates, with UartChannel example --- .../00xx-base-modules/000x-core.yaml | 2 +- .../00xx-base-modules/007x-uart.yaml | 10 +- .../ZscriptDefaultParameters.hpp | 47 ++++++---- .../ZscriptFullInclude.hpp | 2 +- .../i2c-module/channels/I2cChannel.hpp | 40 ++++---- .../i2c-module/commands/I2cChannelInfo.hpp | 6 +- .../i2c-module/commands/I2cChannelSetup.hpp | 8 +- .../c++/arduino/uart-module/UartModule.hpp | 4 +- .../uart-module/channels/UartChannel.hpp | 20 ++-- .../commands/UartCapabilitiesCommand.hpp | 54 ++++------- .../uart-module/commands/UartChannelInfo.hpp | 20 ++-- .../uart-module/commands/UartChannelSetup.hpp | 18 ++-- .../arduino/uart-module/commands/UartUtil.hpp | 27 ++++++ .../I2cChannelDemo/I2cChannelDemo.ino | 2 +- .../I2cChannelDemo/ZscriptParameters.hpp | 46 ++++++---- .../UartChannelDemo/UartChannelDemo.ino | 12 +++ .../UartChannelDemo/ZscriptParameters.hpp | 91 +++++++++++++++++++ .../main/templates/CppCommandKeyDefs.mustache | 13 +-- .../src/main/c++/zscript/ZscriptIncludes.hpp | 15 +++ .../execution/ZscriptCommandContext.hpp | 90 ++++++++++++++++-- .../modules/core/ChannelInfoCommand.hpp | 18 ++-- 21 files changed, 386 insertions(+), 159 deletions(-) create mode 100644 receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartUtil.hpp create mode 100644 receivers/native/arduino/src/main/c++/examples/UartChannelDemo/UartChannelDemo.ino create mode 100644 receivers/native/arduino/src/main/c++/examples/UartChannelDemo/ZscriptParameters.hpp diff --git a/model/standard-module-definitions/src/main/resources/zscript-datamodel/00xx-base-modules/000x-core.yaml b/model/standard-module-definitions/src/main/resources/zscript-datamodel/00xx-base-modules/000x-core.yaml index 7db72e428..bdd8ff56c 100644 --- a/model/standard-module-definitions/src/main/resources/zscript-datamodel/00xx-base-modules/000x-core.yaml +++ b/model/standard-module-definitions/src/main/resources/zscript-datamodel/00xx-base-modules/000x-core.yaml @@ -189,7 +189,7 @@ commands: '@type': number required: no responseFields: - - key: C + - key: N name: channelCount description: the number of channels the device has typeDefinition: diff --git a/model/standard-module-definitions/src/main/resources/zscript-datamodel/00xx-base-modules/007x-uart.yaml b/model/standard-module-definitions/src/main/resources/zscript-datamodel/00xx-base-modules/007x-uart.yaml index 99443ceb8..4c1a2ebed 100644 --- a/model/standard-module-definitions/src/main/resources/zscript-datamodel/00xx-base-modules/007x-uart.yaml +++ b/model/standard-module-definitions/src/main/resources/zscript-datamodel/00xx-base-modules/007x-uart.yaml @@ -2,6 +2,12 @@ name: Uart id: 7 version: 0.0.1 description: UART Connectivity for Serial communication +longDescription: > + This module supports configuring and using multiple device UARTs, either as plain p2p data send/receive connection, + or as a Zscript channel (for receiving commands from upstream), or as a downstream address connection. + + It supports two mechanisms for baud-rate configuration: a menu set of options (0-n), or actual frequency (using the big + field). commands: - name: capabilities @@ -75,7 +81,7 @@ commands: required: yes - key: + name: baudRate - description: the baud rate option requested in Hz (or maximum rate supported if not given) + description: the baud rate menu option requested in Hz (or maximum rate supported if not given) typeDefinition: '@type': bytes required: yes @@ -320,7 +326,7 @@ commands: '@type': number required: yes - key: F - name: frequency + name: frequencySelection description: which frequency option should be selected from the 'menu' typeDefinition: '@type': number diff --git a/receivers/native/arduino/src/main/c++/arduino-converter-files/ZscriptDefaultParameters.hpp b/receivers/native/arduino/src/main/c++/arduino-converter-files/ZscriptDefaultParameters.hpp index 9aa833a23..c60b063ae 100644 --- a/receivers/native/arduino/src/main/c++/arduino-converter-files/ZscriptDefaultParameters.hpp +++ b/receivers/native/arduino/src/main/c++/arduino-converter-files/ZscriptDefaultParameters.hpp @@ -55,33 +55,42 @@ class ZscriptParams { return (uint16_t) millis(); } typedef uint8_t tokenBufferSize_t; + static constexpr uint8_t lockByteCount = 1; - static const uint8_t tcpChannelCount = 1; - static const uint16_t tcpLocalPort = 23; - static const uint8_t tcpBufferSize = 128; + static constexpr uint8_t pinCount = 21; - static const uint8_t udpChannelCount = 1; - static const uint16_t udpLocalPort = 8888; - static const uint8_t udpBufferSize = 128; + static constexpr uint16_t i2cBufferSize = 128; + static constexpr uint16_t i2cChannelOutputBufferSize = 32; + static constexpr uint16_t i2cAddressingReadBlockLength = 8; + static constexpr uint16_t i2cAlertInPin = 2; + static constexpr uint16_t i2cAlertOutPin = 9; + static constexpr uint8_t i2cChannelAddress = 0x60; - static const uint8_t lockByteCount = 1; - static const uint16_t serialBufferSize = 128; - static const uint16_t i2cBufferSize = 128; + static constexpr uint16_t uartCount = 1; + static constexpr uint16_t uartRxBufferSize = 0; + static constexpr uint16_t uartTxBufferSize = 0; + static constexpr uint32_t uartSupportedFreqs[] = {9600, 115200}; + static constexpr uint16_t uartChannelCount = 1; + static constexpr uint16_t uartChannelInterface = 0; + static constexpr uint16_t uartChannelBufferSize = 128; - static const uint16_t i2cChannelOutputBufferSize = 32; - static const uint16_t I2cAddressingReadBlockLength = 8; - static const uint16_t i2cAlertInPin = 2; - static const uint16_t i2cAlertOutPin = 9; - static const uint8_t i2cChannelAddress = 0x60; - static const uint16_t nonActivatedChannelTimeout = 5000; + static constexpr uint8_t servoCount = 1; + //static constexpr uint8_t servoPins[1]; - static const uint8_t pinCount = 21; + static constexpr uint8_t udpChannelCount = 1; + static constexpr uint16_t udpLocalPort = 8888; + static constexpr uint8_t udpBufferSize = 128; - static const uint8_t servoCount = 1; - //static const uint8_t servoPins[1]; + static constexpr uint8_t tcpChannelCount = 1; + static constexpr uint16_t tcpLocalPort = 23; + static constexpr uint8_t tcpBufferSize = 128; + + static constexpr uint16_t nonActivatedChannelTimeout = 5000; }; -//const uint8_t ZscriptParams::servoPins[1] = {9}; + +constexpr uint32_t ZscriptParams::uartSupportedFreqs[]; +//constexpr uint8_t ZscriptParams::servoPins[1]; #endif /* SRC_MAIN_CPP_ARDUINO_CONVERTER_FILES_ZSCRIPTDEFAULTPARAMETERS_HPP_ */ diff --git a/receivers/native/arduino/src/main/c++/arduino-converter-files/ZscriptFullInclude.hpp b/receivers/native/arduino/src/main/c++/arduino-converter-files/ZscriptFullInclude.hpp index 24873e14b..32bb8548c 100644 --- a/receivers/native/arduino/src/main/c++/arduino-converter-files/ZscriptFullInclude.hpp +++ b/receivers/native/arduino/src/main/c++/arduino-converter-files/ZscriptFullInclude.hpp @@ -90,7 +90,7 @@ class ArduinoZscriptBasicSetup { + ZscriptParams::udpChannelCount #endif #ifdef ZSCRIPT_HAVE_TCP_CHANNEL - +ZscriptParams::tcpChannelCount + + ZscriptParams::tcpChannelCount #endif ]; #endif diff --git a/receivers/native/arduino/src/main/c++/arduino/i2c-module/channels/I2cChannel.hpp b/receivers/native/arduino/src/main/c++/arduino/i2c-module/channels/I2cChannel.hpp index 3b72b739d..3aeae13a2 100644 --- a/receivers/native/arduino/src/main/c++/arduino/i2c-module/channels/I2cChannel.hpp +++ b/receivers/native/arduino/src/main/c++/arduino/i2c-module/channels/I2cChannel.hpp @@ -227,26 +227,26 @@ class I2cChannel : public ZscriptChannel { } } - void channelInfo(ZscriptCommandContext ctx) { - CommandOutStream out = ctx.getOutStream(); - out.writeField('N', 0); - out.writeField('M', 0x5); - } - - void channelSetup(ZscriptCommandContext ctx) { - uint16_t addr; - if (ctx.getField('A', &addr)) { - if (addr >= 128) { - ctx.status(ResponseStatus::VALUE_OUT_OF_RANGE); - return; - } - out.setAddr((uint8_t) addr); - } - if (ctx.hasField('P')) { - uint8_t index = this->parser.getChannelIndex(); - PersistenceSystem::writeSection(PersistenceSystem::getNotifChannelIdOffset(), 1, &index); - } - } +// void channelInfo(ZscriptCommandContext ctx) { +// CommandOutStream ctxOut = ctx.getOutStream(); +// ctxOut.writeField('N', 0); +// ctxOut.writeField('M', 0x5); +// } +// +// void channelSetup(ZscriptCommandContext ctx) { +// uint16_t addr; +// if (ctx.getField('A', &addr)) { +// if (addr >= 128) { +// ctx.status(ResponseStatus::VALUE_OUT_OF_RANGE); +// return; +// } +// out.setAddr((uint8_t) addr); +// } +// if (ctx.hasField('P')) { +// uint8_t index = this->parser.getChannelIndex(); +// PersistenceSystem::writeSection(PersistenceSystem::getNotifChannelIdOffset(), 1, &index); +// } +// } }; diff --git a/receivers/native/arduino/src/main/c++/arduino/i2c-module/commands/I2cChannelInfo.hpp b/receivers/native/arduino/src/main/c++/arduino/i2c-module/commands/I2cChannelInfo.hpp index 9500be10a..c40f501c2 100644 --- a/receivers/native/arduino/src/main/c++/arduino/i2c-module/commands/I2cChannelInfo.hpp +++ b/receivers/native/arduino/src/main/c++/arduino/i2c-module/commands/I2cChannelInfo.hpp @@ -33,9 +33,9 @@ class ZscriptI2cChannelInfoCommand { static void execute(ZscriptCommandContext ctx) { - uint16_t channel; - if (ctx.getField(ParamChannel__C, &channel)) { - if (channel != 0) { + uint16_t channelIndex; + if (ctx.getField(ParamChannel__C, &channelIndex)) { + if (channelIndex != 0) { ctx.status(ResponseStatus::VALUE_OUT_OF_RANGE); return; } diff --git a/receivers/native/arduino/src/main/c++/arduino/i2c-module/commands/I2cChannelSetup.hpp b/receivers/native/arduino/src/main/c++/arduino/i2c-module/commands/I2cChannelSetup.hpp index 8a47433ca..6ac238d23 100644 --- a/receivers/native/arduino/src/main/c++/arduino/i2c-module/commands/I2cChannelSetup.hpp +++ b/receivers/native/arduino/src/main/c++/arduino/i2c-module/commands/I2cChannelSetup.hpp @@ -29,16 +29,16 @@ class ZscriptI2cChannelSetupCommand { static void execute(ZscriptCommandContext ctx) { - uint16_t channel; - if (ctx.getField(ParamChannel__C, &channel)) { - if (channel != 0) { + uint16_t channelIndex; + if (ctx.getField(ParamChannel__C, &channelIndex)) { + if (channelIndex != 0) { ctx.status(ResponseStatus::VALUE_OUT_OF_RANGE); return; } } uint16_t address; if (ctx.getField(ParamAddress__A, &address)) { - if (channel > 0x80) { + if (address > 0x80) { ctx.status(ResponseStatus::VALUE_OUT_OF_RANGE); return; } diff --git a/receivers/native/arduino/src/main/c++/arduino/uart-module/UartModule.hpp b/receivers/native/arduino/src/main/c++/arduino/uart-module/UartModule.hpp index a8ade1c39..6d88b2c90 100644 --- a/receivers/native/arduino/src/main/c++/arduino/uart-module/UartModule.hpp +++ b/receivers/native/arduino/src/main/c++/arduino/uart-module/UartModule.hpp @@ -52,9 +52,9 @@ class UartModule : public ZscriptModule { static void setup() { #ifdef ZSCRIPT_HAVE_UART_CHANNEL channel.setup(); - channel.setAddress(ZscriptParams::i2cChannelAddress); + channel.setBananaAddress(ZscriptParams::i2cChannelAddress); #else - Serial.begin(9600); + Serial.begin(ZP::uartSupportedFreqs[0]); #endif } diff --git a/receivers/native/arduino/src/main/c++/arduino/uart-module/channels/UartChannel.hpp b/receivers/native/arduino/src/main/c++/arduino/uart-module/channels/UartChannel.hpp index dc8feaa8b..23360c685 100644 --- a/receivers/native/arduino/src/main/c++/arduino/uart-module/channels/UartChannel.hpp +++ b/receivers/native/arduino/src/main/c++/arduino/uart-module/channels/UartChannel.hpp @@ -18,12 +18,12 @@ namespace Zscript { template -class ZscriptSerialOutStream : public AbstractOutStream { +class ZscriptUartOutStream : public AbstractOutStream { private: bool openB = false; public: - ZscriptSerialOutStream() { + ZscriptUartOutStream() { } void open(uint8_t source) { @@ -56,11 +56,11 @@ class ZscriptSerialOutStream : public AbstractOutStream { template class UartChannel : public ZscriptChannel { - ZscriptSerialOutStream out; + ZscriptUartOutStream out; GenericCore::TokenRingBuffer tBuffer; ZscriptTokenizer tokenizer; - uint8_t buffer[ZP::serialBufferSize]; + uint8_t buffer[ZP::uartChannelBufferSize]; uint8_t tmp = 0; bool usingTmp = false; @@ -70,7 +70,7 @@ class UartChannel : public ZscriptChannel { } UartChannel() : - ZscriptChannel(&out, &tBuffer, 0x7, true), tBuffer(buffer, ZP::serialBufferSize), tokenizer(tBuffer.getWriter(), 2) { + ZscriptChannel(&out, &tBuffer, 0x7, true), tBuffer(buffer, ZP::uartChannelBufferSize), tokenizer(tBuffer.getWriter(), 2) { } bool setupStartupNotificationChannel() { @@ -78,10 +78,12 @@ class UartChannel : public ZscriptChannel { } void channelInfo(ZscriptCommandContext ctx) { - CommandOutStream out = ctx.getOutStream(); - out.writeField('N', 0); - out.writeField('M', 0x7); - out.writeField('I', 0); + CommandOutStream ctxOut = ctx.getOutStream(); + // RespChannelCount__N + ctxOut.writeField('N', 0); + // ?? + ctxOut.writeField('M', 0x7); + ctxOut.writeField('I', 0); } void channelSetup(ZscriptCommandContext ctx) { diff --git a/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartCapabilitiesCommand.hpp b/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartCapabilitiesCommand.hpp index 3e66268df..a84828b5a 100644 --- a/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartCapabilitiesCommand.hpp +++ b/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartCapabilitiesCommand.hpp @@ -9,6 +9,8 @@ #define SRC_MAIN_CPP_ARDUINO_UART_MODULE_COMMANDS_ZSCRIPTUARTCAPABILITIESCOMMAND_HPP_ #include +#include "UartUtil.hpp" +#include #include #define COMMAND_EXISTS_0070 EXISTENCE_MARKER_UTIL @@ -18,56 +20,36 @@ namespace Zscript { namespace uart_module { namespace cmd_capabilities { -using namespace uart_module; - template class ZscriptUartCapabilitiesCommand { public: static constexpr uint8_t CODE = 0x0; - static constexpr uint8_t ReqFrequencySelection__F = 'F'; + static void execute(ZscriptCommandContext ctx) { + CommandOutStream out = ctx.getOutStream(); - static constexpr uint8_t RespCommandsSet__C = 'C'; - static constexpr uint8_t RespNotificationsSupported__N = 'N'; - /** Flag (Optional): whether addressing via the serial interface is available */ - static constexpr uint8_t RespAddressingSupported__A = 'A'; - /** Number (Required): how many interfaces are available */ - static constexpr uint8_t RespInterfaceCount__I = 'I'; - /** Number (Optional): how many frequencies are supported as a 'menu' of frequencies - if not present, no preset frequencies are supported */ - static constexpr uint8_t RespFrequenciesSupported__F = 'F'; - /** Bitset (Required): a set of more specific capabilities of the module */ - static constexpr uint8_t RespBitsetCapabilities__B = 'B'; - /** Number (Required): how many bytes of buffer have been assigned for received data */ - static constexpr uint8_t RespRxBufferSize__R = 'R'; - /** Number (Required): how many bytes of buffer have been assigned for transmitted data */ - static constexpr uint8_t RespTxBufferSize__T = 'T'; - /** Bytes (Required): the baud rate option requested in Hz (or maximum rate supported if not given) */ - static constexpr uint8_t RespBaudRate__Bytes = '+'; + constexpr uint8_t freqCount = sizeof(ZP::uartSupportedFreqs) / sizeof(ZP::uartSupportedFreqs[0]); + uint16_t freqIndex; + if (!ctx.getFieldCheckLimit(ReqFrequencySelection__F, freqCount, freqCount - 1, &freqIndex)) { + return; + } + + UartUtil::writeFrequencySelection(out, freqIndex); -// static constexpr char RespCommands__C = 'C'; -// static constexpr char RespNotificationsSupported__N = 'N'; -// static constexpr char RespAddressingSupported__A = 'A'; -// static constexpr char RespInterfaceCount__I = 'I'; -// static constexpr char RespFrequenciesSupported__F = 'F'; -// static constexpr char RespBitsetCapabilities__B = 'B'; -// - static void execute(ZscriptCommandContext ctx) { // implements just a single Serial port at this time. Should be expanded to more... - CommandOutStream out = ctx.getOutStream(); out.writeField(RespCommandsSet__C, MODULE_CAPABILITIES(007)); - out.writeField(RespInterfaceCount__I, 1); - out.writeField(RespFrequenciesSupported__F, 1); -#ifdef ZSCRIPT_HAVE_UART_MODULE - // out.writeField(RespBitsetCapabilities__B, RespBitsetCapabilities__LowSpeedSupported | RespBitsetCapabilities__SmBusAddressResolution); -#else - // out.writeField(RespBitsetCapabilities__B, RespBitsetCapabilities__LowSpeedSupported); -#endif + out.writeField(RespInterfaceCount__I, ZP::uartCount); + out.writeField(RespFrequenciesSupported__F, freqCount); + out.writeField(RespBitsetCapabilities__B, static_cast(RespBitsetCapabilities_Values::parityOn_field) + | static_cast(RespBitsetCapabilities_Values::doubleStop_field)); + out.writeField(RespRxBufferSize__R, ZP::uartRxBufferSize); + out.writeField(RespTxBufferSize__T, ZP::uartTxBufferSize); #ifdef ZSCRIPT_UART_SUPPORT_NOTIFICATIONS out.writeField(RespNotificationsSupported__N, 0); +#endif #ifdef ZSCRIPT_SUPPORT_ADDRESSING out.writeField(RespAddressingSupported__A, 0); -#endif #endif } diff --git a/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartChannelInfo.hpp b/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartChannelInfo.hpp index 3aa23162a..294f7f1cb 100644 --- a/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartChannelInfo.hpp +++ b/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartChannelInfo.hpp @@ -24,23 +24,25 @@ class UartModule; namespace uart_module { namespace cmd_channel_info { -using namespace uart_module; - - template class ZscriptUartChannelInfoCommand { public: static constexpr uint8_t CODE = 0xc; static void execute(ZscriptCommandContext ctx) { - uint16_t channel; - if (ctx.getField(ReqChannel__C, &channel)) { - if (channel != 0) { - ctx.status(ResponseStatus::VALUE_OUT_OF_RANGE); - return; - } + uint16_t localChannelIndex; + if (!ctx.getFieldCheckLimit(ReqChannel__C, Zscript::zscript.getChannelCount(), ctx.getChannelIndex(), &localChannelIndex)) { + return; } + + constexpr uint8_t freqCount = sizeof(ZP::uartSupportedFreqs) / sizeof(ZP::uartSupportedFreqs[0]); + uint16_t freqIndex; + if (!ctx.getFieldCheckLimit(ReqFrequencySelection__F, freqCount, freqCount - 1, &freqIndex)) { + return; + } + CommandOutStream out = ctx.getOutStream(); + // Just one UART channel supported currently out.writeField(RespChannelCount__N, 1); out.writeField(RespChannel__C, UartModule::channel.getParser()->getChannelIndex()); out.writeField(RespInterface__I, 0); diff --git a/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartChannelSetup.hpp b/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartChannelSetup.hpp index ab55e8774..af83d01c8 100644 --- a/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartChannelSetup.hpp +++ b/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartChannelSetup.hpp @@ -24,21 +24,23 @@ class UartModule; namespace uart_module { namespace cmd_channel_setup { -using namespace uart_module; - template class ZscriptUartChannelSetupCommand { public: static constexpr uint8_t CODE = 0xd; static void execute(ZscriptCommandContext ctx) { - uint16_t channel; - if (ctx.getField(ReqChannel__C, &channel)) { - if (channel != 0) { - ctx.status(ResponseStatus::VALUE_OUT_OF_RANGE); - return; - } + uint16_t channelIndex; + if (!ctx.getFieldCheckLimit(ReqChannel__C, Zscript::zscript.getChannelCount(), ctx.getChannelIndex(), &channelIndex)) { + return; + } + constexpr uint8_t freqCount = sizeof(ZP::uartSupportedFreqs) / sizeof(ZP::uartSupportedFreqs[0]); + uint16_t freqIndex; + if (!ctx.getFieldCheckLimit(ReqFrequencySelection__F, freqCount, freqCount - 1, &freqIndex)) { + return; } + + uint16_t address; // if (ctx.getField(ReqAddress__A, &address)) { // if (channel > 0x80) { diff --git a/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartUtil.hpp b/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartUtil.hpp new file mode 100644 index 000000000..979969e63 --- /dev/null +++ b/receivers/native/arduino/src/main/c++/arduino/uart-module/commands/UartUtil.hpp @@ -0,0 +1,27 @@ +/* + * Zscript Library - Command System for Microcontrollers) + * Copyright (c) 2022 Zscript team (Susan Witts, Alicia Witts) + * + * SPDX-License-Identifier: MIT + */ + +#ifndef SRC_MAIN_CPP_ARDUINO_UART_MODULE_COMMANDS_ZSCRIPTUARTUTIL_HPP_ +#define SRC_MAIN_CPP_ARDUINO_UART_MODULE_COMMANDS_ZSCRIPTUARTUTIL_HPP_ + + +namespace Zscript { + +template +class UartUtil { +public: + static void writeFrequencySelection(CommandOutStream out, uint8_t freqIndex) { + const uint32_t maxBaud = ZP::uartSupportedFreqs[freqIndex]; + uint8_t maxBaudBytes[4]{(maxBaud >> 24) & 0xff, (maxBaud >> 16) & 0xff, (maxBaud >> 8) & 0xff, (maxBaud) & 0xff}; + out.writeBigHex(maxBaudBytes, 4); + } + +}; + +} + +#endif /* SRC_MAIN_CPP_ARDUINO_UART_MODULE_COMMANDS_ZSCRIPTUARTUTIL_HPP_ */ diff --git a/receivers/native/arduino/src/main/c++/examples/I2cChannelDemo/I2cChannelDemo.ino b/receivers/native/arduino/src/main/c++/examples/I2cChannelDemo/I2cChannelDemo.ino index 4bd7477dc..630813776 100644 --- a/receivers/native/arduino/src/main/c++/examples/I2cChannelDemo/I2cChannelDemo.ino +++ b/receivers/native/arduino/src/main/c++/examples/I2cChannelDemo/I2cChannelDemo.ino @@ -2,7 +2,7 @@ #include void setup() { - Serial.begin(9600); +// Serial.begin(9600); ZscriptSetup.setup(); } diff --git a/receivers/native/arduino/src/main/c++/examples/I2cChannelDemo/ZscriptParameters.hpp b/receivers/native/arduino/src/main/c++/examples/I2cChannelDemo/ZscriptParameters.hpp index ece9cd83c..06296c319 100644 --- a/receivers/native/arduino/src/main/c++/examples/I2cChannelDemo/ZscriptParameters.hpp +++ b/receivers/native/arduino/src/main/c++/examples/I2cChannelDemo/ZscriptParameters.hpp @@ -24,12 +24,12 @@ //#define ZSCRIPT_SUPPORT_SCRIPT_SPACE #define ZSCRIPT_SUPPORT_NOTIFICATIONS -#define ZSCRIPT_SUPPORT_ADDRESSING - -#define ZSCRIPT_HAVE_PIN_MODULE -#define ZSCRIPT_PIN_SUPPORT_NOTIFICATIONS -#define ZSCRIPT_PIN_SUPPORT_ANALOG_NOTIFICATIONS - +//#define ZSCRIPT_SUPPORT_ADDRESSING +// +//#define ZSCRIPT_HAVE_PIN_MODULE +//#define ZSCRIPT_PIN_SUPPORT_NOTIFICATIONS +//#define ZSCRIPT_PIN_SUPPORT_ANALOG_NOTIFICATIONS +// #define ZSCRIPT_HAVE_I2C_MODULE #define ZSCRIPT_I2C_SUPPORT_NOTIFICATIONS #define ZSCRIPT_HAVE_I2C_CHANNEL @@ -53,15 +53,9 @@ class ZscriptParams { } typedef uint8_t tokenBufferSize_t; - - static const uint8_t tcpChannelCount = 1; - - static const uint8_t udpChannelCount = 1; - static const uint16_t udpLocalPort = 8888; - static const uint8_t udpBufferSize = 128; - static const uint8_t lockByteCount = 1; - static const uint16_t serialBufferSize = 128; + + static const uint8_t pinCount = NUM_DIGITAL_PINS; static const uint16_t i2cBufferSize = 128; static const uint16_t i2cChannelOutputBufferSize = 32; @@ -70,14 +64,28 @@ class ZscriptParams { static const uint8_t i2cAddressingReadBlockLength = 8; static const uint8_t i2cChannelAddress = 0x61; - static const uint16_t nonActivatedChannelTimeout = 5000; + static constexpr uint16_t uartCount = 1; + static constexpr uint16_t uartRxBufferSize = 0; + static constexpr uint16_t uartTxBufferSize = 0; + static constexpr uint32_t uartSupportedFreqs[] = {9600, 115200}; + static constexpr uint16_t uartChannelInterface = 0; + static constexpr uint16_t uartChannelBufferSize = 128; - static const uint8_t pinCount = NUM_DIGITAL_PINS; + static constexpr uint8_t servoCount = 1; + static constexpr uint8_t servoPins[] = { 9 }; + + static constexpr uint8_t udpChannelCount = 1; + static constexpr uint16_t udpLocalPort = 8888; + static constexpr uint8_t udpBufferSize = 128; + + static constexpr uint8_t tcpChannelCount = 1; + static constexpr uint16_t tcpLocalPort = 23; + static constexpr uint8_t tcpBufferSize = 128; - static const uint8_t servoCount = 1; - static const uint8_t servoPins[1]; + static constexpr uint16_t nonActivatedChannelTimeout = 5000; }; -const uint8_t ZscriptParams::servoPins[1] = {9}; +constexpr uint32_t ZscriptParams::uartSupportedFreqs[]; +constexpr uint8_t ZscriptParams::servoPins[1]; #endif /* SRC_MAIN_CPP_FIRSTARDUINOTEST_ZSCRIPTPARAMETERS_HPP_ */ diff --git a/receivers/native/arduino/src/main/c++/examples/UartChannelDemo/UartChannelDemo.ino b/receivers/native/arduino/src/main/c++/examples/UartChannelDemo/UartChannelDemo.ino new file mode 100644 index 000000000..4bd7477dc --- /dev/null +++ b/receivers/native/arduino/src/main/c++/examples/UartChannelDemo/UartChannelDemo.ino @@ -0,0 +1,12 @@ +#include "ZscriptParameters.hpp" +#include + +void setup() { + Serial.begin(9600); + ZscriptSetup.setup(); +} + +void loop() { + ZscriptSetup.pollAll(); + Zscript::Zscript::zscript.progress(); +} diff --git a/receivers/native/arduino/src/main/c++/examples/UartChannelDemo/ZscriptParameters.hpp b/receivers/native/arduino/src/main/c++/examples/UartChannelDemo/ZscriptParameters.hpp new file mode 100644 index 000000000..e9e097d0c --- /dev/null +++ b/receivers/native/arduino/src/main/c++/examples/UartChannelDemo/ZscriptParameters.hpp @@ -0,0 +1,91 @@ +/* + * Zscript Library - Command System for Microcontrollers) + * Copyright (c) 2022 Zscript team (Susan Witts, Alicia Witts) + * + * SPDX-License-Identifier: MIT + */ + +#ifndef SRC_MAIN_CPP_FIRSTARDUINOTEST_ZSCRIPTPARAMETERS_HPP_ +#define SRC_MAIN_CPP_FIRSTARDUINOTEST_ZSCRIPTPARAMETERS_HPP_ + +#define ZSCRIPT_IDENTIFY_USER_FIRMWARE_STRING "Zscript Arduino Example" +#define ZSCRIPT_IDENTIFY_USER_FIRMWARE_VERSION 0x0001 + +#define ZSCRIPT_IDENTIFY_USER_HARDWARE_STRING "Test setup" +#define ZSCRIPT_IDENTIFY_USER_HARDWARE_VERSION 0x0000 + +#include +#include +#include + +#include + +// Please note that ZscriptFullInclude will set any #defines necessary to other set #defines - eg ZSCRIPT_USE_DEBUG_ADDRESSING_SYSTEM enables ZSCRIPT_SUPPORT_DEBUG + +//#define ZSCRIPT_SUPPORT_SCRIPT_SPACE +//#define ZSCRIPT_SUPPORT_NOTIFICATIONS +//#define ZSCRIPT_SUPPORT_ADDRESSING +// +#define ZSCRIPT_HAVE_PIN_MODULE +#define ZSCRIPT_PIN_SUPPORT_NOTIFICATIONS +//#define ZSCRIPT_PIN_SUPPORT_ANALOG_NOTIFICATIONS +// +#define ZSCRIPT_HAVE_I2C_MODULE +//#define ZSCRIPT_I2C_SUPPORT_NOTIFICATIONS +#define ZSCRIPT_HAVE_I2C_CHANNEL + +#define ZSCRIPT_HAVE_UART_MODULE +#define ZSCRIPT_HAVE_UART_CHANNEL + +//#define ZSCRIPT_HAVE_SERVO_MODULE +//#define ZSCRIPT_SERVO_MODULE_SLOW_MOVE + +//#define ZSCRIPT_HAVE_UDP_CHANNEL +//#define ZSCRIPT_HAVE_TCP_CHANNEL + +class ZscriptParams { +public: + typedef Zscript::ZscriptResetCommand ResetCommand; + typedef Zscript::ZscriptIdCommand IdCommand; + + static uint16_t generateRandom16() { + return (uint16_t) millis(); + } + + typedef uint8_t tokenBufferSize_t; + static const uint8_t lockByteCount = 1; + + static const uint8_t pinCount = NUM_DIGITAL_PINS; + + static const uint16_t i2cBufferSize = 128; + static const uint16_t i2cChannelOutputBufferSize = 32; + static const uint16_t i2cAlertInPin = 4; + static const uint16_t i2cAlertOutPin = 9; + static const uint8_t i2cAddressingReadBlockLength = 8; + static const uint8_t i2cChannelAddress = 0x61; + + static constexpr uint16_t uartCount = 1; + static constexpr uint16_t uartRxBufferSize = 0; + static constexpr uint16_t uartTxBufferSize = 0; + static constexpr uint32_t uartSupportedFreqs[] = {9600, 115200}; + static constexpr uint16_t uartChannelInterface = 0; + static constexpr uint16_t uartChannelBufferSize = 128; + + static constexpr uint8_t servoCount = 1; + static constexpr uint8_t servoPins[] = { 9 }; + + static constexpr uint8_t udpChannelCount = 1; + static constexpr uint16_t udpLocalPort = 8888; + static constexpr uint8_t udpBufferSize = 128; + + static constexpr uint8_t tcpChannelCount = 1; + static constexpr uint16_t tcpLocalPort = 23; + static constexpr uint8_t tcpBufferSize = 128; + + static constexpr uint16_t nonActivatedChannelTimeout = 5000; +}; + +constexpr uint32_t ZscriptParams::uartSupportedFreqs[]; +constexpr uint8_t ZscriptParams::servoPins[1]; + +#endif /* SRC_MAIN_CPP_FIRSTARDUINOTEST_ZSCRIPTPARAMETERS_HPP_ */ diff --git a/receivers/native/cpp-model-components/src/main/templates/CppCommandKeyDefs.mustache b/receivers/native/cpp-model-components/src/main/templates/CppCommandKeyDefs.mustache index 3a70090e9..5bf6159e0 100644 --- a/receivers/native/cpp-model-components/src/main/templates/CppCommandKeyDefs.mustache +++ b/receivers/native/cpp-model-components/src/main/templates/CppCommandKeyDefs.mustache @@ -53,6 +53,7 @@ namespace cmd_{{#lowerUnderscore}}{{commandName}}{{/lowerUnderscore}} { static constexpr uint8_t Req{{#upperCamel}}{{name}}{{/upperCamel}}__Bytes = '{{key}}'; {{/bytesType}} {{/typeDefinition}} + {{/requestFields}} {{#responseFields}} @@ -62,9 +63,8 @@ namespace cmd_{{#lowerUnderscore}}{{commandName}}{{/lowerUnderscore}} { static constexpr uint8_t Resp{{#upperCamel}}{{name}}{{/upperCamel}}__{{key}} = '{{key}}'; /** Enum of acceptable values for '{{#lowerCamel}}{{name}}{{/lowerCamel}}' field. */ - enum class Resp{{#upperCamel}}{{name}}{{/upperCamel}}Values : uint8_t { - /** Enum value: {{description}} */ - {{#values}}{{#lowerCamel}}{{.}}Value{{/lowerCamel}},{{/values}} + enum class Resp{{#upperCamel}}{{name}}{{/upperCamel}}_Values : uint8_t { + {{#values}}{{#lowerCamel}}{{.}}{{/lowerCamel}}_value, {{/values}} }; {{/enumType}} {{#numberType}} @@ -78,14 +78,14 @@ namespace cmd_{{#lowerUnderscore}}{{commandName}}{{/lowerUnderscore}} { /** Enum of bit-positions for '{{#lowerCamel}}{{name}}{{/lowerCamel}}' field. */ enum class Resp{{#upperCamel}}{{fieldName}}{{/upperCamel}}_BitPositions : uint8_t { {{#bits}} - {{#lowerCamel}}{{name}}{{/lowerCamel}}_BitPosition, + {{#lowerCamel}}{{name}}{{/lowerCamel}}_bitPosition, {{/bits}} }; /** Enum of bit fields (ie 1< *buffer = parseState->getReader().asBuffer(); CommandTokenIterator iterator = iteratorToMarker(); - for (GenericCore::OptionalRingBufferToken opt = iterator.next(buffer); opt.isPresent; opt = iterator.next( - buffer)) { + for (GenericCore::OptionalRingBufferToken opt = iterator.next(buffer); opt.isPresent; opt = iterator.next(buffer)) { GenericCore::RingBufferToken token = opt.token; if (token.getKey(buffer) == key) { *dest = token.getData16(buffer); @@ -190,23 +202,81 @@ class ZscriptCommandContext { return false; } + /** + * Determines whether this command has a specific field. + * + * @param key the field to check + * @return true if presne t; false otherwise + */ bool hasField(uint8_t key) { return getField(key).isPresent; } - uint16_t getField(uint8_t key, uint16_t def) { + /** + * Utility method that fetches a field, using the supplied default if it's absent. + * + * @param key the field to fetch + * @param def the default to use if field is absent + * @return the field's value + */ + uint16_t getField(const uint8_t key, const uint16_t def) { uint16_t val = def; getField(key, &val); return val; } + /** + * Utility method that fetches a field, using the supplied default if required, and setting VALUE_OUT_OF_RANGE if the + * resulting value is >= limit. + * + * @param key the field to fetch + * @param limit the limit to check - note the value must be < limit! + * @param def the default to use if field is absent + * @param dest the place to put the value (and may be written to even if the value is out of range) + * @return true if the value is returned within the limit, false otherwise (and response status is therefore set) + */ + bool getFieldCheckLimit(const uint8_t key, const uint16_t limit, const uint16_t def, uint16_t *dest) { + if (!getField(key, dest)) { + *dest = def; + } + if (*dest >= limit) { + status(ResponseStatus::VALUE_OUT_OF_RANGE); + return false; + } + return true; + } + + /** + * Utility method that fetches a *required* field and sets MISSING_KEY if absent or VALUE_OUT_OF_RANGE if the resulting value is >= limit. + * + * @param key the (numeric) field to fetch, from + * @param limit the limit to check - note the value must be < limit! + * @param dest the place to put the value + * @return true if the value is returned and within the limit, false otherwise (and response status is therefore set) + */ + bool getReqdFieldCheckLimit(const uint8_t key, const uint16_t limit, uint16_t *dest) { + if (!getField(key, dest)) { + status(ResponseStatus::MISSING_KEY); + return false; + } + if (*dest >= limit) { + status(ResponseStatus::VALUE_OUT_OF_RANGE); + return false; + } + return true; + } + + /** + * Determines the total number of (numeric) fields in this command. + * + * @return the total number of fields + */ uint8_t getFieldCount() { int count = 0; GenericCore::TokenRingBuffer *buffer = parseState->getReader().asBuffer(); CommandTokenIterator iterator = iteratorToMarker(); - for (GenericCore::OptionalRingBufferToken opt = iterator.next(buffer); opt.isPresent; opt = iterator.next( - buffer)) { + for (GenericCore::OptionalRingBufferToken opt = iterator.next(buffer); opt.isPresent; opt = iterator.next(buffer)) { if (ZcharsUtils::isNumericKey(opt.token.getKey())) { count++; } diff --git a/receivers/native/generic-core/src/main/c++/zscript/modules/core/ChannelInfoCommand.hpp b/receivers/native/generic-core/src/main/c++/zscript/modules/core/ChannelInfoCommand.hpp index a2445fcad..d38f8fed1 100644 --- a/receivers/native/generic-core/src/main/c++/zscript/modules/core/ChannelInfoCommand.hpp +++ b/receivers/native/generic-core/src/main/c++/zscript/modules/core/ChannelInfoCommand.hpp @@ -11,12 +11,14 @@ #include "../../ZscriptIncludes.hpp" #include "../../execution/ZscriptCommandContext.hpp" #include "../../LanguageVersion.hpp" +#include #define COMMAND_EXISTS_0008 EXISTENCE_MARKER_UTIL namespace Zscript { template class ZscriptChannel; + namespace GenericCore { template class ChannelInfoCommand { @@ -25,18 +27,16 @@ class ChannelInfoCommand { static void execute(ZscriptCommandContext ctx) { CommandOutStream out = ctx.getOutStream(); uint8_t current = ctx.getChannelIndex(); + uint16_t channelCount = Zscript::zscript.getChannelCount(); - uint16_t target = ctx.getField('C', current); - if (target >= Zscript::zscript.getChannelCount()) { - ctx.status(ResponseStatus::VALUE_OUT_OF_RANGE); + uint16_t channelIndex; + if (!ctx.getFieldCheckLimit(core_module::cmd_channel_info::ReqChannel__C, channelCount, current, &channelIndex)) { return; } - out.writeField('C', Zscript::zscript.getChannelCount()); - out.writeField('M', Zscript::zscript.getChannels()[target]->getAssociatedModule()); - out.writeField('B', Zscript::zscript.getChannels()[target]->getBufferLength()); - if (current <= Zscript::zscript.getChannelCount()) { - out.writeField('U', current); - } + out.writeField(core_module::cmd_channel_info::RespChannelCount__N, channelCount); + out.writeField(core_module::cmd_channel_info::RespAssociatedModule__M, Zscript::zscript.getChannels()[channelIndex]->getAssociatedModule()); + out.writeField(core_module::cmd_channel_info::RespBufferLength__B, Zscript::zscript.getChannels()[channelIndex]->getBufferLength()); + out.writeField(core_module::cmd_channel_info::RespCurrentChannel__U, current); } };