blob: 90e8c0961bc99aaf0fa702bd22650a86ff123e0f [file] [log] [blame]
Alexei Frolov4d2adde2020-08-04 10:19:24 -07001// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
Wyatt Hepler8ec2cf82021-07-09 17:18:41 -070015#include "pw_rpc/nanopb/internal/common.h"
Alexei Frolov4d2adde2020-08-04 10:19:24 -070016
17#include "pb_decode.h"
18#include "pb_encode.h"
Wyatt Hepler9e8ca382021-08-20 08:29:57 -070019#include "pw_log/log.h"
Alexei Frolov4d2adde2020-08-04 10:19:24 -070020
21namespace pw::rpc::internal {
Wyatt Hepler9e8ca382021-08-20 08:29:57 -070022namespace {
Alexei Frolov4d2adde2020-08-04 10:19:24 -070023
24// Nanopb 3 uses pb_field_s and Nanopb 4 uses pb_msgdesc_s for fields. The
25// Nanopb version macro is difficult to use, so deduce the correct type from the
26// pb_decode function.
27template <typename DecodeFunction>
28struct NanopbTraits;
29
30template <typename FieldsType>
31struct NanopbTraits<bool(pb_istream_t*, FieldsType, void*)> {
32 using Fields = FieldsType;
33};
34
35using Fields = typename NanopbTraits<decltype(pb_decode)>::Fields;
36
Wyatt Hepler9e8ca382021-08-20 08:29:57 -070037} // namespace
38
39// PB_NO_ERRMSG is used in pb_decode.h and pb_encode.h to enable or disable the
40// errmsg member of the istream and ostream structs. If errmsg is available, use
41// it to give more detailed log messages.
42#ifdef PB_NO_ERRMSG
43
44#define PW_RPC_LOG_NANOPB_FAILURE(msg, stream) PW_LOG_ERROR(msg)
45
46#else
47
48#define PW_RPC_LOG_NANOPB_FAILURE(msg, stream) \
49 PW_LOG_ERROR(msg ": %s", stream.errmsg)
50
51#endif // PB_NO_ERRMSG
52
Alexei Frolov4d2adde2020-08-04 10:19:24 -070053StatusWithSize NanopbMethodSerde::Encode(NanopbMessageDescriptor fields,
Wyatt Hepler59b37f72021-06-15 16:23:44 -070054 const void* proto_struct,
55 ByteSpan buffer) const {
Alexei Frolov4d2adde2020-08-04 10:19:24 -070056 auto output = pb_ostream_from_buffer(
57 reinterpret_cast<pb_byte_t*>(buffer.data()), buffer.size());
58 if (!pb_encode(&output, static_cast<Fields>(fields), proto_struct)) {
Wyatt Hepler9e8ca382021-08-20 08:29:57 -070059 PW_RPC_LOG_NANOPB_FAILURE("Nanopb protobuf encode failed", output);
Alexei Frolov4d2adde2020-08-04 10:19:24 -070060 return StatusWithSize::Internal();
61 }
62
Wyatt Hepler1b3da3a2021-01-07 13:26:57 -080063 return StatusWithSize(output.bytes_written);
Alexei Frolov4d2adde2020-08-04 10:19:24 -070064}
65
66bool NanopbMethodSerde::Decode(NanopbMessageDescriptor fields,
Wyatt Hepler59b37f72021-06-15 16:23:44 -070067 ConstByteSpan buffer,
68 void* proto_struct) const {
Alexei Frolov4d2adde2020-08-04 10:19:24 -070069 auto input = pb_istream_from_buffer(
70 reinterpret_cast<const pb_byte_t*>(buffer.data()), buffer.size());
Wyatt Hepler9e8ca382021-08-20 08:29:57 -070071 bool result = pb_decode(&input, static_cast<Fields>(fields), proto_struct);
72 if (!result) {
73 PW_RPC_LOG_NANOPB_FAILURE("Nanopb protobuf decode failed", input);
74 }
75 return result;
Alexei Frolov4d2adde2020-08-04 10:19:24 -070076}
77
Wyatt Hepler9e8ca382021-08-20 08:29:57 -070078#undef PW_RPC_LOG_NANOPB_FAILURE
79
Alexei Frolov4d2adde2020-08-04 10:19:24 -070080} // namespace pw::rpc::internal