ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
goose.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 goose.h
6 * @brief IEC 61850 GOOSE publisher + subscriber codec (PC_ENABLE_GOOSE).
7 *
8 * GOOSE (Generic Object Oriented Substation Event) is the fast raw-L2 multicast publish IEC 61850 uses
9 * for protection trips. A GOOSE frame is an Ethernet frame (ethertype 0x88B8, see services/fieldbus/rawl2) with
10 * an 8-octet GOOSE header (APPID, length, two reserved) followed by the BER-encoded `IECGoosePdu`:
11 *
12 * 61 len { 80 gocbRef 81 timeAllowedToLive 82 datSet 83 goID 84 t(UtcTime,8) 85 stNum
13 * 86 sqNum 87 simulation(BOOL) 88 confRev 89 ndsCom(BOOL) 8A numDatSetEntries AB allData }
14 *
15 * This builds the control PDU (all fields above) with `allData` supplied as a caller-encoded BER blob
16 * (a SEQUENCE of Data elements), then wraps it in the GOOSE header + Ethernet frame; `pc_goose_parse_frame`
17 * decodes a received frame the other way (the subscriber side), walking the BER TLVs into a pc_goose_rx.
18 * Pure, zero heap, no stdlib, host-testable; the raw-L2 transmit / receive is the
19 * device step.
20 */
21
22#ifndef PROTOCORE_GOOSE_H
23#define PROTOCORE_GOOSE_H
24
25#include "protocore_config.h"
26#include <stddef.h>
27#include <stdint.h>
28
29#if PC_ENABLE_GOOSE
30
31/** @brief The GOOSE control fields (strings are borrowed, not copied). */
32struct pc_goose
33{
34 const char *gocb_ref; ///< the GOOSE control-block reference.
35 uint32_t time_allowed_to_live; ///< ms the subscriber should keep this valid.
36 const char *dat_set; ///< the dataset reference.
37 const char *go_id; ///< the GOOSE id.
38 const uint8_t *t; ///< 8-octet UtcTime (seconds-since-epoch + fraction + quality).
39 uint32_t st_num; ///< state number (bumped on a data change).
40 uint32_t sq_num; ///< sequence number (bumped on each resend).
41 bool simulation; ///< test/simulation flag.
42 uint32_t conf_rev; ///< configuration revision.
43 bool nds_com; ///< needs-commissioning flag.
44 uint32_t num_entries; ///< number of dataset entries in allData.
45 const uint8_t *all_data; ///< pre-encoded BER SEQUENCE-of-Data body (contents of the AB field).
46 size_t all_data_len;
47};
48
49/**
50 * @brief Build the BER IECGoosePdu (the `61 ...` structure) into @p out. @return length, or 0 on overflow.
51 */
52size_t pc_goose_pdu(const pc_goose *g, uint8_t *out, size_t cap);
53
54/**
55 * @brief Build a full GOOSE Ethernet frame: [dst][src][88B8][APPID len rsvd rsvd][IECGoosePdu].
56 * @param appid the GOOSE APPID.
57 * @return the frame length, or 0 on overflow. Requires PC_ENABLE_RAWL2 for the Ethernet framing.
58 */
59size_t pc_goose_frame(const uint8_t *dst, const uint8_t *src, uint16_t appid, const pc_goose *g, uint8_t *out,
60 size_t cap);
61
62/** @brief The decoded fields of a received GOOSE frame. String / blob members point INTO the source buffer
63 * and are NOT NUL-terminated (each has an explicit length), so the caller must keep the buffer alive. */
64struct pc_goose_rx
65{
66 uint16_t appid; ///< GOOSE APPID from the header
67 const char *gocb_ref; ///< gocbRef, or nullptr if absent
68 size_t gocb_ref_len;
69 uint32_t time_allowed_to_live; ///< ms the subscriber should keep this valid
70 const char *dat_set; ///< dataset reference, or nullptr
71 size_t dat_set_len;
72 const char *go_id; ///< GOOSE id, or nullptr
73 size_t go_id_len;
74 const uint8_t *t; ///< 8-octet UtcTime, or nullptr
75 uint32_t st_num; ///< state number
76 uint32_t sq_num; ///< sequence number
77 bool simulation; ///< test / simulation flag
78 uint32_t conf_rev; ///< configuration revision
79 bool nds_com; ///< needs-commissioning flag
80 uint32_t num_entries; ///< number of dataset entries
81 const uint8_t *all_data; ///< the BER-encoded allData contents (inside the 0xAB tag), or nullptr
82 size_t all_data_len;
83};
84
85/**
86 * @brief Parse (subscribe to) a received GOOSE Ethernet frame into @p out. String / blob members borrow the
87 * input buffer. Unknown / future PDU tags are skipped.
88 * @return true iff the ethertype is 0x88B8 and the IECGoosePdu parses without truncation; false otherwise.
89 */
90bool pc_goose_parse_frame(const uint8_t *buf, size_t len, pc_goose_rx *out);
91
92#endif // PC_ENABLE_GOOSE
93#endif // PROTOCORE_GOOSE_H
User-facing configuration for ProtoCore.