Import of the watch repository from Pebble

This commit is contained in:
Matthieu Jeanson 2024-12-12 16:43:03 -08:00 committed by Katharine Berry
commit 3b92768480
10334 changed files with 2564465 additions and 0 deletions

View file

@ -0,0 +1,50 @@
/*
* 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.
*/
#pragma once
#if defined(__clang__)
#define GCC_ONLY(x)
#else
#define GCC_ONLY(x) x
#endif
// Function attributes
#define FORMAT_FUNC(TYPE, STR_IDX, FIRST) __attribute__((__format__(TYPE, STR_IDX, FIRST)))
#define FORMAT_PRINTF(STR_IDX, FIRST) FORMAT_FUNC(__printf__, STR_IDX, FIRST)
#define ALWAYS_INLINE __attribute__((__always_inline__)) inline
#define NOINLINE __attribute__((__noinline__))
#define NORETURN __attribute__((__noreturn__)) void
#define NAKED_FUNC __attribute__((__naked__))
#define OPTIMIZE_FUNC(LVL) __attribute__((__optimize__(LVL)))
#define CONST_FUNC __attribute__((__const__))
#define PURE_FUNC __attribute__((__pure__))
// Variable attributes
#define ATTR_CLEANUP(FUNC) __attribute__((__cleanup__(FUNC)))
// Structure attributes
#define PACKED __attribute__((__packed__))
// General attributes
#define USED __attribute__((__used__))
#define UNUSED __attribute__((__unused__))
#define WEAK __attribute__((__weak__))
#define ALIAS(sym) __attribute__((__weak__, __alias__(sym)))
#define SECTION(SEC) GCC_ONLY(__attribute__((__section__(SEC))))
#define EXTERNALLY_VISIBLE GCC_ONLY(__attribute__((__externally_visible__)))

View file

