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

65
docs/battery_state.dot Normal file
View file

@ -0,0 +1,65 @@
digraph G {
compound=true;
Initialized [label=<<b>Initialized (0)</b><br/><font color='#6E6E6E'>q is unknown</font>>];
PreStandby [label=<<b>PreStandby (8)</b><br/><font color='#6E6E6E'>q &lt; 2 mAh</font>>];
Standby [label=<<b>Standby (9)</b><br/><font color='#6E6E6E'>q &lt; 2 mAh (unless manually entered)</font>>];
/* Charging flow */
subgraph cluster0 {
{rank=same;
FullPlugged [label=<<b>FullPlugged (4)</b><br/><font color='#6E6E6E'>q ~= 130mAh</font>>, group="charging"];
O1[style=invis];
}
{rank=same;
HighCharging [label=<<b>HighCharging (5)</b><br/><font color='#6E6E6E'>25 mAh &lt;= q &lt; 130 mAh</font>>, group="charging"];
O2[style=invis];
}
{rank=same;
LowCharging [label=<<b>LowCharging (6)</b><br/><font color='#6E6E6E'>5 mAh &lt;= q &lt; 25 mAh</font>>, group="charging"];
O3[style=invis];
}
{rank=same;
CriticalCharging [label=<<b>CriticalCharging (7)</b><br/><font color='#6E6E6E'>q &lt; 5 mAh</font>>, group="charging"];
O4[style=invis];
}
CriticalCharging -> LowCharging [label=">3.2V", constraint=false, weight=100];
LowCharging -> HighCharging [label=">3.8V", constraint=false, weight=100];
HighCharging -> FullPlugged [color=green, constraint=false, weight=100];
edge[style=invis];
O1->O2->O3->O4;
color=blue;
}
subgraph cluster1 {
FullDischarging [label=<<b>FullDischarging (1)</b><br/><font color='#6E6E6E'>q &gt; 30mAh (~125h)</font>>, group="discharging"];
LowDischarging [label=<<b>LowDischarging (2)</b><br/><font color='#6E6E6E'>5 mAh &lt;= q &lt; 30mAh (~31h)</font>>, group="discharging"];
CriticalDischarging [label=<<b>CriticalDischarging (3)</b><br/><font color='#6E6E6E'>2 mAh &lt;= q &lt; 5 mAh (~3h)</font>>, group="discharging"];
FullDischarging -> LowDischarging [label="<=3.7V"];
LowDischarging -> CriticalDischarging [label="<=3.3V"];
CriticalDischarging -> PreStandby [label="<=3.1V"];
color=red;
}
Initialized -> FullDischarging [color=red, lhead=cluster1];
Initialized -> FullPlugged [color=blue, lhead=cluster0, constraint=false];
FullPlugged -> FullDischarging [color=red]
CriticalCharging -> PreStandby [color=red, weight=0.1];
HighCharging -> FullDischarging [color=red, constraint=false, weight=0.1];
LowCharging -> FullDischarging [color=red, constraint=false, weight=0.1];
FullDischarging -> LowCharging [color=blue, weight=0.01];
FullDischarging -> HighCharging [color=blue, constraint=false, weight=0.1];
LowDischarging -> LowCharging [color=blue, constraint=false, weight=0.1];
CriticalDischarging -> LowCharging [color=blue, constraint=false, weight=0.1];
PreStandby -> CriticalCharging [color=blue, weight=0.1];
PreStandby -> Standby [label="30s timeout", weight=0.1];
}

500
docs/common.dox Normal file
View file

