Skip to main content

ocpp_types/v201/
error.rs

1//! RPC framework error codes from Table 8 ("Valid Error Codes") of the
2//! OCPP-J 2.0.1 specification -- the `errorCode` values a `CALLERROR`
3//! frame may carry.
4
5/// One of the error codes OCPP-J 2.0.1 allows in a `CALLERROR` frame.
6///
7/// Two codes changed from 1.6J: `FormationViolation` was renamed to
8/// `FormatViolation`, and `OccurenceConstraintViolation`'s missing "r" was
9/// fixed to `OccurrenceConstraintViolation`. Two codes were added:
10/// `MessageTypeNotSupported` and `RpcFrameworkError`.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub enum RpcErrorCode {
14    /// Payload for Action is syntactically incorrect
15    FormatViolation,
16    /// Any other error not covered by the more specific error codes in
17    /// this table
18    GenericError,
19    /// An internal error occurred and the receiver was not able to process
20    /// the requested Action successfully
21    InternalError,
22    /// A message with an Message Type Number received that is not
23    /// supported by this implementation.
24    MessageTypeNotSupported,
25    /// Requested Action is not known by receiver
26    NotImplemented,
27    /// Requested Action is recognized but not supported by the receiver
28    NotSupported,
29    /// Payload for Action is syntactically correct but at least one of the
30    /// fields violates occurrence constraints
31    OccurrenceConstraintViolation,
32    /// Payload is syntactically correct but at least one field contains an
33    /// invalid value
34    PropertyConstraintViolation,
35    /// Payload for Action is not conform the PDU structure
36    ProtocolError,
37    /// Content of the call is not a valid RPC Request, for example:
38    /// MessageId could not be read.
39    RpcFrameworkError,
40    /// During the processing of Action a security issue occurred
41    /// preventing receiver from completing the Action successfully
42    SecurityError,
43    /// Payload for Action is syntactically correct but at least one of the
44    /// fields violates data type constraints (e.g. "somestring": 12)
45    TypeConstraintViolation,
46}
47
48impl RpcErrorCode {
49    /// The spec's own description for this error code (see `Display`,
50    /// which uses this).
51    pub const fn description(&self) -> &'static str {
52        match self {
53            Self::FormatViolation => "Payload for Action is syntactically incorrect",
54            Self::GenericError => {
55                "Any other error not covered by the more specific error codes in this table"
56            }
57            Self::InternalError => {
58                "An internal error occurred and the receiver was not able to process the requested Action successfully"
59            }
60            Self::MessageTypeNotSupported => {
61                "A message with an Message Type Number received that is not supported by this implementation."
62            }
63            Self::NotImplemented => "Requested Action is not known by receiver",
64            Self::NotSupported => {
65                "Requested Action is recognized but not supported by the receiver"
66            }
67            Self::OccurrenceConstraintViolation => {
68                "Payload for Action is syntactically correct but at least one of the fields violates occurrence constraints"
69            }
70            Self::PropertyConstraintViolation => {
71                "Payload is syntactically correct but at least one field contains an invalid value"
72            }
73            Self::ProtocolError => "Payload for Action is not conform the PDU structure",
74            Self::RpcFrameworkError => {
75                "Content of the call is not a valid RPC Request, for example: MessageId could not be read."
76            }
77            Self::SecurityError => {
78                "During the processing of Action a security issue occurred preventing receiver from completing the Action successfully"
79            }
80            Self::TypeConstraintViolation => {
81                "Payload for Action is syntactically correct but at least one of the fields violates data type constraints (e.g. \"somestring\": 12)"
82            }
83        }
84    }
85}
86
87impl core::fmt::Display for RpcErrorCode {
88    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
89        f.write_str(self.description())
90    }
91}
92
93impl core::error::Error for RpcErrorCode {}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn has_exactly_the_twelve_codes_defined_by_the_ocpp_2_0_1j_spec() {
101        let all = [
102            RpcErrorCode::FormatViolation,
103            RpcErrorCode::GenericError,
104            RpcErrorCode::InternalError,
105            RpcErrorCode::MessageTypeNotSupported,
106            RpcErrorCode::NotImplemented,
107            RpcErrorCode::NotSupported,
108            RpcErrorCode::OccurrenceConstraintViolation,
109            RpcErrorCode::PropertyConstraintViolation,
110            RpcErrorCode::ProtocolError,
111            RpcErrorCode::RpcFrameworkError,
112            RpcErrorCode::SecurityError,
113            RpcErrorCode::TypeConstraintViolation,
114        ];
115
116        assert_eq!(all.len(), 12);
117    }
118
119    #[test]
120    fn display_shows_the_spec_description() {
121        use core::fmt::Write;
122        let mut buf = heapless::String::<128>::new();
123        write!(buf, "{}", RpcErrorCode::MessageTypeNotSupported).unwrap();
124
125        assert_eq!(
126            buf.as_str(),
127            "A message with an Message Type Number received that is not supported by this implementation."
128        );
129    }
130
131    #[test]
132    fn implements_the_core_error_trait() {
133        fn assert_error<T: core::error::Error>() {}
134        assert_error::<RpcErrorCode>();
135    }
136
137    #[cfg(feature = "serde")]
138    #[test]
139    fn serializes_using_the_exact_wire_spelling() {
140        // 2.0.1 corrected 1.6J's "OccurenceConstraintViolation" typo and
141        // renamed "FormationViolation" to "FormatViolation" -- this locks
142        // in that those aren't accidentally reused from v16.
143        let mut buf = [0u8; 64];
144        let json =
145            serde_json_core::to_slice(&RpcErrorCode::OccurrenceConstraintViolation, &mut buf)
146                .unwrap();
147
148        assert_eq!(&buf[..json], br#""OccurrenceConstraintViolation""#);
149    }
150}