MC Protocol Serial C++ 0.2.3
MC protocol serial library for MCU-oriented environments
Loading...
Searching...
No Matches
platformio_rpipico_arduino_uart.cpp
Go to the documentation of this file.
1#include <Arduino.h>
2
3#include <array>
4#include <cstddef>
5#include <cstdint>
6
9
10#ifndef MCPROTOCOL_EXAMPLE_PLC_BAUD
11#define MCPROTOCOL_EXAMPLE_PLC_BAUD 19200
12#endif
13
14#ifndef MCPROTOCOL_EXAMPLE_DEBUG_BAUD
15#define MCPROTOCOL_EXAMPLE_DEBUG_BAUD 115200
16#endif
17
18#ifndef MCPROTOCOL_EXAMPLE_POLL_INTERVAL_MS
19#define MCPROTOCOL_EXAMPLE_POLL_INTERVAL_MS 1000U
20#endif
21
22namespace {
23
36
37constexpr std::uint32_t kPollIntervalMs = MCPROTOCOL_EXAMPLE_POLL_INTERVAL_MS;
38constexpr std::uint32_t kPlcBaud = MCPROTOCOL_EXAMPLE_PLC_BAUD;
39constexpr DeviceAddress kHeadDevice {.code = DeviceCode::D, .number = 100};
40
41struct AppState {
42 MelsecSerialClient client;
43 std::array<std::uint16_t, 4> out_words {};
44 bool request_started = false;
45 bool tx_sent = false;
46 bool request_done = false;
47 bool request_reported = false;
48 std::uint32_t next_request_ms = 0;
49 Status completion_status {};
50};
51
52AppState g_app;
53HardwareSerial& g_plc_serial = Serial1;
54
55ProtocolConfig make_protocol() {
56 ProtocolConfig config;
57 config.frame_kind = FrameKind::C4;
58 config.code_mode = CodeMode::Ascii;
59 config.ascii_format = AsciiFormat::Format4;
60 config.target_series = PlcSeries::Q_L;
61 config.sum_check_enabled = false;
62 config.route = RouteConfig {
63 .kind = RouteKind::HostStation,
64 .station_no = 0x00,
65 .network_no = 0x00,
66 .pc_no = 0xFF,
67 .request_destination_module_io_no = 0x03FF,
68 .request_destination_module_station_no = 0x00,
69 .self_station_enabled = false,
70 .self_station_no = 0x00,
71 };
72 return config;
73}
74
75void on_request_complete(void* user, Status status) {
76 auto* app = static_cast<AppState*>(user);
77 app->request_done = true;
78 app->completion_status = status;
79 app->request_started = false;
80 app->tx_sent = false;
81 app->next_request_ms = millis() + kPollIntervalMs;
82}
83
84void configure_plc_uart() {
85 g_plc_serial.begin(kPlcBaud, SERIAL_8E1);
86}
87
88void pump_uart_tx(std::uint32_t now_ms) {
89 if (!g_app.request_started || g_app.tx_sent) {
90 return;
91 }
92
93 const std::span<const std::byte> frame = g_app.client.pending_tx_frame();
94 if (frame.empty()) {
95 return;
96 }
97
98 g_plc_serial.write(reinterpret_cast<const std::uint8_t*>(frame.data()), frame.size());
99 g_plc_serial.flush();
100 const Status status = g_app.client.notify_tx_complete(now_ms);
101 if (!status.ok()) {
102 on_request_complete(&g_app, status);
103 return;
104 }
105
106 g_app.tx_sent = true;
107}
108
109void pump_uart_rx(std::uint32_t now_ms) {
110 std::array<char, 64> rx_chunk {};
111 while (g_plc_serial.available() > 0) {
112 const int available = g_plc_serial.available();
113 const std::size_t request_size =
114 static_cast<std::size_t>(available > 0 ? available : 0);
115 const std::size_t read_size =
116 request_size < rx_chunk.size() ? request_size : rx_chunk.size();
117 const std::size_t bytes_read = static_cast<std::size_t>(
118 g_plc_serial.readBytes(rx_chunk.data(), read_size));
119 if (bytes_read == 0) {
120 break;
121 }
122
123 g_app.client.on_rx_bytes(
124 now_ms,
126 reinterpret_cast<const std::byte*>(rx_chunk.data()),
127 bytes_read));
128 }
129}
130
131void start_read_if_due(std::uint32_t now_ms) {
132 if (g_app.request_started || g_app.client.busy() || now_ms < g_app.next_request_ms) {
133 return;
134 }
135
136 g_app.request_done = false;
137 g_app.request_reported = false;
138 g_app.tx_sent = false;
139 const Status status = g_app.client.async_batch_read_words(
140 now_ms,
141 BatchReadWordsRequest {
142 .head_device = kHeadDevice,
143 .points = static_cast<std::uint16_t>(g_app.out_words.size()),
144 },
145 std::span<std::uint16_t>(g_app.out_words.data(), g_app.out_words.size()),
146 on_request_complete,
147 &g_app);
148 if (!status.ok()) {
149 on_request_complete(&g_app, status);
150 return;
151 }
152
153 g_app.request_started = true;
154}
155
156void report_once() {
157 if (!g_app.request_done || g_app.request_reported) {
158 return;
159 }
160
161 g_app.request_reported = true;
162 if (!g_app.completion_status.ok()) {
163 Serial.print("rpipico uart example failed: ");
164 Serial.println(g_app.completion_status.message);
165 return;
166 }
167
168 Serial.print("rpipico uart read ok: D100=");
169 Serial.print(g_app.out_words[0], HEX);
170 Serial.print(" D101=");
171 Serial.print(g_app.out_words[1], HEX);
172 Serial.print(" D102=");
173 Serial.print(g_app.out_words[2], HEX);
174 Serial.print(" D103=");
175 Serial.println(g_app.out_words[3], HEX);
176}
177
178} // namespace
179
180void setup() {
181 Serial.begin(MCPROTOCOL_EXAMPLE_DEBUG_BAUD);
182 configure_plc_uart();
183
184 const Status status = g_app.client.configure(make_protocol());
185 if (!status.ok()) {
186 on_request_complete(&g_app, status);
187 return;
188 }
189
190 g_app.next_request_ms = 0;
191 Serial.println("rpipico uart example: read-only D100-D103 via Serial1");
192}
193
194void loop() {
195 const std::uint32_t now_ms = millis();
196 start_read_if_due(now_ms);
197 pump_uart_tx(now_ms);
198 pump_uart_rx(now_ms);
199 g_app.client.poll(now_ms);
200 report_once();
201}
Asynchronous MC protocol client for UART / serial integrations.
Definition client.hpp:37
constexpr size_type size() const noexcept
constexpr pointer data() const noexcept
constexpr bool empty() const noexcept
Single-include entry point for the public serial client API.
DeviceCode
Device-family identifier used by the request codecs.
Definition types.hpp:198
RouteKind
Route layout inside the request header.
Definition types.hpp:190
FrameKind
MC protocol frame family used on the serial link.
Definition types.hpp:147
CodeMode
Request/response payload encoding.
Definition types.hpp:161
AsciiFormat
ASCII formatting variant for C4 / C3 / C2 serial frames.
Definition types.hpp:169
PlcSeries
PLC family selection used for subcommand and device-layout differences.
Definition types.hpp:181
#define MCPROTOCOL_EXAMPLE_POLL_INTERVAL_MS
#define MCPROTOCOL_EXAMPLE_PLC_BAUD
#define MCPROTOCOL_EXAMPLE_DEBUG_BAUD
Device code plus numeric address.
Definition types.hpp:348
Top-level protocol configuration shared by codecs and client requests.
Definition types.hpp:323
Route header fields for serial MC requests.
Definition types.hpp:296
Result object returned by most public APIs.
Definition status.hpp:26