@ -0,0 +1,500 @@
/**
@defgroup Foundation Foundation
\brief The core of the Pebble SDK
The Pebble SDK consists of different frameworks that are organized by functionality.
Each framework includes an API and provides access to the software libraries supported
natively by Pebble OS. You use these interfaces (APIs) in the C programming
language to write software for the Pebble platform.
Frameworks are grouped hierarchically into Foundation, Graphics, Standard C and User Interface.
The Foundation framework is the core of the Pebble OS.
@defgroup Graphics Graphics
\brief Low-level drawing routines
The Graphics framework defines a set of APIs that can be used to draw paths, primitives and text,
as well as handle the loading of fonts and the setting of graphics contexts for compositing, fill color
and text color.
@defgroup Smartstrap
\brief Communicating with a Smartstrap
Smartstrap APIs allow Pebble watches to communicate with electronics connected to the
watch through the accessory port.
Apps communicate with smartstraps by manipulating the attributes which the smartstrap supports
or by reading and writing raw data using the raw data attribute (see \ref
SMARTSTRAP_RAW_DATA_SERVICE_ID and \ref SMARTSTRAP_RAW_DATA_ATTRIBUTE_ID). A service is a collection of
attributes which may be supported by a smartstrap. Once a smartstrap is connected, the
availability handler will be called (if subscribed) for each service which is supported by the
smartstrap. Then, the app may make read and write requests to attributes within that service on
the smartstrap.
Performing a read request on an attribute will cause the did_read handler to be called for the
attribute when either a valid response is received from the smartstrap, or some error (i.e. a
timeout) occurs.
Performing a write request on an attribute will cause the did_write handler to be called for the
attribute when the write is completed or an error occurs.
When either the first attribute is created (see \ref smartstrap_attribute_create), or an
availability_did_change handler is subscribed (see \ref smartstrap_subscribe), whichever comes
first, power will be applied to the smartstrap, and connection establishment will begin. As part
of the connection establishment, the smartstrap will report the services which it supports, at
which point the smartstrap APIs will report them as being available and allow requests to be
issued. If all created attributes are destroyed (see \ref smartstrap_attribute_destroy) and the
availability_did_change handler is unsubscribed (see \ref smartstrap_unsubscribe), power will no
longer be applied to the smartstrap and the services which it supported will no longer be
available.
Multiple attributes may have a read or write request pending at any given time, but individual
attributes may only have a single request (either read or write) pending at any given time.
Calls made to \ref smartstrap_attribute_create on a platform that does not support smartstraps
will return NULL. Other calls will do nothing, and return SmartstrapResultNotPresent if
possible.
For code samples, a list of available attributes, and technical details of the Smartstrap
protocol, see the
<a href="//developer.getpebble.com/guides/hardware/">Building Smartstraps Guide</a>.
@defgroup UI User Interface
\brief Everything related to user interface
The User Interface framework enables your Pebble watchface or watchapp to handle basic UI components,
like clicks, layers, vibes, windows and window stacks.
@defgroup Fonts Fonts
\brief Custom and system fonts
Pebble OS provides you with a wide range of system fonts that you can use when you need to display and
render text or numbers in your Pebble watchface or watchapp.
If you want to use a system font, you call fonts_get_system_font() and simply pass it the name of the
system font you want.
To use a custom font, call fonts_load_custom_font(). The sample code feature_custom_font shows how you can
do this programmatically, using a font resource to convert a TrueType font into a rasterized version of that
font at a specified font size.
For example:
\code{.c}
GFont custom_font = fonts_load_custom_font
(resource_get_handle(RESOURCE_ID_FONT_OSP_DIN_44));
\endcode
Raster Gothic Condensed is the font used throughout the Pebble system, largely because it is optimized
for monochromatic displays. Pebble selected this font because it allows a relatively large number of
characters to be displayed on a single line, also because the font has an excellent readability vs. size ratio.
Refer to the chapter \htmlinclude UsingResources.html which explains how to work with font resources and embed
a font into your app.
@defgroup Math Math
\brief Math routines.
Below is a code example that uses the trigonometry functions to calculate the coordinate at which
the second hand of a watch ends, using seconds from the system time.
\code{.c}
GPoint secondHand;
GPoint center;
struct tm *tick_time = ...;
int32_t secondHandLength = ...;
...
int32_t second_angle = TRIG_MAX_ANGLE * tick_time->tm_sec / 60;
secondHand.y = (-cos_lookup(second_angle) * secondHandLength / TRIG_MAX_RATIO) + center.y;
secondHand.x = (sin_lookup(second_angle) * secondHandLength / TRIG_MAX_RATIO) + center.x;
\endcode
@defgroup EventService Event Service
\brief APIs to handle event services
Pebble OS provides you with a set of APIs for handling event services, like accelerometer taps, app focus
for interactivity, battery states, Bluetooth connections, and tick timers to call when a time component has
changed. You use event services to be notified, for example, when something happens on Pebble, like losing
the connection to the phone or when a notification covers the screen and requires your Pebble game to pause.
@defgroup App App
\brief App entry point and event loop.
App is a module that provides you with an event loop for your Pebble app.
All interaction between Pebble apps and the underlying Pebble OS takes place through an event loop.
Before calling the \ref app_event_loop() function, you subscribe to event services and implement event handlers.
Each handler receives specific types of Events dispatched throughout the life of the Pebble watchapp.
The \ref app_event_loop() function takes care of both waiting for new events to become available on the
watchapp event bus and routing new events to the appropriate handler. \ref EventService allows an app to
directly register for different types of events. This function will block until the watchapp is ready
to exit, and should be placed in the app's main() function.
A watchapp typically configures and uses the \ref app_event_loop() as follows:
\code{.c}
int main(void) {
// do set up here
// Enter the main event loop. This will block until the app is ready to exit.
app_event_loop();
// do clean up here
}
\endcode
@defgroup StandardC Standard C
\brief Standard C types, functions, constants, etc.
The standard C functions available here, such as \ref snprintf() and \ref time(), are provided by the firmware. Using these functions will not significantly increase the size of your app beyond what is needed to call the function. You may use other standard C functions not listed here, but be aware that not all will successfully be added to your app, and if they are added, your app's binary size will increase accordingly.
@addtogroup StandardC
@{
@defgroup StandardMath Math
\brief Standard math functions.
@addtogroup StandardMath
@{
\fn int rand()
\brief Generate a pseudo-random integer between 0 and \ref RAND_MAX inclusive. This function can be seeded by \ref srand().
A simple way to change the range to be an integer between 0 and n-1 inclusive is using \% e.g. `rand() % n`.
\return The pseudo-randomly generated number
\fn void srand(unsigned int seed)
\brief Seed the pseudo-random number generator.
When your app starts, the pseudo-random number generator is automatically seeded with a random number that is generated by a high-entropy hardware random number generator.
This function affects subsequent calls to \ref rand() to produce a sequence of numbers for a given seed value. You can use this to either create a different sequence of numbers by always using a different seed or to obtain the same sequence of numbers by reusing the same seed.
\param seed The source number used to generate a sequence of pseudo-random numbers
\def RAND_MAX
\brief The maximum integer value \ref rand() may return.
@}
@defgroup StandardLocale Locale
\brief Standard locale functions.
@addtogroup StandardLocale
@{
\fn char *setlocale(int category, char *locale)
\brief Set the app's locale for a category of routines.
`setlocale` can be used to:
- set the app's locale to a specific locale: `setlocale(LC_ALL, "en_CA")`
- set the app's locale to the system locale: `setlocale(LC_ALL, "")`
- get the app's curent locale: `setlocale(LC_ALL, NULL)`
\param category The category of routines for which to set the locale
\param locale The ISO formatted locale to use, or "" for the system locale
\return the locale after the change is applied, NULL on failure (e.g. unsuported category)
\note Currently, we only support two categories: LC_ALL and LC_TIME
@}
@defgroup StandardMemory Memory
\brief Standard memory functions.
@addtogroup StandardMemory
@{
\fn void *malloc(size_t size)
\brief Allocates a requested amount of memory.
\param size The number of bytes to allocate
\return A pointer to the allocated memory or NULL on error.
\fn void free(void *ptr)
\brief Frees previously allocated memory.
\param ptr The memory buffer to free.
\fn void *calloc(size_t count, size_t size)
\brief Allocates space for count objects that are size bytes and fills the
memory with bytes of value 0
\param count The number of objects to allocate space for
\param size The size of the object type being allocated
\return A pointer to the allocated memory or NULL on error.
\fn void *realloc(void *ptr, size_t size)
\brief Takes the memory allocated at ptr and changes the length of its
allocation to the size specified. Copies the smaller of the length of the
original allocation or the new size into the newly allocated buffer.
\param ptr The memory allocation to be changed
\param size The size to change the ptr allocation to
\return A pointer to the new allocated memory or NULL on error
\fn int memcmp(const void *ptr1, const void *ptr2, size_t n)
\brief Compares the first n bytes of memory regions ptr1 and ptr2
\param ptr1 The pointer to the first memory region to compare
\param ptr2 The pointer to the second memory region to compare
\param n The number of bytes to compare
\return 0 if the first n bytes of ptr1 and ptr 2 match. Otherwise, the sign is determined by the sign of the difference between the first pair of bytes that differ in ptr1 and ptr2.
\fn void *memcpy(void *dest, const void *src, size_t n)
\brief Copies n bytes from src to dest.
\param dest The pointer to the destination memory region
\param src The pointer to the source memory region
\param n The number of bytes to copy
\fn void *memmove(void *dest, const void *src, size_t n);
\brief Copies n bytes from src to dest by first copying to a temporary area first, allowing dest and src to potentially overlap. This can be used to move data to a location that overlaps its previous location.
\param dest The pointer to the destination memory region
\param src The pointer to the source memory region
\param n The number of bytes to copy
\fn void *memset(void *dest, int c, size_t n);
\brief Sets n bytes to c starting at dest. This can be used to clear a memory region for example if c is 0.
\param dest The pointer to the destination memory region
\param c The integer used as an unsigned char to assign to each byte
\param n The number of bytes to set
\typedef size_t
\brief size as an unsigned integer
@}
@defgroup StandardIO Format
\brief Standard formatting. If you're looking for input/output functions, check out the \ref Logging API.
@addtogroup StandardIO
@{
\fn int snprintf(char *str, size_t n, const *fmt, ...);
\brief Format a string into a buffer. The Pebble-supported format specifiers are displayed below.
\param str The string buffer to write the formatted string into
\param n The maximum size of the buffer
\param fmt The C formatting string
\return The number of bytes written
\htmlonly
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
</style>
<table class="tg">
<tr>
<th class="tg-031e">Specifier</th>
<th class="tg-031e">Output</th>
<th class="tg-031e">Example</th>
</tr>
<tr>
<td class="tg-031e">d or i</td>
<td class="tg-031e">Signed decimal integer</td>
<td class="tg-031e">294<br>-294</td>
</tr>
<tr>
<td class="tg-031e">u</td>
<td class="tg-031e">Unsigned decimal integer</td>
<td class="tg-031e">7235</td>
</tr>
<tr>
<td class="tg-031e">o</td>
<td class="tg-031e">Unsigned octal</td>
<td class="tg-031e">610</td>
</tr>
<tr>
<td class="tg-031e">x</td>
<td class="tg-031e">Unsigned hexadecimal integer</td>
<td class="tg-031e">8b2</td>
</tr>
<tr>
<td class="tg-031e">X</td>
<td class="tg-031e">Unsigned hexadecimal integer (uppercase)</td>
<td class="tg-031e">8B2</td>
</tr>
<tr>
<td class="tg-031e">c</td>
<td class="tg-031e">Character</td>
<td class="tg-031e">h</td>
</tr>
<tr>
<td class="tg-031e">s</td>
<td class="tg-031e">Null-terminated string of characters</td>
<td class="tg-031e">pebble</td>
</tr>
<tr>
<td class="tg-031e">p</td>
<td class="tg-031e">Pointer address</td>
<td class="tg-031e">0xb8000000</td>
</tr>
<tr>
<td class="tg-031e">%</td>
<td class="tg-031e">A % followed by another % character will write a single % to the stream.</td>
<td class="tg-031e">%</td>
</tr>
</table>
<br>
\endhtmlonly
\details Length specifiers can also be combined with the format specifiers above:
\htmlonly
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
.tg .tg-s6z2{text-align:center}
</style>
<table class="tg">
<tr>
<th class="tg-031e"></th>
<th class="tg-s6z2">u o x X</th>
<th class="tg-s6z2">c</th>
<th class="tg-s6z2">s</th>
<th class="tg-s6z2">p</th>
<th class="tg-s6z2">n</th>
</tr>
<tr>
<td class="tg-031e">(none)</td>
<td class="tg-031e">unsigned int</td>
<td class="tg-031e">int</td>
<td class="tg-031e">char*</td>
<td class="tg-031e">void*</td>
<td class="tg-031e">int*</td>
</tr>
<tr>
<td class="tg-031e">h</td>
<td class="tg-031e">unsigned short int</td>
<td class="tg-031e"></td>
<td class="tg-031e"></td>
<td class="tg-031e"></td>
<td class="tg-031e">short int*</td>
</tr>
<tr>
<td class="tg-031e">l</td>
<td class="tg-031e">unsigned long int</td>
<td class="tg-031e">wint_t</td>
<td class="tg-031e">wchar_t*</td>
<td class="tg-031e"></td>
<td class="tg-031e">long int*</td>
</tr>
</table>
\endhtmlonly
@}
@defgroup StandardString String
\brief Standard C-string manipulation.
@addtogroup StandardString
@{
\fn int strcmp(const char *str1, const char *str2)
\brief Compares the null terminated strings str1 and str2 to each other.
\param str1 The first C string to compare
\param str2 The second C string to compare
\return The difference of the first differing pair of bytes or 0 if the strings are identical
\fn int strncmp(const char *str1, const char *str2, size_t n)
\brief Compares the null terminated strings str1 and str2 to each other for up to n bytes. Comparison ends when a null is read or when n bytes are read, whichever happens first.
\param str1 The first C string to compare
\param str2 The second C string to compare
\param n The maximum number of bytes to compare
\return The difference of the first differing pair of bytes or the final pair of bytes read or 0 if the portions of the strings read are identical
\fn char *strcpy(char *dest, const char *src)
\brief Copies the string in src into dest and null terminates dest. There should be no overlap of dest and src in memory.
\param dest The destination buffer with enough space for src
\param src The source C string
\return The destination buffer dest
\fn char *strncpy(char *dest, const char *src, size_t n)
\brief Copies up to n bytes from the string in src into dest and null terminates dest. If dest is null terminated before n bytes have been written, null bytes will continue to be written until n bytes total were written. There should be no overlap of dest and src in memory.
\param dest The destination buffer with enough space for n bytes
\param src The source string
\param n The number of bytes to copy
\return The destination buffer dest
\fn char *strcat(char *dest, const char *src)
\brief Concatenates the string in src to the end of the string pointed by dest and null terminates dest. There should be no overlap of dest and src.
\param dest The destination buffer with enough space for src beyond the null character
\param src The source C string
\return The destination buffer dest
\fn char *strncat(char *dest, const char *src, size_t n)
\brief Concatenates up to n bytes from the string in src to the end of the string pointed by dest and null terminates dest. There should be no overlap of dest and src in memeory.
\param dest The destination buffer with enough space for src beyond the null character
\param src The source string
\param n The maximum number of bytes to copy
\return The destination buffer dest
\fn size_t strlen(const char *str)
\brief Calculates the length of a null terminated string.
\param str The C string.
\return The length of the C string str.
@}
@addtogroup StandardTime
@{
\typedef time_t
time in seconds since the epoch, January 1st 1970
@}
\typedef unsigned int uint32_t
\brief 32-bit unsigned integer number
\typedef unsigned int uint16_t
\brief 16-bit unsigned integer number
@}
@defgroup Misc Miscellaneous
\brief Miscellaneous
Useful helper functionality for building your pebble application that doesn't fit in any other category.
*/
/* stdio.h */
int snprintf(char *str, size_t n, const *fmt, ...);
/* stdlib.h */
#define RAND_MAX
int rand();
void srand(unsigned int seed);
void *malloc(size_t size);
void *calloc(size_t count, size_t size);
void *realloc(void *ptr, size_t size);
void free(void *ptr);
/* string.h */
typedef unsigned int size_t;
int memcmp(const void *ptr1, const void *ptr2, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
void *memset(void *dest, int c, size_t n);
int strcmp(const char *str1, const char *str2);
int strncmp(const char *str1, const char *str2, size_t n);
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
size_t strlen(const char *str);
/* locale.h */
char *setlocale(int category, char *locale);
/* time.h */
typedef unsigned int time_t;
/* C99 integer types */
typedef int int8_t;
typedef int uint8_t;
typedef int int16_t;
typedef int uint16_t;
typedef int int32_t;
typedef int uint32_t;
typedef int int64_t;
typedef int uint64_t;

11
docs/docstring-help.md Normal file
View file

@ -0,0 +1,11 @@
Doxygen pro tips
---
- Define top-level groups and other doxygen constructs in `docs/common.dox`.
- The main page can be found in `docs/mainpage_sdk.dox`
- Use \ref to create a cross reference in the documentation to another group, function, struct, or any kind of symbol, for example: `Use \ref app_event_loop() to do awesome shit.` will create a clickable link to the documentation of app_event_loop. Don't forget to add the () parens if the symbol is a function! Using angle brackets like <app_event_loop()> doesn't seem to work reliably, nor does the automatic detection of symbols.
- Use the directive `@internal` to indicate that a piece of documentation is internal and should not be included in the public SDK documentation. You can add the @internal halfway, so that the first part of your docstrings will be included in the public SDK documentation, and the part after the @internal directive will also get included in our internal docs.
- Use `@param param_name Description of param` to document a function parameter.
- Use `@return Description of return value` to document the return value of a function.
- If you need to add a file or directory that doxygen should index, add its path to `INPUT` in the Doxyfile-SDK configuration file.
- If you want to make a cross-reference to an external doc page (the conceptual pages on developer.getpebble.com), create an .html file in /docs/external_refs, containing only a <a> link to the page. Then use `\htmlinclude my_ref.html` to include that link in the docs. This extra level of indirection will make it easy to relocate external pages later on.

View file

@ -0,0 +1,17 @@
<!--
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.
-->
<a href="https://developer.getpebble.com/guides/pebble-apps/display-and-animations/layers/">User Interface Layers chapter in the Pebble Developer Guides</a>

View file

@ -0,0 +1,17 @@
<!--
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.
-->
<a href="https://developer.getpebble.com/guides/pebble-apps/resources/">App Resources in the Pebble Developer Guides</a>

View file

@ -0,0 +1,17 @@
<!--
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.
-->
<a href="http://developer.getpebble.com/guides/pebble-apps/communications/">App Communication in the Pebble Developer Guides</a>

View file

@ -0,0 +1,17 @@
<!--
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.
-->
<a href="http://developer.getpebble.com/sdk/migration-guide/">2.0 Migration Guide</a>

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
docs/images/animations.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/images/app_loop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/images/app_message.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/images/app_sync.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
docs/images/compops.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/images/fonts.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
docs/images/galign.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/images/gbitmap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
docs/images/menu_layer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
docs/images/text_layer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View file

@ -0,0 +1,85 @@
SPI Flash Imaging Using The Serial Console
==========================================
NOTE: This document describes the original method of flash imaging
over the serial console. It is no longer used and has been superseded by
newer, faster methods.
By default the serial console is in logging mode, where log messages
are echoed to the screen as they are issued. To enter the serial
prompt, send a CTRL-C character to the serial console. The prompt
looks like a single right angle bracket ('>'). Commands may be typed
at this prompt and executed using the enter key.
There are several commands available that can be used to manipulate
the SPI flash contents.
dump flash <address> <length>
=============================
This command will dump a section of SPI flash. The address must be specified
in hex with a leading '0x'. The length is in bytes.
Ex:
>dump flash 0x200000 128
[00:26:38.263] ../src/core/console/prompt.c:115> Data at address 0x200000
[00:26:38.271] ../src/core/util/hexdump.c:11> 0000 0c 00 00 00 74 bf 03 00 32 9a 8a 4b 90 81 00 20 ....t... 2..K...
[00:26:38.283] ../src/core/util/hexdump.c:11> 0010 2d a0 01 08 7d a0 01 08 19 93 01 08 7d a0 01 08 -...}... ....}...
[00:26:38.294] ../src/core/util/hexdump.c:11> 0020 7d a0 01 08 7d a0 01 08 00 00 00 00 00 00 00 00 }...}... ........
[00:26:38.307] ../src/core/util/hexdump.c:11> 0030 00 00 00 00 00 00 00 00 01 8a 01 08 7d a0 01 08 ........ ....}...
[00:26:38.319] ../src/core/util/hexdump.c:11> 0040 00 00 00 00 9d 8a 01 08 d9 8a 01 08 7d a0 01 08 ........ ....}...
[00:26:38.332] ../src/core/util/hexdump.c:11> 0050 7d a0 01 08 7d a0 01 08 7d c9 01 08 7d a0 01 08 }...}... }...}...
[00:26:38.343] ../src/core/util/hexdump.c:11> 0060 7d a0 01 08 29 59 01 08 3b 59 01 08 4d 59 01 08 }...)Y.. ;Y..MY..
[00:26:38.355] ../src/core/util/hexdump.c:11> 0070 5f 59 01 08 7d a0 01 08 7d a0 01 08 7d a0 01 08 _Y..}... }...}...
>
erase flash <address> <length>
==============================
This command will erase a section of SPI flash in 64k chunks. The address must be
specified in hex with a leading '0x'. The address must be 64k aligned. The length
is in bytes, and will be rounded up to the next 64k boundary. 'OK' will be echoed to
the console once the erase operation is complete.
Ex:
>erase flash 0x0 128
Erasing 64k flash sectors starting at address 0x0 for 128 bytes (rounded up to 65536 bytes)
OK
>
write flash <address>
=====================
This command allows a user to write bytes to SPI flash. Please ensure
the region being written to has already been erased. The address must
be specified in hex with a leading '0x'.
Bytes must be written using base64 encoding. The base64 characters are
not echoed back to the console as they are written. Bytes are written
to flash in chunks of 1024 base64 characters, corresponding to 768
decoded bytes. The watch will echo a '#' character to acknowledge
receipt of a chunk, followed by echoing 'OK' when the watch is ready
to receive the next chunk. The end of the final chunk is indicated by
sending a CTRL-D character (EOF). The current chunk will be flushed to
SPI flash upon receiving an EOF character. Remember to pad the final
chunk with '=' characters if it's not a multiple of 3 bytes, as per
the base64 encoding standard. To exit the 'write flash' mode without
flushing the current chunk, enter a CTRL-C character.
If a chunk is malformed due to invalid characters or incorrect
padding, 'Decoding Error' will be printed to the serial port and the
normal serial prompt will return. Note that any previous chunks that
were well formed have already been written to SPI flash.
Ex:
>write flash 0x0
Flash imaging mode, CTRL-D to stop
#OK
>
(NB: Your base64 data is not echoed back when writing to flash. The #OK will show up
when a chunk is complete or CTRL-D is used.)

0
docs/mainpage_sdk.dox Normal file
View file

View file

@ -0,0 +1,135 @@
PULSE Flash Imaging
===================
This document describes the PULSE flash imaging protocol. This protocol
was originally designed for use over PULSEv1, but also works over the
PULSEv2 Best-Effort transport.
The flash imaging protocol is used to write raw data directly to the
external flash. It is a message-oriented protocol encapsulated in PULSE
frames. The primary goals of the protocol are reliability and speed over
high-latency links.
* All client-sent commands elicit responses
* As much as possible, any command can be resent without corrupting the
flashing process. This is to accommodate the situation where the
command was received and acted upon but the response was lost, and the
client retried the command.
* Any notification (server→client message which is not a response to a
command) can be lost without holding up the flashing process. There
must be a way to poll for the status of all operations which elicit
notifications.
* Most of the state is tracked by the client. The server only has to
maintain a minimal, fixed-size amount of state.
> The idempotence of writing to flash is leveraged in the design of this
> protocol to effectively implement a [Selective Repeat ARQ](http://en.wikipedia.org/wiki/Selective_Repeat_ARQ)
> with an unlimited window size without requiring the server to keep
> track of which frames are missing. Any Write Data command to the same
> location in flash can be repeated any number of times with no ill
> effects.
## Message format
All fields in a message which are more than one octet in length are
transmitted least-significant octet (LSB) first.
All messages begin with a 1-octet Opcode, followed by zero or more data
fields depending on the message. All Address fields are offsets from the
beginning of flash. Address and Length fields are specified in units of
bytes.
### Client Commands
#### 1 - Erase flash region
Address: 4 octets
Length: 4 octets
#### 2 - Write data to flash
Address: 4 octets
Data: 1+ octets
The data length is implied.
#### 3 - Checksum flash region
Address: 4 octets
Length: 4 octets
#### 4 - Query flash region geometry
Region: 1 octet
Region | Description
-------|-------------------
1 | PRF
2 | Firmware resources
#### 5 - Finalize flash region
Region: 1 octet
Inform the server that writing is complete and perform whatever task is
necessary to finalize the data written to the region. This may be a
no-op.
Region numbers are the same as for the "Query flash region geometry"
message.
### Server Responses
#### 128 - ACKnowledge erase command
Address: 4 octets
Length: 4 octets
Complete?: 1 octet
Complete field is zero if the erase is in progress, nonzero when the
erase is complete.
#### 129 - ACKnowledge write command
Address: 4 octets
Length: 4 octets
Complete?: 1 octet
#### 130 - Checksum result
Address: 4 octets
Length: 4 octets
Checksum: 4 octets
The legacy Pebble checksum ("STM32 CRC") of the specified memory is
returned.
#### 131 - Flash region geometry
Region: 1 octet
Address: 4 octets
Length: 4 octets
A length of zero indicates that the region does not exist.
#### 132 - ACKnowledge finalize flash region command
Region: 1 octet
#### 192 - Malformed command
Bad message: 9 octets
Error string: 0+ octets
#### 193 - Internal error
Error string: 0+ octets
Something has gone terribly wrong which prevents flashing from
proceeding.
<!-- vim: set tw=72: -->

165
docs/pulse2/history.md Normal file
View file

@ -0,0 +1,165 @@
History of PULSEv2
==================
This document describes the history of the Pebble dbgserial console
leading up to the design of PULSEv2.
In The Beginning
----------------
In the early days of Pebble, the dbgserial port was used to print out
log messages in order to assist in debugging the firmware. These logs
were plain text and could be viewed with a terminal emulator such as
minicom. An interactive prompt was added so that firmware developers and
the manufacturing line could interact with the running firmware. The
prompt mode could be accessed by pressing CTRL-C at the terminal, and
could be exited by pressing CTRL-D. Switching the console to prompt mode
suppressed the printing of log messages. Data could be written into the
external flash memory over the console port by running a prompt command
to switch the console to a special "flash imaging" mode and sending it
base64-encoded data.
This setup worked well enough, though it was slow and a little
cumbersome to use at times. Some hacks were tacked on as time went on,
like a "hybrid" prompt mode which allowed commands to be executed
without suppressing log messages. These hacks didn't work terribly well.
But it didn't really matter as the prompt was only used internally and
it was good enough to let people get stuff done.
First Signs of Trouble
----------------------
The problems with the serial console started becoming apparent when
we started building out automated integration testing. The test
automation infrastructure made extensive use of the serial console to
issue commands to simulate actions such as button clicks, inspect the
firmware state, install applications, and capture screenshots and log
messages. From the very beginning the serial console proved to be very
unreliable for test automation's uses, dropping commands, corrupting
screenshots and other data, and hiding log messages. The test automation
harness which interacted with the dbgserial port became full of hacks
and workarounds, but was still very unreliable. While we wanted to have
functional and reliable automated testing, we didn't have the manpower
at the time to improve the serial console for test automation's use
cases. And so test automation remained frustratingly unreliable for a
long time.
PULSEv1
-------
During the development of Pebble Time, the factory was complaining that
imaging the recovery firmware onto external flash over the dbgserial
port was taking too long and was causing a manufacturing bottleneck. The
old flash imaging mode had many issues and was in need of a replacement
anyway, and improving the throughput to reduce manufacturing costs
finally motivated us to allocate engineering time to replace it.
The biggest reason the flash imaging protocol was so slow was that it
was extremely latency sensitive. After every 768 data bytes sent, the
sender was required to wait for the receiver to acknowledge the data
before continuing. USB-to-serial adapter ICs are used at both the
factory and by developers to interface the watches' dbgserial ports to
modern computers, and these adapters can add up to 16 ms latency to
communications in each direction. The vast majority of the flash imaging
time was wasted with the dbgserial port idle, waiting for the sender to
receive and respond to an acknowledgement.
There were other problems too, such as a lack of checksums. If line
noise (which wasn't uncommon at the factory) corrupted a byte into
another valid base64 character, the corruption would go unnoticed and be
written out to flash. It would only be after the writing was complete
that the integrity was verified, and the entire transfer would have to
be restarted from the beginning.
Instead of designing a new flash imaging protocol directly on top of the
raw dbgserial console, as the old flash imaging protocol did, a
link-layer protocol was designed which the new flash imaging protocol
would operate on top of. This new protocol, PULSE version 1, provided
best-effort multiprotocol datagram delivery with integrity assurance to
any applications built on top of it. That is, PULSE allowed
applications to send and receive packets over dbgserial, without
interfering with other applications simultaneously using the link, with
the guarantee that the packets either will arrive at the receiver intact
or not be delivered at all. It was designed around the use-case of flash
imaging, with the hope that other protocols could be implemented over
PULSE later on. The hope was that this was the first step to making test
automation reliable.
Flash imaging turns out to be rather unique, with affordances that make
it easy to implement a performant protocol without protocol features
that many other applications would require. Writing to flash memory is
an idempotent operation: writing the same bytes to the same flash
address _n_ times has the same effect as writing it just once. And
writes to different addresses can be performed in any order. Because
of these features of flash, each write operation can be treated as a
wholly independent operation, and the data written to flash will be
complete as long as every write is performed at least once. The
communications channel for flash writes does not need to be reliable,
only error-free. The protocol is simple: send a write command packet
with the target address and data. The receiver performs the write and
sends an acknowledgement with the address. If the sender doesn't receive
an acknowledgement within some timeout, it re-sends the write command.
Any number of write commands and acknowledgements can be in-flight
simulatneously. If a write completes but the acknowledgement is lost in
transit, the sender can re-send the same write command and the receiver
can naively overwrite the data without issue due to the idempotence of
flash writes.
The new PULSE flash imaging protocol was a great success, reducing
imaging time from over sixty seconds down to ten, with the bottleneck
being the speed at which the flash memory could be erased or written.
After the success of PULSE flash imaging, attempts were made to
implement other protocols on top of it, with varying degrees of success.
A protocol for streaming log messages over PULSE was implemented, as
well as a protocol for reading data from external flash. There were
attempts to implement prompt commands and even an RPC system using
dynamically-loaded binary modules over PULSE, but they required reliable
and in-order delivery, and implementing a reliable transmission scheme
separately for each application protocol proved to be very
time-consuming and bug-prone.
Other flaws in PULSE became apparent as it came into wider use. The
checksum used to protect the integrity of PULSE frames was discovered to
have a serious flaw, where up to three trailing 0x00 bytes could be
appended to or dropped from a packet without changing the checksum
value. This flaw, combined with the lack of explicit length fields in
the protocol headers, made it much more likely for PULSE flash imaging
to write corrupted data. This was discovered shortly after test
automation switched over to PULSE flash imaging.
Make TA Green Again
-------------------
Around January 2016, it was decided that the issues with PULSE that were
preventing test automation from fully dropping use of the legacy serial
console would best be resolved by taking the lessons learned from PULSE
and designing a successor. This new protocol suite, appropriately
enough, is called PULSEv2. It is designed with test automation in mind,
with the intention of completely replacing the legacy serial console for
test automation, developers and the factory. It is much better at
communicating and synchronizing link state, which solves problems that
test automation was running into with the firmware crashing and
rebooting getting the test harness confused. It uses a standard checksum
without the flaws of its predecessor, and packet lengths are explicit.
And it is future-proofed by having an option-negotiation mechanism,
allowing us to add new features to the protocol while allowing old and
new implementations to interoperate.
Applications can choose to communicate with either best-effort datagram
service (like PULSEv1), or reliable datagram service that guarantees
in-order datagram delivery. Having the reliable transport available
made it very easy to implement prompt commands over PULSEv2. And it was
also suprisingly easy to implement a PULSEv2 transport for the Pebble
Protocol, which allows developers and test automation to interact with
bigboards using libpebble2 and pebble-tool, exactly like they can with
emulators and sealed watches connected to phones.
Test automation switched over to PULSEv2 on 2016 May 31. It immediately
cut down test run times and, once some bugs got shaken out, measurably
improved the reliability of test automation. It also made the captured
logs from test runs much more useful as messages were no longer getting
dropped. PULSEv2 was made the default for all firmware developers at the
end of September 2016.
<!-- vim: set tw=72: -->

419
docs/pulse2/pulse2.md Normal file
View file

@ -0,0 +1,419 @@
PULSEv2 Protocol Suite
======================
Motivation
----------
The initial design of PULSE was shaped by its initial use case of flash
imaging. Flash imaging has a few properties which allowed it to be
implemented on top of a very simplistic wire protocol. Writing to flash
can be split up into any number of atomic write operations that can be
applied in arbitrary order. Flash writes are idempotent: repeatedly
writing the same data to the same flash address does not corrupt the
written data. Because of these properties, it was possible to implement
the flash imaging protocol in a stateless manner simply by ensuring that
every write was applied at least once without concern for out of order
delivery or duplicated datagrams. The PULSE link layer was designed as
simply as possible, guaranteeing only datagram integrity with only
best-effort reliability and sequencing, since it was all that the flash
imaging protocol needed.
As we try to use PULSE for more applications, it has become clear that
flash imaging is a special case. Most applications have some manner of
statefulness or non-idempotent operations, so they need guarantees about
reliable delivery and sequencing of datagrams in order to operate
correctly in the face of lost or corrupted datagrams. The lack of such
guarantees in PULSE has forced these applications to bake sequencing and
retransmissions into the application protocols in an ad-hoc manner,
poorly. This has made the design and implementation of prompt and file
transfer protocols more complex than necessary, and no attempt has yet
been made to tunnel Pebble Protocol over PULSE. It's the [waterbed
theory](http://wiki.c2.com/?WaterbedTheory) at work.
Adding support for reliable, ordered delivery of datagrams will allow
for any application to make use of reliable service simply by requesting
it. Implementation of chatty protocols will be greatly simplified.
Protocol Stack
--------------
PULSEv2 is a layered protocol stack. The link layer provides
integrity-assured delivery of packet data. On top of the link layer is a
suite of transport protocols which provide multiprotocol delivery of
application datagrams with or without guaranteed reliable in-order
delivery. Application protocols use one or more of the available
transports to exchange datagrams between the firmware running on a board
and a host workstation.
Physical Layer
--------------
PULSEv2 supports asynchronous serial byte-oriented full duplex links,
8-N-1, octets transmitted LSB first. The link must transparently pass
all octet values. The baud rate is 1,000,000 bps.
> **Why that baud rate?**
>
> 1 Mbaud is a convenient choice as it is the highest frequency which
> divides perfectly into a 16 MHz core clock at 16x oversampling, and
> works with zero error at 64, 80 and 100 MHz (with only 100 MHz
> requiring any fractional division at all). The only downside is that
> it is not a "standard" baud rate, but this is unlikely to be a problem
> as FTDI, PL2303, CP2102 (but not CP2101) and likely others will handle
> 1 Mbaud rates (at least in hardware). YMMV with Windows drivers...
Link Layer
----------
The link layer, in a nutshell, is PPP with custom framing. The entirety
of [RFC 1661](https://tools.ietf.org/html/rfc1661) is normative, except
as noted in this document.
### Encapsulation
PPP encapsulation (RFC 1661, Section 2) is used. The Padding field of
the PPP encapsulation must be empty.
A summary of the frame structure is shown below. This figure does not
include octets inserted for transparency. The fields are transmitted
from left to right.
Flag | Protocol | Information | FCS | Flag
-----|----------|-------------|----------|-----
0x55 | 2 octets | * | 4 octets | 0x55
#### Flag field
Each frame begins and ends with a Flag sequence, which is the octet 0x55
hexadecimal. The flag is used for frame synchronization.
> **Why 0x55?**
>
> It is transmitted as bit pattern `(1)0101010101`, which is really easy
> to spot on an oscilloscope trace or logic analyzer capture, and it
> allows for auto baud rate detection. The STM32F7 USART supports auto
> baud rate detection with an 0x55 character in hardware.
Only one Flag sequence is required between two frames. Two consecutive
Flag sequences constitute and empty frame, which is silently discarded.
#### Protocol field
The Protocol field is used as prescribed by RFC 1661, Section 2. PPP
assigned protocol numbers and their respective assigned protocols should
be used wherever it makes sense. Custom protocols must not be assigned
protocol numbers which overlap any [existing PPP assigned protocol](http://www.iana.org/assignments/ppp-numbers/ppp-numbers.xhtml).
#### Frame Check Sequence field
The Frame Check Sequence is transmitted least significant octet first.
The check sequence is calculated using the [CRC-32](http://reveng.sourceforge.net/crc-catalogue/all.htm#crc.cat.crc-32)
checksum. The parameters of the CRC algorithm are:
width=32 poly=0x04c11db7 init=0xffffffff refin=true refout=true
xorout=0xffffffff check=0xcbf43926 name="CRC-32"
The FCS field is calculated over all bits of the Protocol and
Information fields, not including any start and stop bits, or octets
inserted for transparency. This also does not include the Flag sequence
nor the FCS field itself.
### Transparency
Transparency is achieved by applying [COBS](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing)
encoding to the Protocol, Information and FCS fields, then replacing any
instances of 0x55 in the COBS-encoded data with 0x00.
### Link Operation
The Link Control Protocol packet format, assigned numbers and state
machine are the same as PPP (RFC 1661), with minor exceptions.
> Do not be put off by the length of the RFC document. Only a small
> subset of the protocol needs to be implemented (especially if there
> are no negotiable options) for an implementation to be conforming.
> All multi-byte fields in LCP packets are transmitted in Network
> (big-endian) byte order. The burden of converting from big-endian to
> little-endian is very minimal, and it lets Wireshark dissectors work
> on PULSEv2 LCP packets just like any other PPP LCP packet.
By prior agreement, peers MAY transmit or receive packets of certain
protocols while the link is in any phase. This is contrary to the PPP
standard, which requires that all non-LCP packets be rejected before the
link reaches the Authentication phase.
Transport Layer
---------------
### Best-Effort Application Transport (BEAT) protocol
Best-effort delivery with very little overhead, similar to PULSEv1.
#### Packet format
Application Protocol | Length | Information
---------------------|----------|------------
2 octets | 2 octets | *
All multibyte fields are in big-endian byte order.
The Length field encodes the number of octets in the Application
Protocol, Length and Information fields of the packet. The minimum value
of the Length field in a valid packet is 4.
BEAT application protocol 0x0001 is assigned to the PULSE Control
Message Protocol (PCMP). When a BEAT packet is received by a conforming
implementation with the Application Protocol field set to an
unrecognized value, a PCMP Unknown Protocol message MUST be sent.
#### BEAT Control Protocol (BECP)
BECP uses the same packet exchange mechanism as the Link Control
Protocol. BECP packets may not be exchanged until LCP is in the Opened
state. BECP packets received before this state is reached should be
silently discarded.
BECP is exactly the same as the Link Control Protocol with the following
exceptions:
* Exactly one BECP packet is encapsulated in the Information field of
Link Layer frames where the Protocol field indicates type 0xBA29 hex.
* Only codes 1 through 7 (Configure-Request, Configure-Ack,
Configure-Nak, Configure-Reject, Terminate-Request, Terminate-Ack and
Code-Reject) are used. Other codes should be treated as unrecognized
and should result in Code-Rejects.
* A distinct set of configure options are used. There are currently no
options defined.
#### Sending BEAT packets
Before any BEAT protocol packets may be communicated, both LCP and BECP
must reach the Opened state. Exactly one BEAT protocol packet is
encapsulated in the Information field of Link Layer frames where the
Protocol field indicates type 0x3A29 hex.
### PUSH (Simplex) transport
Simplex best-effort delivery of datagrams. It is designed for log
messages and other status updates from the firmware to the host. There
is no NCP, no options, no negotiation.
#### Packet format
Application Protocol | Length | Information
---------------------|----------|------------
2 octets | 2 octets | *
All multibyte fields are in big-endian byte order.
The Length field encodes the number of octets in the Application
Protocol, Length and Information fields of the packet. The minimum value
of the Length field in a valid packet is 4.
#### Sending PUSH packets
Packets can be sent at any time regardless of the state of the link,
including link closed. Exactly one PUSH packet is encapsulated in the
Information field of Link Layer frames where the Protocol field
indicates type 0x5021 hex.
### Reliable transport (TRAIN)
The Reliable transport provides reliable in-order delivery service of
multiprotocol application datagrams. The protocol is heavily based on
the [ITU-T Recommendation X.25](https://www.itu.int/rec/T-REC-X.25-199610-I/en)
LAPB data-link layer. The remainder of this section relies heavily on
the terminology used in Recommendation X.25. Readers are also assumed to
have some familiarity with section 2 of the Recommendation.
#### Packet formats
The packet format is, in a nutshell, LAPB in extended mode carrying BEAT
packets.
**Information command packets**
Control | Application Protocol | Length | Information
---------|----------------------|----------|------------
2 octets | 2 octets | 2 octets | *
**Supervisory commands and responses**
Control |
---------|
2 octets |
##### Control field
The control field is basically the same as LAPB in extended mode. Only
Information transfer and Supervisory formats are supported. The
Unnumbered format is not used as such signalling is performed
out-of-band using the TRCP control protocol. The Information command and
the Receive Ready, Receive Not Ready, and Reject commands and responses
are permitted in the control field.
The format and meaning of the subfields in the Control field are
described in ITU-T Recommendation X.25.
##### Application Protocol field
The protocol number for the message contained in the Information field.
This field is only present in Information packets. The Application
Protocol field is transmitted most-significant octet first.
##### Length field
The Length field specifies the number of octets covering the Control,
Application Protocol, Length and Information fields. The Length field is
only present in Information packets. The content of a valid Information
packet must be no less than six. The Length field is transmitted
most-significant octet first.
##### Information field
The application datagram itself. This field is only present in
Information packets.
#### TRAIN Control Protocol
The TRAIN Control Protocol, or TRCP for short, is used to set up and
tear down the communications channel between the two peers. TRCP uses
the same packet exchange mechanism as the Link Control Protocol. TRCP
packets may not be exchanged until LCP is in the Opened state. TRCP
packets received before this state is reached should be silently
discarded.
TRCP is exactly the same as the Link Control Protocol with the following
exceptions:
* Exactly one TRCP packet is encapsulated in the Information field of
Link Layer frames where the Protocol field indicates type 0xBA33 hex.
* Only codes 1 through 7 (Configure-Request, Configure-Ack,
Configure-Nak, Configure-Reject, Terminate-Request, Terminate-Ack and
Code-Reject) are used. Other codes should be treated as unrecognized
and should result in Code-Rejects.
* A distinct set of configure options are used. There are currently no
options defined.
The `V(S)` and `V(R)` state variables shall be reset to zero when the
TRCP automaton signals the This-Layer-Up event. All packets in the TRAIN
send queue are discarded when the TRCP automaton signals the
This-Layer-Finished event.
#### LAPB system parameters
The LAPB system parameters used in information transfer have the default
values described below. Some parameter values may be altered through the
TRCP option negotiation mechanism. (NB: there are currently no options
defined, so there is currently no way to alter the default values during
the protocol negotiation phase)
**Maximum number of bits in an I packet _N1_** is equal to eight times
the MRU of the link, minus the overhead imposed by the Link Layer
framing and the TRAIN header. This parameter is not negotiable.
**Maximum number of outstanding I packets _k_** defaults to 1 for both
peers. This parameter is (to be) negotiable. If left at the default, the
protocol will operate with a Stop-and-Wait ARQ.
#### Transfer of application datagrams
Exactly one TRAIN packet is encapsulated in the Information field of
Link Layer frames. A command packet is encapsulated in a Link Layer
frame where the Protocol field indicates 0x3A33 hex, and a response
packet is encapsulated in a Link Layer frame where the Protocol field
indicates 0x3A35 hex. Transfer of datagrams shall follow the procedures
described in Recommendation X.25 §2.4.5 _LAPB procedures for information
transfer_. A cut-down set of procedures for a compliant implementation
which only supports _k=1_ operation can be found in
[reliable-transport.md](reliable-transport.md).
In the event of a frame rejection condition (as defined in
Recommendation X.25), the TRCP automaton must be issued a Down event
followed by an Up event to cause an orderly renegotiation of the
transport protocol and reset the state variables. This is the same as
the Restart option described in RFC 1661. A FRMR response MUST NOT be
sent.
TRAIN application protocol 0x0001 is assigned to the PULSE Control
Message Protocol (PCMP). When a TRAIN packet is received by a conforming
implementation with the Application Protocol field set to an
unrecognized value, a PCMP Unknown Protocol message MUST be sent.
### PULSE Control Message Protocol
The PULSE Control Message Protocol (PCMP) is used for signalling of
control messages by the transport protocols. PCMP messages must be
encapsulated in a transport protocol, and are interpreted within the
context of the encapsulated transport protocol.
> **Why a separate protocol?**
>
> Many of the transports need to communicate the same types of control
> messages. Rather than defining a different way of communicating these
> messages for each protocol, they can use PCMP and share a single
> definition (and implementation!) of these messages.
#### Packet format
Code | Information
--------|------------
1 octet | *
#### Defined codes
##### 1 - Echo Request
When the transport is in the Opened state, the recipient MUST respond
with an Echo-Reply packet. When the transport is not Opened, any
received Echo-Request packets MUST be silently discarded.
##### 2 - Echo Reply
A reply to an Echo-Request packet. The Information field MUST be copied
from the received Echo-Request.
##### 3 - Discard Request
The receiver MUST silently discard any Discard-Request packet that it
receives.
##### 129 - Port Closed
A packet has been received with a port number unrecognized by the
recipient. The Information field must be filled with the port number
copied from the received packet (without endianness conversion).
##### 130 - Unknown PCMP Code
A PCMP packet has been received with a Code field which is unknown to
the recipient. The Information field must be filled with the Code field
copied from the received packet.
----
Useful Links
------------
* [The design document for PULSEv2](https://docs.google.com/a/pulse-dev.net/document/d/1ZlSRz5-BSQDsmutLhUjiIiDfVXTcI53QmrqENJXuCu4/edit?usp=sharing),
which includes a draft of this documentation along with a lot of
notes about the design decisions.
* [Python implementation of PULSEv2](https://github.com/pebble/pulse2)
* [Wireshark plugin for dissecting PULSEv2 packet captures](https://github.com/pebble/pulse2-wireshark-plugin)
* [RFC 1661 - The Point to Point Protocol (PPP)](https://tools.ietf.org/html/rfc1661)
* [RFC 1662 - PPP in HDLC-like Framing](https://tools.ietf.org/html/rfc1662)
* [RFC 1663 - PPP Reliable Transmission](https://tools.ietf.org/html/rfc1663)
* [RFC 1570 - PPP LCP Extensions](https://tools.ietf.org/html/rfc1570)
* [RFC 2153 - PPP Vendor Extensions](https://tools.ietf.org/html/rfc2153)
* [RFC 3772 - Point-to-Point Protocol (PPP) Vendor Protocol](https://tools.ietf.org/html/rfc3772)
* [PPP Consistent Overhead Byte Stuffing (COBS)](https://tools.ietf.org/html/draft-ietf-pppext-cobs)
* [ITU-T Recommendation X.25](https://www.itu.int/rec/T-REC-X.25-199610-I/en)
* [Digital Data Communications Message Protocol](http://www.ibiblio.org/pub/historic-linux/early-ports/Mips/doc/DEC/ddcmp-4.1.txt)
<!-- vim: set tw=72: -->

View file

@ -0,0 +1,96 @@
PULSEv2 Reliable Transport
==========================
The purpose of this document is to describe the procedures for the PULSEv2
reliable transport (TRAIN) to be used in the initial implementations, with
support for only Stop-and-Wait ARQ (Automatic Repeat reQuest). Hopefully,
limiting the scope in this way will make it simpler to implement compared to a
more performant Go-Back-N ARQ. This document is a supplement to the description
of TRAIN in [pulse2.md](pulse2.md).
The PULSEv2 reliable transport (TRAIN) is based on X.25 LAPB, which implements
reliable datagram delivery using a Go-Back-N ARQ (Automatic Repeat reQuest)
procedure. Since a Stop-and-Wait ARQ is equivalent to Go-Back-N with a window
size of 1, LAPB can be readily adapted for Stop-and-Wait ARQ. The description in
this document should hopefully be compatible with an implementation supporting
the full Go-Back-N LAPB procedures when that implementation is configured with a
window size of 1, so that there is a smooth upgrade path which doesn't require
special cases or compatibility breakages.
Documentation conventions
-------------------------
This document relies heavily on the terminology used in [ITU-T Recommendation
X.25](https://www.itu.int/rec/T-REC-X.25-199610-I/en). Readers are also assumed
to have some familiarity with section 2 of that document.
The term "station" is used in this document to mean "DCE or DTE".
Procedures for information transfer
-----------------------------------
There is no support for communicating a busy condition. It is assumed that a
station in a busy condition will silently drop packets, and that the timer
recovery procedure will be sufficient to ensure reliable delivery of the dropped
packets once the busy condition is cleared. An implementation need not support
sending or receiving RNR packets.
Sending I packets
-----------------
All Information transfer packets must be sent with the Poll bit set to 1. The
procedures from X.25 §2.4.5.1 apply otherwise.
Receiving an I packet
---------------------
When the DCE receives a valid I packet whose send sequence number N(S) is equal
to the DCE receive state variable V(R), the DCE will accept the information
fields of this packet, increment by one its receive state variable V(R), and
transmit an RR response packet with N(R) equal to the value of the DCE receive
state variable V(R). If the received I packet has the Poll bit set to 1, the
transmitted RR packet must be a response packet with Final bit set to 1.
Otherwise the transmitted RR packet should have the Final bit set to 0.
Reception of out-of-sequence I packets
--------------------------------------
Since the DTE should not have more than one packet in-flight at once, an
out-of-sequence I packet would be due to a retransmit: RR response for the most
recently received I packet got lost, so the DTE re-sent the I packet. Discard
the information fields of the packet and send an RR packet with N(R)=V(R).
Receiving acknowledgement
-------------------------
When correctly receiving a RR packet, the DCE will consider this packet as an
acknowledgement of the most recently-sent I packet if N(S) of the most
recently-sent I packet is equal to the received N(R)-1. The DCE will stop timer
T1 when it correctly receives an acknowledgement of the most recently-sent I
packet.
Since all I packets are sent with P=1, the receiving station is obligated to
respond with a supervisory packet. Therefore it is unnecessary to support
acknowledgements embedded in I packets.
Receiving an REJ packet
-----------------------
Since only one I packet may be in-flight at once, the REJ packet is due to the
RR acknowledgement from the DTE getting lost and the DCE retransmitting the I
packet. Treat it like an RR.
Waiting acknowledgement
-----------------------
The DCE maintains an internal transmission attempt variable which is set to 0
when the transport NCP signals a This-Layer-Up event, and when the DCE correctly
receives an acknowledgement of a sent I packet.
If Timer T1 runs out waiting for the acknowledgement from the DTE for an I
packet transmitted, the DCE will add one to its transmission attempt variable,
restart Timer T1 and retransmit the unacknowledged I packet.
If the transmission attempt variable is equal to N2 (a system parameter), the
DCE will initiate a restart of the transport link.

37
docs/tasks.txt Normal file
View file

@ -0,0 +1,37 @@
FreeRTOS lets us create tasks, which are independant threads of execution. We create a few ourselves, and more are created internally by FreeRTOS. We have pre-emption enabled in our FreeRTOS configuration, so we must be mindful of which other tasks are mucking with the same data. This document describes the tasks that exist in our system.
FreeRTOS Tasks
==============
Tasks defined internally by FreeRTOS.
"Tmr Svc" - The timer task
--------------------------
Timers that are registered using our timer infrastructure are executed on this task. This is a FreeRTOS subsystem that we've wrapped with the goodies in fw/timers.h.
"IDLE" - The idle task
----------------------
This is a special task used by the FreeRTOS scheduler. It's defined at it's own priority level which is at the lowest priority. If no other task is ready to run, either due to waiting on a semaphore or waiting using vTaskDelay (or something like that), the idle task is chosen to run instead.
We have modified FreeRTOS such that if we're in the idle task, we enter a lower power mode, either sleep or stop. Stop mode is special in that peripheral clocks are shut down when we go into stop and are not automatically turned back on when we leave stop mode. This means we have to go through and turn them all back on. This is what the `register_stop_mode_resume_callback` function does. It allows individual drivers to register callbacks that are called when we leave stop from the idle thread. This comes with a caveat though. Since the idle thread only ever runs when there's nothing else to run, the scheduler assumes that there is always a task to run. This means that if the idle task is stopped or delayed for any reason, the scheduler will explode. Therefore you are not permitted to do operations that may stop the task's execution from within the resume callback.
Pebble Tasks
============
"main" - The main task
----------------------
The first task in our system. Runs the all the driver initialization code, and then gets taken over by the main launcher loop. The launcher event queue is then serviced forever in a loop.
"system_task" - The system task
-------------------------------
A lower priority task that services callbacks from a worker queue. If you are doing something that may take more than a few milliseconds, it makes sense to delegate it to this queue. For example, flash writes and reads during firmware updates are done on this task.
"app" - The application task
----------------------------
This task is created for the currently running app. No task is created for the launcher "app", as it's not a real app and just uses the main task. This task's lifetime is limited to the lifetime of the app.
???
Open Questions
==============
Which tasks are allowed to manipulate the window state? What if the launcher wants to push a notification window at the same time as an app pushes it's own window?

BIN
docs/template/bg-navbar.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

38
docs/template/footer.html vendored Normal file
View file

@ -0,0 +1,38 @@
<!--
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.
-->
</div>
<!-- start footer part -->
<!--BEGIN GENERATE_TREEVIEW-->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
$navpath
<li class="footer">$generatedby
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="$relpath$doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
</ul>
</div>
<!--END GENERATE_TREEVIEW-->
<!--BEGIN !GENERATE_TREEVIEW-->
<hr class="footer"/><address class="footer"><small>
$generatedby &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="$relpath$doxygen.png" alt="doxygen"/>
</a> $doxygenversion
</small></address>
<!--END !GENERATE_TREEVIEW-->
</body>
</html>

78
docs/template/header.html vendored Normal file
View file

@ -0,0 +1,78 @@
<!DOCTYPE html>
<!--
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.
-->
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
<meta charset="utf-8">
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<link href='$relpath$bootstrap.css' media='screen' rel='stylesheet' type='text/css' />
<link href='$relpath$pebble-developer.css' media='screen' rel='stylesheet' type='text/css' />
<link href="$relpath$tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="$relpath$jquery.js"></script>
<script type="text/javascript" src="$relpath$dynsections.js"></script>
$treeview
$search
$mathjax
<link href="$relpath$$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-30638158-4']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div id="top" ><!-- do not remove this div, it is closed by doxygen! -->
<div class="navbar navbar-inverse ">
<div class="navbar-inner">
<div class="container">
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<div class="nav-collapse collapse">
<ul class="nav">
<li><a class="first" href="#"><span></span></a></li>
<li><a href="http://developer.getpebble.com/">Develop for Pebble</a></li>
</ul>
<ul class="nav pull-right">
<li class="doc-nav-searchbox">$searchbox</li>
<li><a href="http://forums.getpebble.com/">Forum</a></li>
<li><a href="http://developer.getpebble.com/2/api-reference/modules.html">API Documentation</a></li>
<li><a href="http://developer.getpebble.com/2/">Guides</a></li>
<li><a href="http://developer.getpebble.com/blog/">Developer Blog</a></li>
</ul>
</div>
</div>
</div>
</div>

BIN
docs/template/navbar-brdr.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

BIN
docs/template/navbar-icon.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

17
docs/template/pebble-developer.css vendored Normal file

File diff suppressed because one or more lines are too long

1248
docs/template/stylesheet.css vendored Normal file

File diff suppressed because it is too large Load diff