@ -0,0 +1,51 @@
/*
* 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 "cobs.h"
size_t cobs_encode(void *dst_ptr, const void *src_ptr, size_t length) {
const char *src = src_ptr;
char *dst = dst_ptr;
uint8_t code = 0x01;
size_t code_idx = 0;
size_t dst_idx = 1;
for (size_t src_idx = 0; src_idx < length; ++src_idx) {
if (src[src_idx] == '\0') {
dst[code_idx] = code;
code_idx = dst_idx++;
code = 0x01;
} else {
dst[dst_idx++] = src[src_idx];
code++;
if (code == 0xff) {
if (src_idx == length - 1) {
// Special case: the final encoded block is 254 bytes long with no
// zero after it. While it's technically a valid encoding if a
// trailing zero is appended, it causes the output to be one byte
// longer than it needs to be. This violates consistent overhead
// contract and could overflow a carefully sized buffer.
break;
}
dst[code_idx] = code;
code_idx = dst_idx++;
code = 0x01;
}
}
}
dst[code_idx] = code;
return dst_idx;
}

View file

@ -0,0 +1,40 @@
/*
* 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.
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
//! An implementation of Consistent Overhead Byte Stuffing
//!
//! http://conferences.sigcomm.org/sigcomm/1997/papers/p062.pdf
//! http://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
//! Evaluates to the offset required when encoding in-place
#define COBS_OVERHEAD(n) (((n) + 253) / 254)
//! Evaluates to the maximum buffer size required to hold n bytes of data
//! after COBS encoding.
#define MAX_SIZE_AFTER_COBS_ENCODING(n) ((n) + COBS_OVERHEAD(n))
//! COBS-encode a buffer out to another buffer.
//!
//! @param [out] dst destination buffer. The buffer must be at least
//! MAX_SIZE_AFTER_COBS_ENCODING(length) bytes long.
//! @param [in] src source buffer
//! @param length length of src
size_t cobs_encode(void * restrict dst, const void * restrict src,
size_t length);

View file

@ -0,0 +1,48 @@
/*
* 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/crc32.h"
// Nybble-wide table driven CRC-32 algorithm
//
// A compromise between speed and size, this algorithm uses a lookup table to
// calculate the CRC four bits at a time with a size cost of only 64 bytes. By
// contrast, a byte-wide algorithm requires a lookup table sixteen times larger!
//
// The lookup table is generated by the crc32_lut.py
static const uint32_t s_lookup_table[] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
};
uint32_t crc32(uint32_t crc, const void * restrict data, size_t length) {
if (data == 0) {
return 0;
}
const uint8_t * restrict bytes = data;
crc ^= 0xffffffff;
while (length--) {
crc = (crc >> 4) ^ s_lookup_table[(crc ^ *bytes) & 0xf];
crc = (crc >> 4) ^ s_lookup_table[(crc ^ (*bytes >> 4)) & 0xf];
bytes++;
}
crc ^= 0xffffffff;
return crc;
}

View file

@ -0,0 +1,67 @@
/*
* 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.
*/
#pragma once
//! \file
//! Calculate the CRC-32 checksum of data.
//!
//! The checksum is the standard CRC-32 used by zlib, PNG and others.
//! The model parameters for the algorithm, as described in A Painless Guide to
//! CRC Error Detection Algorithms (http://www.zlib.net/crc_v3.txt), are:
//! Name: "CRC-32"
//! Width: 32
//! Poly: 04C11DB7
//! Init: FFFFFFFF
//! RefIn: True
//! RefOut: True
//! XorOut: FFFFFFFF
//! Check: CBF43926
#include <stdint.h>
#include <string.h>
//! Update a running CRC-32 checksum with the bytes of data and return the
//! updated CRC-32. If data is NULL, the function returns the required initial
//! value for the CRC.
//!
//! This function is drop-in compatible with zlib's crc32 function.
//!
//! \par Usage
//! \code
//! uint32_t crc = crc32(0, NULL, 0);
//! while (read_buffer(data, length)) {
//! crc = crc32(crc, data, length);
//! }
//! \endcode
uint32_t crc32(uint32_t crc, const void * restrict data, size_t length);
//! The initial CRC register value for a standard CRC-32 checksum.
//!
//! It is the same value as is returned by the `crc32` function when data is
//! NULL.
//!
//! \code
//! assert(CRC32_INIT == crc32(0, NULL, 0));
//! \endcode
#define CRC32_INIT (0)
//! The residue constant of the CRC-32 algorithm.
//!
//! If the CRC-32 value of a message is appended (little-endian) onto the
//! end of the message, the CRC-32 of the concatenated message and CRC will be
//! equal to CRC32_RESIDUE if the message has not been corrupted in transit.
#define CRC32_RESIDUE (0x2144DF1C)

View file

@ -0,0 +1,47 @@
/*
* 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 "delay.h"
#include "util/attributes.h"
#include "stm32f7xx.h"
#include <inttypes.h>
void delay_us(uint32_t us) {
// Empirically (measured on a C2 bb), 1 loop = 1 cycle. (sysclk @
// 16MHz, I-Cache disabled) Alignment of code will have some impact on how
// long this actually takes
uint32_t delay_loops = us * 16;
__asm volatile (
"spinloop: \n"
" subs %[delay_loops], #1 \n"
" bne spinloop \n"
: [delay_loops] "+r" (delay_loops) // read-write operand
:
: "cc"
);
}
void delay_ms(uint32_t millis) {
// delay_us(millis*1000) is not used because a long delay could easily
// overflow the veriable. Without the outer loop, a delay of even five
// seconds would overflow.
while (millis--) {
delay_us(1000);
}
}

View file

@ -0,0 +1,25 @@
/*
* 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.
*/
#pragma once
#include <inttypes.h>
//! Carefully timed spinloop that allows one to delay at a microsecond
//! granularity.
void delay_us(uint32_t us);
void delay_ms(uint32_t millis);

View file

