ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
fins.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file fins.h
6 * @brief Omron FINS frame codec (PC_ENABLE_FINS) - zero-heap command/response builder +
7 * parser for the Factory Interface Network Service (FINS/UDP), so a device can talk
8 * to an Omron PLC over the shipped UDP transport.
9 *
10 * A FINS message is a 10-octet header then the command code and data:
11 * @code
12 * ICF RSV GCT DNA DA1 DA2 SNA SA1 SA2 SID MRC SRC [params / data...]
13 * @endcode
14 * - ICF: bit 6 = command(0)/response(1), bit 0 = response required(0)/not(1), bit 7 = use
15 * gateway. RSV = 0, GCT = 0x02. DNA/DA1/DA2 = destination net/node/unit; SNA/SA1/SA2 =
16 * source; SID = service id (echoed in the response).
17 * - MRC/SRC are the main/sub command code. A response inserts a 2-octet end code
18 * (MRES/SRES) before its data; MRES = SRES = 0 means normal completion.
19 * - Multi-octet command parameters (addresses, counts) are big-endian.
20 *
21 * FINS/UDP carries this frame directly (UDP provides integrity, so there is no checksum);
22 * FINS/TCP would prepend its own header. This is the message codec; the send is the app's.
23 *
24 * @author Douglas Quigg (dstroy0)
25 * @date 2026
26 */
27
28#ifndef PROTOCORE_FINS_H
29#define PROTOCORE_FINS_H
30
31#include "protocore_config.h"
32
33#if PC_ENABLE_FINS
34
35#include <stddef.h>
36#include <stdint.h>
37
38#define FINS_HEADER_SIZE 10
39
40#define FINS_ICF_COMMAND 0x80 ///< command, response required, gateway
41#define FINS_ICF_RESPONSE 0xC0 ///< response
42#define FINS_ICF_NO_RESPONSE 0x01 ///< OR into ICF: response not required
43
44// Common command codes (MRC, SRC).
45#define FINS_MRC_MEMORY_AREA 0x01
46#define FINS_SRC_MEMORY_AREA_READ 0x01
47#define FINS_SRC_MEMORY_AREA_WRITE 0x02
48#define FINS_MRC_OPERATING_MODE 0x04
49#define FINS_SRC_RUN 0x01
50#define FINS_SRC_STOP 0x02
51
52/** @brief The operating mode requested by a RUN (0401) command. */
53enum class FinsRunMode : uint8_t
54{
55 MONITOR = 0x02, ///< MONITOR mode (program runs, online edits allowed)
56 RUN = 0x04, ///< RUN mode (program runs, no online edits)
57};
58
59/** @brief The 10-octet FINS routing header. */
60struct FinsHeader
61{
62 uint8_t icf;
63 uint8_t rsv;
64 uint8_t gct;
65 uint8_t dna;
66 uint8_t da1;
67 uint8_t da2; ///< destination network / node / unit
68 uint8_t sna;
69 uint8_t sa1;
70 uint8_t sa2; ///< source network / node / unit
71 uint8_t sid; ///< service id
72};
73
74/** @brief Build a command frame: header + MRC + SRC + params. Returns total octets, or 0. */
75size_t pc_fins_build_command(uint8_t *buf, size_t cap, const FinsHeader *h, uint8_t mrc, uint8_t src,
76 const uint8_t *params, size_t params_len);
77
78/**
79 * @brief Build a Memory Area Read command (0101): area code, 2-octet word address + bit,
80 * 2-octet item count. The number of items is big-endian.
81 */
82size_t pc_fins_build_memory_area_read(uint8_t *buf, size_t cap, const FinsHeader *h, uint8_t area, uint16_t address,
83 uint8_t bit, uint16_t count);
84
85/**
86 * @brief Build a Memory Area Write command (0102): the same area / word address + bit / item-count
87 * parameters as the read, followed by @p data_len octets of write data (word areas carry two octets
88 * per item, big-endian). @p count is the number of items (big-endian).
89 * @return total octets written, or 0 on a null data pointer with a nonzero length, or an overflow.
90 */
91size_t pc_fins_build_memory_area_write(uint8_t *buf, size_t cap, const FinsHeader *h, uint8_t area, uint16_t address,
92 uint8_t bit, uint16_t count, const uint8_t *data, size_t data_len);
93
94/**
95 * @brief Build a RUN command (0401): switches the PLC to @p mode. Parameters are the program number
96 * (0xFFFF, all programs) followed by the 1-octet mode code. @return total octets, or 0 on overflow.
97 */
98size_t pc_fins_build_run(uint8_t *buf, size_t cap, const FinsHeader *h, FinsRunMode mode);
99
100/**
101 * @brief Build a STOP command (0402): switches the PLC to PROGRAM mode (stops execution). The command
102 * carries no parameters. @return total octets, or 0 on overflow.
103 */
104size_t pc_fins_build_stop(uint8_t *buf, size_t cap, const FinsHeader *h);
105
106/** @brief A parsed command (request side). @ref params points INTO the source buffer. */
107struct FinsCommand
108{
109 FinsHeader header;
110 uint8_t mrc;
111 uint8_t src;
112 const uint8_t *params;
113 size_t params_len;
114};
115
116/** @brief Parse a command frame (header + MRC + SRC + params). */
117bool pc_fins_parse_command(const uint8_t *buf, size_t len, FinsCommand *out);
118
119/** @brief A parsed response. @ref data points INTO the source buffer. */
120struct FinsResponse
121{
122 FinsHeader header;
123 uint8_t mrc;
124 uint8_t src; ///< echoed command code
125 uint8_t mres;
126 uint8_t sres; ///< end code (0/0 = normal completion)
127 const uint8_t *data;
128 size_t data_len;
129};
130
131/** @brief Parse a response frame (header + MRC + SRC + MRES + SRES + data). */
132bool pc_fins_parse_response(const uint8_t *buf, size_t len, FinsResponse *out);
133
134#endif // PC_ENABLE_FINS
135
136#endif // PROTOCORE_FINS_H
User-facing configuration for ProtoCore.