LCOV - code coverage report
Current view: top level - setup_payload - ManualSetupPayloadGenerator.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 57 59 96.6 %
Date: 2024-02-15 08:20:41 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /**
       2             :  *
       3             :  *    Copyright (c) 2020 Project CHIP Authors
       4             :  *
       5             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6             :  *    you may not use this file except in compliance with the License.
       7             :  *    You may obtain a copy of the License at
       8             :  *
       9             :  *        http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  *    Unless required by applicable law or agreed to in writing, software
      12             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  *    See the License for the specific language governing permissions and
      15             :  *    limitations under the License.
      16             :  */
      17             : 
      18             : /**
      19             :  *    @file
      20             :  *      This file describes a Manual Entry Code Generator.
      21             :  *
      22             :  */
      23             : 
      24             : #include "ManualSetupPayloadGenerator.h"
      25             : 
      26             : #include <inttypes.h>
      27             : #include <limits>
      28             : 
      29             : #include <lib/support/logging/CHIPLogging.h>
      30             : #include <lib/support/verhoeff/Verhoeff.h>
      31             : 
      32             : namespace chip {
      33             : 
      34          12 : static uint32_t chunk1PayloadRepresentation(const PayloadContents & payload)
      35             : {
      36             :     /* <1 digit> Represents:
      37             :      *     - <bits 1..0> Discriminator <bits 11.10>
      38             :      *     - <bit 2> VID/PID present flag
      39             :      */
      40             : 
      41          12 :     constexpr int kDiscriminatorShift = (kManualSetupDiscriminatorFieldLengthInBits - kManualSetupChunk1DiscriminatorMsbitsLength);
      42          12 :     constexpr uint32_t kDiscriminatorMask = (1 << kManualSetupChunk1DiscriminatorMsbitsLength) - 1;
      43             : 
      44             :     static_assert(kManualSetupChunk1VidPidPresentBitPos >=
      45             :                       kManualSetupChunk1DiscriminatorMsbitsPos + kManualSetupChunk1DiscriminatorMsbitsLength,
      46             :                   "Discriminator won't fit");
      47             : 
      48          12 :     uint32_t discriminatorChunk = (payload.discriminator.GetShortValue() >> kDiscriminatorShift) & kDiscriminatorMask;
      49          12 :     uint32_t vidPidPresentFlag  = payload.commissioningFlow != CommissioningFlow::kStandard ? 1 : 0;
      50             : 
      51          12 :     uint32_t result = (discriminatorChunk << kManualSetupChunk1DiscriminatorMsbitsPos) |
      52          12 :         (vidPidPresentFlag << kManualSetupChunk1VidPidPresentBitPos);
      53             : 
      54          12 :     return result;
      55             : }
      56             : 
      57          12 : static uint32_t chunk2PayloadRepresentation(const PayloadContents & payload)
      58             : {
      59             :     /* <5 digits> Represents:
      60             :      *     - <bits 13..0> PIN Code <bits 13..0>
      61             :      *     - <bits 15..14> Discriminator <bits 9..8>
      62             :      */
      63             : 
      64          12 :     constexpr uint32_t kDiscriminatorMask = (1 << kManualSetupChunk2DiscriminatorLsbitsLength) - 1;
      65          12 :     constexpr uint32_t kPincodeMask       = (1 << kManualSetupChunk2PINCodeLsbitsLength) - 1;
      66             : 
      67          12 :     uint32_t discriminatorChunk = payload.discriminator.GetShortValue() & kDiscriminatorMask;
      68             : 
      69          12 :     uint32_t result = ((payload.setUpPINCode & kPincodeMask) << kManualSetupChunk2PINCodeLsbitsPos) |
      70          12 :         (discriminatorChunk << kManualSetupChunk2DiscriminatorLsbitsPos);
      71             : 
      72          12 :     return result;
      73             : }
      74             : 
      75          12 : static uint32_t chunk3PayloadRepresentation(const PayloadContents & payload)
      76             : {
      77             :     /* <4 digits> Represents:
      78             :      *     - <bits 12..0> PIN Code <bits 26..14>
      79             :      */
      80             : 
      81          12 :     constexpr int kPincodeShift     = (kSetupPINCodeFieldLengthInBits - kManualSetupChunk3PINCodeMsbitsLength);
      82          12 :     constexpr uint32_t kPincodeMask = (1 << kManualSetupChunk3PINCodeMsbitsLength) - 1;
      83             : 
      84          12 :     uint32_t result = ((payload.setUpPINCode >> kPincodeShift) & kPincodeMask) << kManualSetupChunk3PINCodeMsbitsPos;
      85             : 
      86          12 :     return result;
      87             : }
      88             : 
      89          62 : static CHIP_ERROR decimalStringWithPadding(MutableCharSpan buffer, uint32_t number)
      90             : {
      91          62 :     int len    = static_cast<int>(buffer.size() - 1);
      92          62 :     int retval = snprintf(buffer.data(), buffer.size(), "%0*" PRIu32, len, number);
      93             : 
      94          62 :     return (retval >= static_cast<int>(buffer.size())) ? CHIP_ERROR_BUFFER_TOO_SMALL : CHIP_NO_ERROR;
      95             : }
      96             : 
      97          13 : CHIP_ERROR ManualSetupPayloadGenerator::payloadDecimalStringRepresentation(MutableCharSpan & outBuffer)
      98             : {
      99             :     static_assert(kManualSetupCodeChunk1CharLength + kManualSetupCodeChunk2CharLength + kManualSetupCodeChunk3CharLength ==
     100             :                       kManualSetupShortCodeCharLength,
     101             :                   "Manual code length mismatch (short)");
     102             :     static_assert(kManualSetupShortCodeCharLength + kManualSetupVendorIdCharLength + kManualSetupProductIdCharLength ==
     103             :                       kManualSetupLongCodeCharLength,
     104             :                   "Manual code length mismatch (long)");
     105             :     static_assert(kManualSetupChunk1DiscriminatorMsbitsLength + kManualSetupChunk2DiscriminatorLsbitsLength ==
     106             :                       kManualSetupDiscriminatorFieldLengthInBits,
     107             :                   "Discriminator won't fit");
     108             :     static_assert(kManualSetupChunk2PINCodeLsbitsLength + kManualSetupChunk3PINCodeMsbitsLength == kSetupPINCodeFieldLengthInBits,
     109             :                   "PIN code won't fit");
     110             : 
     111          13 :     if (!mAllowInvalidPayload && !mPayloadContents.isValidManualCode())
     112             :     {
     113           1 :         ChipLogError(SetupPayload, "Failed encoding invalid payload");
     114           1 :         return CHIP_ERROR_INVALID_ARGUMENT;
     115             :     }
     116             : 
     117          12 :     bool useLongCode = (mPayloadContents.commissioningFlow != CommissioningFlow::kStandard) && !mForceShortCode;
     118             : 
     119             :     // Add two for the check digit and null terminator.
     120          24 :     if ((useLongCode && outBuffer.size() < kManualSetupLongCodeCharLength + 2) ||
     121          12 :         (!useLongCode && outBuffer.size() < kManualSetupShortCodeCharLength + 2))
     122             :     {
     123           0 :         ChipLogError(SetupPayload, "Failed encoding payload to buffer");
     124           0 :         return CHIP_ERROR_BUFFER_TOO_SMALL;
     125             :     }
     126             : 
     127          12 :     uint32_t chunk1 = chunk1PayloadRepresentation(mPayloadContents);
     128          12 :     uint32_t chunk2 = chunk2PayloadRepresentation(mPayloadContents);
     129          12 :     uint32_t chunk3 = chunk3PayloadRepresentation(mPayloadContents);
     130             : 
     131          12 :     size_t offset = 0;
     132             : 
     133             :     // Add one to the length of each chunk, since snprintf writes a null terminator.
     134          12 :     ReturnErrorOnFailure(decimalStringWithPadding(outBuffer.SubSpan(offset, kManualSetupCodeChunk1CharLength + 1), chunk1));
     135          12 :     offset += kManualSetupCodeChunk1CharLength;
     136          12 :     ReturnErrorOnFailure(decimalStringWithPadding(outBuffer.SubSpan(offset, kManualSetupCodeChunk2CharLength + 1), chunk2));
     137          12 :     offset += kManualSetupCodeChunk2CharLength;
     138          12 :     ReturnErrorOnFailure(decimalStringWithPadding(outBuffer.SubSpan(offset, kManualSetupCodeChunk3CharLength + 1), chunk3));
     139          12 :     offset += kManualSetupCodeChunk3CharLength;
     140             : 
     141          12 :     if (useLongCode)
     142             :     {
     143           7 :         ReturnErrorOnFailure(
     144             :             decimalStringWithPadding(outBuffer.SubSpan(offset, kManualSetupVendorIdCharLength + 1), mPayloadContents.vendorID));
     145           7 :         offset += kManualSetupVendorIdCharLength;
     146           7 :         ReturnErrorOnFailure(
     147             :             decimalStringWithPadding(outBuffer.SubSpan(offset, kManualSetupProductIdCharLength + 1), mPayloadContents.productID));
     148           7 :         offset += kManualSetupProductIdCharLength;
     149             :     }
     150             : 
     151          12 :     int checkDigit = Verhoeff10::CharToVal(Verhoeff10::ComputeCheckChar(outBuffer.data()));
     152          12 :     ReturnErrorOnFailure(decimalStringWithPadding(outBuffer.SubSpan(offset, 2), static_cast<uint32_t>(checkDigit)));
     153          12 :     offset += 1;
     154             : 
     155             :     // Reduce outBuffer span size to be the size of written data and to not include null-terminator.
     156          12 :     outBuffer.reduce_size(offset);
     157             : 
     158          12 :     return CHIP_NO_ERROR;
     159             : }
     160             : 
     161          13 : CHIP_ERROR ManualSetupPayloadGenerator::payloadDecimalStringRepresentation(std::string & outDecimalString)
     162             : {
     163             :     // One extra char for the check digit, another for the null terminator.
     164          13 :     char decimalString[kManualSetupLongCodeCharLength + 1 + 1] = "";
     165          13 :     MutableCharSpan outBuffer(decimalString);
     166             : 
     167          13 :     ReturnErrorOnFailure(payloadDecimalStringRepresentation(outBuffer));
     168          12 :     outDecimalString.assign(decimalString);
     169             : 
     170          12 :     return CHIP_NO_ERROR;
     171             : }
     172             : 
     173             : } // namespace chip

Generated by: LCOV version 1.14