• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
19 namespace pw::rpc::internal {
20 
21 using std::byte;
22 
FromBuffer(ConstByteSpan data)23 Result<Packet> Packet::FromBuffer(ConstByteSpan data) {
24   Packet packet;
25   Status status;
26   protobuf::Decoder decoder(data);
27 
28   while ((status = decoder.Next()).ok()) {
29     RpcPacket::Fields field =
30         static_cast<RpcPacket::Fields>(decoder.FieldNumber());
31 
32     switch (field) {
33       case RpcPacket::Fields::TYPE: {
34         uint32_t value;
35         decoder.ReadUint32(&value);
36         packet.set_type(static_cast<PacketType>(value));
37         break;
38       }
39 
40       case RpcPacket::Fields::CHANNEL_ID:
41         decoder.ReadUint32(&packet.channel_id_);
42         break;
43 
44       case RpcPacket::Fields::SERVICE_ID:
45         decoder.ReadFixed32(&packet.service_id_);
46         break;
47 
48       case RpcPacket::Fields::METHOD_ID:
49         decoder.ReadFixed32(&packet.method_id_);
50         break;
51 
52       case RpcPacket::Fields::PAYLOAD:
53         decoder.ReadBytes(&packet.payload_);
54         break;
55 
56       case RpcPacket::Fields::STATUS: {
57         uint32_t value;
58         decoder.ReadUint32(&value);
59         packet.set_status(static_cast<Status::Code>(value));
60         break;
61       }
62     }
63   }
64 
65   if (status.IsDataLoss()) {
66     return status;
67   }
68 
69   return packet;
70 }
71 
Encode(ByteSpan buffer) const72 Result<ConstByteSpan> Packet::Encode(ByteSpan buffer) const {
73   pw::protobuf::NestedEncoder encoder(buffer);
74   RpcPacket::Encoder rpc_packet(&encoder);
75 
76   // The payload is encoded first, as it may share the encode buffer.
77   rpc_packet.WritePayload(payload_);
78 
79   rpc_packet.WriteType(type_);
80   rpc_packet.WriteChannelId(channel_id_);
81   rpc_packet.WriteServiceId(service_id_);
82   rpc_packet.WriteMethodId(method_id_);
83   rpc_packet.WriteStatus(status_.code());
84 
85   return encoder.Encode();
86 }
87 
MinEncodedSizeBytes() const88 size_t Packet::MinEncodedSizeBytes() const {
89   size_t reserved_size = 0;
90 
91   reserved_size += 1;  // channel_id key
92   reserved_size += varint::EncodedSize(channel_id());
93   reserved_size += 1 + sizeof(uint32_t);  // service_id key and fixed32
94   reserved_size += 1 + sizeof(uint32_t);  // method_id key and fixed32
95 
96   // Packet type always takes two bytes to encode (varint key + varint enum).
97   reserved_size += 2;
98 
99   // Status field always takes two bytes to encode (varint key + varint status).
100   reserved_size += 2;
101 
102   // Payload field takes at least two bytes to encode (varint key + length).
103   reserved_size += 2;
104 
105   return reserved_size;
106 }
107 
108 }  // namespace pw::rpc::internal
109