namespace RioJoy.Core.Protocol;

/// <summary>
/// The RIO packet checksum: the low 7 bits of the sum of the low 7 bits of
/// every byte in the command+payload (the checksum byte itself excluded).
/// Port of the build loop in <c>SendCommand</c> (riovjoy2.cpp#L1227) and the
/// verify loop in <c>ReadCommBlock</c> (riovjoy2.cpp#L884); see docs/PROTOCOL.md §2.
/// </summary>
public static class RioChecksum
{
    /// <summary>
    /// Compute the 7-bit checksum over the command byte followed by its payload
    /// bytes (not the checksum byte): <paramref name="count"/> bytes of
    /// <paramref name="commandAndPayload"/> starting at <paramref name="offset"/>.
    /// </summary>
    public static byte Compute(byte[] commandAndPayload, int offset, int count)
    {
        if (commandAndPayload is null) throw new ArgumentNullException(nameof(commandAndPayload));

        byte sum = 0;
        for (int i = offset; i < offset + count; i++)
            sum += (byte)(commandAndPayload[i] & 0x7F);

        return (byte)(sum & 0x7F);
    }

    /// <summary>Compute the checksum over all of <paramref name="commandAndPayload"/>.</summary>
    public static byte Compute(byte[] commandAndPayload) =>
        Compute(commandAndPayload, 0, commandAndPayload?.Length ?? 0);
}
