Alexei Frolov | f93cb26 | 2021-07-14 16:05:15 -0700 | [diff] [blame] | 1 | // Copyright 2021 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_transfer_private/chunk.h" |
| 16 | |
| 17 | #include "pw_protobuf/decoder.h" |
| 18 | #include "pw_transfer/transfer.pwpb.h" |
| 19 | |
| 20 | namespace pw::transfer::internal { |
| 21 | |
| 22 | namespace ProtoChunk = transfer::Chunk; |
| 23 | |
| 24 | Status DecodeChunk(ConstByteSpan message, Chunk& chunk) { |
| 25 | protobuf::Decoder decoder(message); |
| 26 | Status status; |
| 27 | uint32_t value; |
| 28 | |
| 29 | chunk = {}; |
| 30 | |
| 31 | while ((status = decoder.Next()).ok()) { |
| 32 | ProtoChunk::Fields field = |
| 33 | static_cast<ProtoChunk::Fields>(decoder.FieldNumber()); |
| 34 | |
| 35 | switch (field) { |
| 36 | case ProtoChunk::Fields::TRANSFER_ID: |
| 37 | PW_TRY(decoder.ReadUint32(&chunk.transfer_id)); |
| 38 | break; |
| 39 | |
| 40 | case ProtoChunk::Fields::PENDING_BYTES: |
| 41 | PW_TRY(decoder.ReadUint32(&value)); |
| 42 | chunk.pending_bytes = value; |
| 43 | break; |
| 44 | |
| 45 | case ProtoChunk::Fields::MAX_CHUNK_SIZE_BYTES: |
| 46 | PW_TRY(decoder.ReadUint32(&value)); |
| 47 | chunk.max_chunk_size_bytes = value; |
| 48 | break; |
| 49 | |
| 50 | case ProtoChunk::Fields::MIN_DELAY_MICROSECONDS: |
| 51 | PW_TRY(decoder.ReadUint32(&value)); |
| 52 | chunk.min_delay_microseconds = value; |
| 53 | break; |
| 54 | |
| 55 | case ProtoChunk::Fields::OFFSET: |
| 56 | PW_TRY(decoder.ReadUint32(&chunk.offset)); |
| 57 | break; |
| 58 | |
| 59 | case ProtoChunk::Fields::DATA: |
| 60 | PW_TRY(decoder.ReadBytes(&chunk.data)); |
| 61 | break; |
| 62 | |
| 63 | case ProtoChunk::Fields::REMAINING_BYTES: { |
| 64 | uint64_t remaining; |
| 65 | PW_TRY(decoder.ReadUint64(&remaining)); |
| 66 | chunk.remaining_bytes = remaining; |
| 67 | break; |
| 68 | } |
| 69 | |
| 70 | case ProtoChunk::Fields::STATUS: |
| 71 | PW_TRY(decoder.ReadUint32(&value)); |
| 72 | chunk.status = static_cast<Status::Code>(value); |
| 73 | break; |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | return status.IsOutOfRange() ? OkStatus() : status; |
| 78 | } |
| 79 | |
| 80 | Result<ConstByteSpan> EncodeChunk(const Chunk& chunk, ByteSpan buffer) { |
Armando Montanez | 9f3708c | 2021-08-02 14:37:36 -0700 | [diff] [blame] | 81 | ProtoChunk::MemoryEncoder encoder(buffer); |
Alexei Frolov | f93cb26 | 2021-07-14 16:05:15 -0700 | [diff] [blame] | 82 | |
Adrien Larbanet | d1ca56c | 2021-06-10 14:20:45 +0000 | [diff] [blame] | 83 | encoder.WriteTransferId(chunk.transfer_id) |
| 84 | .IgnoreError(); // TODO(pwbug/387): Handle Status properly |
Alexei Frolov | f93cb26 | 2021-07-14 16:05:15 -0700 | [diff] [blame] | 85 | |
| 86 | if (chunk.pending_bytes.has_value()) { |
Adrien Larbanet | d1ca56c | 2021-06-10 14:20:45 +0000 | [diff] [blame] | 87 | encoder.WritePendingBytes(chunk.pending_bytes.value()) |
| 88 | .IgnoreError(); // TODO(pwbug/387): Handle Status properly |
Alexei Frolov | f93cb26 | 2021-07-14 16:05:15 -0700 | [diff] [blame] | 89 | } |
| 90 | if (chunk.max_chunk_size_bytes.has_value()) { |
Adrien Larbanet | d1ca56c | 2021-06-10 14:20:45 +0000 | [diff] [blame] | 91 | encoder.WriteMaxChunkSizeBytes(chunk.max_chunk_size_bytes.value()) |
| 92 | .IgnoreError(); // TODO(pwbug/387): Handle Status properly |
Alexei Frolov | f93cb26 | 2021-07-14 16:05:15 -0700 | [diff] [blame] | 93 | } |
| 94 | if (chunk.min_delay_microseconds.has_value()) { |
Adrien Larbanet | d1ca56c | 2021-06-10 14:20:45 +0000 | [diff] [blame] | 95 | encoder.WriteMinDelayMicroseconds(chunk.min_delay_microseconds.value()) |
| 96 | .IgnoreError(); // TODO(pwbug/387): Handle Status properly |
Alexei Frolov | f93cb26 | 2021-07-14 16:05:15 -0700 | [diff] [blame] | 97 | } |
| 98 | if (chunk.offset != 0) { |
Adrien Larbanet | d1ca56c | 2021-06-10 14:20:45 +0000 | [diff] [blame] | 99 | encoder.WriteOffset(chunk.offset) |
| 100 | .IgnoreError(); // TODO(pwbug/387): Handle Status properly |
Alexei Frolov | f93cb26 | 2021-07-14 16:05:15 -0700 | [diff] [blame] | 101 | } |
| 102 | if (!chunk.data.empty()) { |
Adrien Larbanet | d1ca56c | 2021-06-10 14:20:45 +0000 | [diff] [blame] | 103 | encoder.WriteData(chunk.data) |
| 104 | .IgnoreError(); // TODO(pwbug/387): Handle Status properly |
Alexei Frolov | f93cb26 | 2021-07-14 16:05:15 -0700 | [diff] [blame] | 105 | } |
| 106 | if (chunk.remaining_bytes.has_value()) { |
Adrien Larbanet | d1ca56c | 2021-06-10 14:20:45 +0000 | [diff] [blame] | 107 | encoder.WriteRemainingBytes(chunk.remaining_bytes.value()) |
| 108 | .IgnoreError(); // TODO(pwbug/387): Handle Status properly |
Alexei Frolov | f93cb26 | 2021-07-14 16:05:15 -0700 | [diff] [blame] | 109 | } |
| 110 | if (chunk.status.has_value()) { |
Adrien Larbanet | d1ca56c | 2021-06-10 14:20:45 +0000 | [diff] [blame] | 111 | encoder.WriteStatus(chunk.status.value().code()) |
| 112 | .IgnoreError(); // TODO(pwbug/387): Handle Status properly |
Alexei Frolov | f93cb26 | 2021-07-14 16:05:15 -0700 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | PW_TRY(encoder.status()); |
| 116 | return ConstByteSpan(encoder); |
| 117 | } |
| 118 | |
| 119 | } // namespace pw::transfer::internal |