mirror of
https://github.com/google/pebble.git
synced 2025-06-04 09:13:12 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
128
src/fw/util/legacy_checksum.c
Normal file
128
src/fw/util/legacy_checksum.c
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "util/legacy_checksum.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
// Software implementation of the legacy checksum. This emulates the behaviour
|
||||
// of the CRC peripheral in the STM32F2/F4 series MCUs and the bugs in the
|
||||
// legacy CRC driver implementation. While the raw throughput of the hardware
|
||||
// CRC peripheral is greater, it is not reentrant and so a mutex is required
|
||||
// to prevent concurrent access to the peripheral by multiple tasks. The
|
||||
// overhead of locking and unlocking the mutex, while not yet benchmarked, is
|
||||
// potentially significant enough to cancel out the increased throughput of
|
||||
// the hardware acceleration. There is also no evidence (for or against) that
|
||||
// checksums are a performance bottleneck in the first place. Given the added
|
||||
// complexity of the hardware-accelerated implementation, and the dubious
|
||||
// performance improvement of using it, hardware acceleration of checksums is a
|
||||
// case of premature optimization.
|
||||
//
|
||||
// That being said, the API for the legacy checksum is fully capable of
|
||||
// supporting a non-reentrant implementation. Simply acquire the mutex in
|
||||
// legacy_defective_checksum_init and release it in
|
||||
// legacy_defective_checksum_finish.
|
||||
|
||||
// The implementation is based on a nybble-wide table driven CRC.
|
||||
// The CRC implementation (but not the checksum based on it) has the
|
||||
// model parameters:
|
||||
// Width: 32
|
||||
// Poly: 04C11DB7
|
||||
// Init: FFFFFFFF
|
||||
// RefIn: False
|
||||
// RefOut: False
|
||||
// XorOut: 00000000
|
||||
//
|
||||
// The CRC lookup table was generated by legacy_checksum_crc_table.py
|
||||
|
||||
static const uint32_t s_lookup_table[] = {
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
|
||||
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
||||
};
|
||||
|
||||
static uint32_t prv_crc_byte(uint32_t crc, uint8_t input) {
|
||||
crc = (crc << 4) ^ s_lookup_table[((crc >> 28) ^ (input >> 4)) & 0x0f];
|
||||
crc = (crc << 4) ^ s_lookup_table[((crc >> 28) ^ (input >> 0)) & 0x0f];
|
||||
return crc;
|
||||
}
|
||||
|
||||
void legacy_defective_checksum_init(LegacyChecksum *checksum) {
|
||||
*checksum = (LegacyChecksum) {
|
||||
.reg = 0xffffffff,
|
||||
};
|
||||
}
|
||||
|
||||
void legacy_defective_checksum_update(
|
||||
LegacyChecksum * restrict checksum,
|
||||
const void * restrict data, size_t length) {
|
||||
const char * restrict data_bytes = data;
|
||||
uint32_t * restrict reg = &checksum->reg;
|
||||
uint8_t * restrict accumulator = checksum->accumulator;
|
||||
uint8_t * restrict accumulated_length = &checksum->accumulated_length;
|
||||
|
||||
if (*accumulated_length) {
|
||||
for (; *accumulated_length < 3 && length; length--) {
|
||||
accumulator[(*accumulated_length)++] = *data_bytes++;
|
||||
}
|
||||
|
||||
if (*accumulated_length == 3 && length) {
|
||||
*reg = prv_crc_byte(*reg, *data_bytes++);
|
||||
length--;
|
||||
*reg = prv_crc_byte(*reg, accumulator[2]);
|
||||
*reg = prv_crc_byte(*reg, accumulator[1]);
|
||||
*reg = prv_crc_byte(*reg, accumulator[0]);
|
||||
*accumulated_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (; length >= 4; length -= 4) {
|
||||
*reg = prv_crc_byte(*reg, data_bytes[3]);
|
||||
*reg = prv_crc_byte(*reg, data_bytes[2]);
|
||||
*reg = prv_crc_byte(*reg, data_bytes[1]);
|
||||
*reg = prv_crc_byte(*reg, data_bytes[0]);
|
||||
data_bytes += 4;
|
||||
}
|
||||
|
||||
for (; length; length--) {
|
||||
accumulator[(*accumulated_length)++] = *data_bytes++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t legacy_defective_checksum_finish(LegacyChecksum *checksum) {
|
||||
if (checksum->accumulated_length) {
|
||||
// CRC the final bytes forwards (reversed relative to the normal checksum)
|
||||
// padded on the left(!) with null bytes.
|
||||
for (int padding = 4 - checksum->accumulated_length; padding; padding--) {
|
||||
checksum->reg = prv_crc_byte(checksum->reg, 0);
|
||||
}
|
||||
for (int i = 0; i < checksum->accumulated_length; ++i) {
|
||||
checksum->reg = prv_crc_byte(checksum->reg, checksum->accumulator[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return checksum->reg;
|
||||
}
|
||||
|
||||
uint32_t legacy_defective_checksum_memory(const void * restrict data,
|
||||
size_t length) {
|
||||
LegacyChecksum checksum;
|
||||
legacy_defective_checksum_init(&checksum);
|
||||
legacy_defective_checksum_update(&checksum, data, length);
|
||||
return legacy_defective_checksum_finish(&checksum);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue