blob: dfbdb50753bc25263f9bd89da8f9bcab25b7cbee [file] [log] [blame]
Alexei Frolov5d6d3922020-05-08 13:57:02 -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
15#include "pw_rpc/internal/packet.h"
16
17#include "pw_protobuf/decoder.h"
18
19namespace pw::rpc::internal {
20
Wyatt Hepler142616c2020-06-01 10:16:04 -070021using std::byte;
22
Wyatt Hepler712d3672020-07-13 15:52:11 -070023Status Packet::FromBuffer(std::span<const byte> data, Packet& packet) {
24 packet = Packet();
Alexei Frolov5d6d3922020-05-08 13:57:02 -070025
26 protobuf::Decoder decoder(data);
27
Wyatt Hepler712d3672020-07-13 15:52:11 -070028 Status status;
29
30 while ((status = decoder.Next()).ok()) {
Alexei Frolov5d6d3922020-05-08 13:57:02 -070031 RpcPacket::Fields field =
32 static_cast<RpcPacket::Fields>(decoder.FieldNumber());
Alexei Frolov5d6d3922020-05-08 13:57:02 -070033
34 switch (field) {
Wyatt Hepler712d3672020-07-13 15:52:11 -070035 case RpcPacket::Fields::TYPE: {
36 uint32_t value;
37 decoder.ReadUint32(&value);
38 packet.set_type(static_cast<PacketType>(value));
Alexei Frolov5d6d3922020-05-08 13:57:02 -070039 break;
Wyatt Hepler712d3672020-07-13 15:52:11 -070040 }
Alexei Frolov5d6d3922020-05-08 13:57:02 -070041
Alexei Frolovd54975b2020-05-19 15:13:27 -070042 case RpcPacket::Fields::CHANNEL_ID:
Wyatt Hepler712d3672020-07-13 15:52:11 -070043 decoder.ReadUint32(&packet.channel_id_);
Alexei Frolov5d6d3922020-05-08 13:57:02 -070044 break;
45
Alexei Frolovd54975b2020-05-19 15:13:27 -070046 case RpcPacket::Fields::SERVICE_ID:
Wyatt Hepler712d3672020-07-13 15:52:11 -070047 decoder.ReadFixed32(&packet.service_id_);
Alexei Frolov5d6d3922020-05-08 13:57:02 -070048 break;
49
Alexei Frolovd54975b2020-05-19 15:13:27 -070050 case RpcPacket::Fields::METHOD_ID:
Wyatt Hepler712d3672020-07-13 15:52:11 -070051 decoder.ReadFixed32(&packet.method_id_);
Alexei Frolov5d6d3922020-05-08 13:57:02 -070052 break;
53
Alexei Frolovd54975b2020-05-19 15:13:27 -070054 case RpcPacket::Fields::PAYLOAD:
Wyatt Hepler712d3672020-07-13 15:52:11 -070055 decoder.ReadBytes(&packet.payload_);
Alexei Frolov5d6d3922020-05-08 13:57:02 -070056 break;
Alexei Frolov00890942020-05-19 10:45:08 -070057
Wyatt Hepler712d3672020-07-13 15:52:11 -070058 case RpcPacket::Fields::STATUS: {
59 uint32_t value;
Alexei Frolov00890942020-05-19 10:45:08 -070060 decoder.ReadUint32(&value);
Wyatt Hepler712d3672020-07-13 15:52:11 -070061 packet.set_status(static_cast<Status::Code>(value));
Alexei Frolov00890942020-05-19 10:45:08 -070062 break;
Wyatt Hepler712d3672020-07-13 15:52:11 -070063 }
Alexei Frolov5d6d3922020-05-08 13:57:02 -070064 }
65 }
66
Wyatt Hepler712d3672020-07-13 15:52:11 -070067 return status == Status::DATA_LOSS ? Status::DATA_LOSS : Status::OK;
Alexei Frolov5d6d3922020-05-08 13:57:02 -070068}
69
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070070StatusWithSize Packet::Encode(std::span<byte> buffer) const {
Alexei Frolov5d6d3922020-05-08 13:57:02 -070071 pw::protobuf::NestedEncoder encoder(buffer);
72 RpcPacket::Encoder rpc_packet(&encoder);
73
Alexei Frolov33a1e8f2020-05-26 08:39:32 -070074 // The payload is encoded first, as it may share the encode buffer.
75 rpc_packet.WritePayload(payload_);
76
Alexei Frolov5d6d3922020-05-08 13:57:02 -070077 rpc_packet.WriteType(type_);
78 rpc_packet.WriteChannelId(channel_id_);
79 rpc_packet.WriteServiceId(service_id_);
80 rpc_packet.WriteMethodId(method_id_);
Alexei Frolov00890942020-05-19 10:45:08 -070081 rpc_packet.WriteStatus(status_);
Alexei Frolov5d6d3922020-05-08 13:57:02 -070082
Wyatt Heplere2cbadf2020-06-22 11:21:45 -070083 std::span<const byte> proto;
Alexei Frolov5d6d3922020-05-08 13:57:02 -070084 if (Status status = encoder.Encode(&proto); !status.ok()) {
85 return StatusWithSize(status, 0);
86 }
87
88 return StatusWithSize(proto.size());
89}
90
Wyatt Hepler671946e2020-06-09 14:39:33 -070091size_t Packet::MinEncodedSizeBytes() const {
Wyatt Hepler142616c2020-06-01 10:16:04 -070092 size_t reserved_size = 0;
93
94 reserved_size += 1; // channel_id key
95 reserved_size += varint::EncodedSize(channel_id());
Wyatt Hepler712d3672020-07-13 15:52:11 -070096 reserved_size += 1 + sizeof(uint32_t); // service_id key and fixed32
97 reserved_size += 1 + sizeof(uint32_t); // method_id key and fixed32
Wyatt Hepler142616c2020-06-01 10:16:04 -070098
99 // Packet type always takes two bytes to encode (varint key + varint enum).
100 reserved_size += 2;
101
102 // Status field always takes two bytes to encode (varint key + varint status).
103 reserved_size += 2;
104
105 // Payload field takes at least two bytes to encode (varint key + length).
106 reserved_size += 2;
107
Wyatt Hepler671946e2020-06-09 14:39:33 -0700108 return reserved_size;
Wyatt Hepler142616c2020-06-01 10:16:04 -0700109}
110
Alexei Frolov5d6d3922020-05-08 13:57:02 -0700111} // namespace pw::rpc::internal