@ -0,0 +1,31 @@
/*
* 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/math.h"
#include <stdint.h>
#include <stdbool.h>
int ceil_log_two(uint32_t n) {
// clz stands for Count Leading Zeroes. We use it to find the MSB
int msb = 31 - __builtin_clz(n);
// popcount counts the number of set bits in a word (1's)
bool power_of_two = __builtin_popcount(n) == 1;
// if not exact power of two, use the next power of two
// we want to err on the side of caution and want to
// always round up
return ((power_of_two) ? msb : (msb + 1));
}

View file

@ -0,0 +1,79 @@
/*
* 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.
*/
#pragma once
#include <stdint.h>
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define ABS(a) (((a) > 0) ? (a) : -1 * (a))
#define CLIP(n, min, max) ((n) < (min) ? (min) : ((n) > (max) ? (max) : (n)))
#define ROUND(num, denom) (((num) + ((denom) / 2))/(denom))
#define WITHIN(n, min, max) ((n) >= (min) && (n) <= (max))
#define RANGE_WITHIN(n_min, n_max, min, max) ((n_min) >= (min) && (n_max) <= (max))
// Divide num by denom, rounding up (ceil(0.5) is 1.0, and ceil(-0.5) is 0.0)
// ex. 3, 4 (ie. 3/4) : returns 1
// ex. -3, 4 : returns 0
#define DIVIDE_CEIL(num, denom) ((num + (denom - 1)) / denom)
// Round value up to the next increment of modulus
// ex. val = 152 mod = 32 : returns 160
// val = -32 mod = 90 : returns -90
#define ROUND_TO_MOD_CEIL(val, mod) \
((val >= 0) ? \
((((val) + ABS(ABS(mod) - 1)) / ABS(mod)) * ABS(mod)) : \
-((((-val) + ABS(ABS(mod) - 1)) / ABS(mod)) * ABS(mod)))
/*
* find the log base two of a number rounded up
*/
int ceil_log_two(uint32_t n);
/*
* The -Wtype-limits flag generated an error with the previous IS_SIGNED maco.
* If an unsigned number was passed in the macro would check if the unsigned number was less than 0.
*/
//! Determine whether a variable is signed or not.
//! @param var The variable to evaluate.
//! @return true if the variable is signed.
#define IS_SIGNED(var) (__builtin_choose_expr( \
__builtin_types_compatible_p(__typeof__(var), unsigned char), false, \
__builtin_choose_expr( \
__builtin_types_compatible_p(__typeof__(var), unsigned short), false, \
__builtin_choose_expr( \
__builtin_types_compatible_p(__typeof__(var), unsigned int), false, \
__builtin_choose_expr( \
__builtin_types_compatible_p(__typeof__(var), unsigned long), false, \
__builtin_choose_expr( \
__builtin_types_compatible_p(__typeof__(var), unsigned long long), false, true))))) \
)
/**
* Compute the next backoff interval using a bounded binary expoential backoff formula.
*
* @param[in,out] attempt The number of retries performed so far. This count will be incremented
* by the function.
* @param[in] initial_value The inital backoff interval. Subsequent backoff attempts will be this
* number multiplied by a power of 2.
* @param[in] max_value The maximum backoff interval that returned by the function.
* @return The next backoff interval.
*/
uint32_t next_exponential_backoff(uint32_t *attempt, uint32_t initial_value, uint32_t max_value);
//! Find the greatest common divisor of two numbers.
uint32_t gcd(uint32_t a, uint32_t b);

View file

