MC Protocol Serial C++ 0.2.3
MC protocol serial library for MCU-oriented environments
Loading...
Searching...
No Matches
link_direct.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstddef>
4#include <cstdint>
5
10
11namespace mcprotocol::serial {
12
18
24
31
37
44
49
58
63
68
69namespace link_direct_detail {
70
71[[nodiscard]] constexpr char ascii_upper(char value) noexcept {
72 return (value >= 'a' && value <= 'z') ? static_cast<char>(value - ('a' - 'A')) : value;
73}
74
75[[nodiscard]] constexpr bool is_separator(char value) noexcept {
76 return value == '\\' || value == '/';
77}
78
79[[nodiscard]] inline bool parse_u32_chars(
81 int base,
82 std::uint32_t& out_value) noexcept {
83 if (text.empty()) {
84 return false;
85 }
86
87 std::uint32_t value = 0U;
88 for (char ch : text) {
89 std::uint32_t digit = 0U;
90 if (ch >= '0' && ch <= '9') {
91 digit = static_cast<std::uint32_t>(ch - '0');
92 } else if (base == 16 && ch >= 'A' && ch <= 'F') {
93 digit = static_cast<std::uint32_t>(ch - 'A' + 10);
94 } else if (base == 16 && ch >= 'a' && ch <= 'f') {
95 digit = static_cast<std::uint32_t>(ch - 'a' + 10);
96 } else {
97 return false;
98 }
99
100 if (digit >= static_cast<std::uint32_t>(base)) {
101 return false;
102 }
103
104 value = static_cast<std::uint32_t>(value * static_cast<std::uint32_t>(base) + digit);
105 }
106
107 out_value = value;
108 return true;
109}
110
117
119 {"SB", 2U, DeviceCode::SB, 16},
120 {"SW", 2U, DeviceCode::SW, 16},
121 {"X", 1U, DeviceCode::X, 16},
122 {"Y", 1U, DeviceCode::Y, 16},
123 {"B", 1U, DeviceCode::B, 16},
124 {"W", 1U, DeviceCode::W, 16},
125};
126
127[[nodiscard]] inline bool parse_link_direct_inner_device(
128 std::string_view text,
129 DeviceAddress& out_device) noexcept {
130 for (const auto& spec : kLinkDirectParseSpecs) {
131 if (text.size() <= spec.prefix_length) {
132 continue;
133 }
134
135 bool prefix_match = true;
136 for (std::size_t index = 0; index < spec.prefix_length; ++index) {
137 if (ascii_upper(text[index]) != spec.prefix[index]) {
138 prefix_match = false;
139 break;
140 }
141 }
142 if (!prefix_match) {
143 continue;
144 }
145
146 std::uint32_t number = 0;
147 if (!parse_u32_chars(text.substr(spec.prefix_length), spec.base, number)) {
148 return false;
149 }
150
151 out_device = DeviceAddress {
152 .code = spec.code,
153 .number = number,
154 };
155 return true;
156 }
157
158 return false;
159}
160
161} // namespace link_direct_detail
162
164[[nodiscard]] inline Status parse_link_direct_device(
165 std::string_view text,
166 LinkDirectDevice& out_device) noexcept {
167 if (text.size() < 4U || link_direct_detail::ascii_upper(text.front()) != 'J') {
168 return make_status(
170 "Link direct device must begin with J");
171 }
172
174 for (std::size_t index = 1U; index < text.size(); ++index) {
175 if (link_direct_detail::is_separator(text[index])) {
176 separator = index;
177 break;
178 }
179 }
180 if (separator == std::string_view::npos || separator <= 1U || separator >= (text.size() - 1U)) {
181 return make_status(
183 "Link direct device must look like J1\\W100");
184 }
185
186 std::uint32_t network_number = 0;
187 if (!link_direct_detail::parse_u32_chars(text.substr(1U, separator - 1U), 16, network_number) ||
188 network_number > 0xFFFFU) {
189 return make_status(
191 "Link direct network number must be a hexadecimal value in range 0x0000..0xFFFF");
192 }
193
194 DeviceAddress device {};
195 if (!link_direct_detail::parse_link_direct_inner_device(text.substr(separator + 1U), device)) {
196 return make_status(
198 "Link direct device must be X, Y, B, W, SB, or SW");
199 }
200
201 out_device = LinkDirectDevice {
202 .network_number = static_cast<std::uint16_t>(network_number),
203 .device = device,
204 };
205 return ok_status();
206}
207
208} // namespace mcprotocol::serial
constexpr size_type size() const noexcept
static constexpr size_type npos
Status parse_link_direct_device(std::string_view text, LinkDirectDevice &out_device) noexcept
Parses a Jn\\... link-direct device string such as J1\\W100 or J1\\X10.
DeviceCode
Device-family identifier used by the request codecs.
Definition types.hpp:198
BitValue
Logical single-bit value used by bit read/write APIs.
Definition types.hpp:243
constexpr Status make_status(StatusCode code, const char *message, std::uint16_t plc_error_code=0) noexcept
Builds a status value with an optional PLC end code.
Definition status.hpp:42
constexpr Status ok_status() noexcept
Returns the default success status.
Definition status.hpp:37
Device code plus numeric address.
Definition types.hpp:348
DeviceCode code
Device family such as D, M, X, LTN, or LZ.
Definition types.hpp:350
Parsed Jn\\... link-direct device reference such as J1\\W100.
Jn\\... monitor registration payload (0801 + device extension specification).
std::span< const LinkDirectRandomReadItem > items
One Jn\\... block used by native multi-block read.
Jn\\... native multi-block read request.
std::span< const LinkDirectMultiBlockReadBlock > blocks
One Jn\\... block used by native multi-block write.
Jn\\... native multi-block write request.
std::span< const LinkDirectMultiBlockWriteBlock > blocks
One sparse Jn\\... item used by native random-read and monitor registration.
One sparse Jn\\... bit item used by native random bit-write.
One sparse Jn\\... word item used by native random word-write.
Result object returned by most public APIs.
Definition status.hpp:26
Public request, response, configuration, and callback types for the serial MC protocol library.