@ -0,0 +1,46 @@
/*
* 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 "misc.h"
#include "drivers/dbgserial.h"
#include <stdint.h>
void itoa_hex(uint32_t num, char *buffer, int buffer_length) {
if (buffer_length < 11) {
dbgserial_putstr("itoa buffer too small");
return;
}
*buffer++ = '0';
*buffer++ = 'x';
for (int i = 7; i >= 0; --i) {
uint32_t digit = (num & (0xf << (i * 4))) >> (i * 4);
char c;
if (digit < 0xa) {
c = '0' + digit;
} else if (digit < 0x10) {
c = 'a' + (digit - 0xa);
} else {
c = ' ';
}
*buffer++ = c;
}
*buffer = '\0';
}

View file

@ -0,0 +1,31 @@
/*
* 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.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MHZ_TO_HZ(hz) (((uint32_t)(hz)) * 1000000)
#define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
//! Convert num to a hex string and put in buffer
void itoa_hex(uint32_t num, char *buffer, int buffer_length);

View file

@ -0,0 +1,80 @@
/*
* 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.
*/
#pragma once
#include <stdint.h>
// When compiling test, the host OS might have conflicting defines for this:
#undef ntohs
#undef htons
#undef ntohl
#undef htonl
#undef ltohs
#undef ltohl
static inline uint16_t ntohs(uint16_t v) {
// return ((v & 0x00ff) << 8) | ((v & 0xff00) >> 8);
return __builtin_bswap16(v);
}
static inline uint16_t htons(uint16_t v) {
return ntohs(v);
}
static inline uint32_t ntohl(uint32_t v) {
// return ((v & 0x000000ff) << 24) |
// ((v & 0x0000ff00) << 8) |
// ((v & 0x00ff0000) >> 8) |
// ((v & 0xff000000) >> 24);
return __builtin_bswap32(v);
}
static inline uint32_t htonl(uint32_t v) {
return ntohl(v);
}
#define ltohs(v) (v)
#define ltohl(v) (v)
// Types for values in network byte-order. They are wrapped in structs so that
// the compiler will disallow implicit casting of these types to or from
// integral types. This way it is a compile error to try using variables of
// these types without first performing a byte-order conversion.
// There is no overhead for wrapping the values in structs.
typedef struct net16 {
uint16_t v;
} net16;
typedef struct net32 {
uint32_t v;
} net32;
static inline uint16_t ntoh16(net16 net) {
return ntohs(net.v);
}
static inline net16 hton16(uint16_t v) {
return (net16){ htons(v) };
}
static inline uint32_t ntoh32(net32 net) {
return ntohl(net.v);
}
static inline net32 hton32(uint32_t v) {
return (net32){ htonl(v) };
}

View file

@ -0,0 +1,31 @@
/*
* 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.
*/
#pragma once
//! Calculate the length of an array, based on the size of the element type.
//! @param array The array to be evaluated.
//! @return The length of the array.
#define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
//! Calculate the length of a literal array based on the size of the given type
//! This is usable in contexts that require compile time constants
//! @param type Type of the elements
//! @param array Literal definition of the array
//! @return Length of the array in bytes
#define STATIC_ARRAY_LENGTH(type, array) (sizeof((type[]) array) / sizeof(type))
#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)

View file

@ -0,0 +1,88 @@
/*
* 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 "sle.h"
#include "system/passert.h"
// See waftools/sparse_length_encoding.py for more info on SLE encoding/decoding
typedef struct {
const uint8_t *data;
uint32_t index;
uint32_t length;
} ReadByteStream;
typedef struct {
uint8_t *data;
uint32_t index;
uint32_t length;
} WriteByteStream;
static uint8_t prv_byte_stream_read(ReadByteStream *stream) {
PBL_ASSERTN(stream->index < stream->length);
return stream->data[stream->index++];
}
static void prv_byte_stream_write(WriteByteStream *stream, uint8_t data) {
PBL_ASSERTN(stream->index < stream->length);
stream->data[stream->index++] = data;
}
uint32_t sle_decode(const uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len) {
ReadByteStream in_stream = {
.data = in,
.length = in_len
};
WriteByteStream out_stream = {
.data = out,
.length = out_len
};
const uint8_t escape = prv_byte_stream_read(&in_stream);
while (true) {
const uint8_t byte = prv_byte_stream_read(&in_stream);
if (byte != escape) {
// simply write the byte into the output stream
prv_byte_stream_write(&out_stream, byte);
continue;
}
// read the escape code
const uint8_t code = prv_byte_stream_read(&in_stream);
if (code == 0) {
// end of stream
break;
} else if (code == 1) {
// literal escape byte
prv_byte_stream_write(&out_stream, escape);
} else {
// a sequence of zeros
uint16_t count;
if ((code & 0x80) == 0) {
// the count is only 1 byte (1-127)
count = code;
} else {
// the count is 2 bytes
count = (((uint16_t)(code & 0x7f) << 8) | prv_byte_stream_read(&in_stream)) + 0x80;
}
for (int i = 0; i < count; ++i) {
prv_byte_stream_write(&out_stream, 0);
}
}
}
return out_stream.index;
}

View file

@ -0,0 +1,21 @@
/*
* 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.
*/
#pragma once
#include <stdint.h>
uint32_t sle_decode(const uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len);