http://developer.getpebble.com/
Pebble C:
Customized pebble firmware: http://pebblebits.com/
Development language: C
Environment: local or CloudPebble, according to some discussion, CloudPebble is the preferred one unless some special requirement
Window dimension:
- W = 144 (Action bar = 30 wide, use the ACTION_BAR_WIDTH definition. Rest = 144-30=114)
- H = 168 (Status bar = 16 W-S = 152)
- Action icon on action bar 14 X 14
- Standard application launch icon 24 X 28
http://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html
- Integer types & sizes
- Operators
- Arithmetic: + - * / ++ --
- =
- Logical: == != > < >= <= && || !
- Variables
- int value = 42; float pi = 3.14159F; double cir = 2 * pi * radius;
- bool show_weather = true;
- char first_initial = 'C';
- char string_array[7]; string_array[6] = '\0'; char hello[] = "Hello!";
- static keyword
- variables in file scope - visible only in that file
- variable in block - will survive across invocations
- functions - visible only in that file
- Functions (CHECK SAME TYPE!)
- int double_this(int value) { return 2 * value; }
- Conditional statements
- if (value > 10) { .... } else { ... };
- switch (day) { case 0: ...; break; case 1: ....; break....}
- Loops
- for (int i=0; i<5; i++) {}
- while (i<5) {}
- do {} while() ;
- Structures
- struct Person { int age; char first_initial... }
- struct Person me; me.age = 23....
- anonymous struct value: (WindowHandlers) {.load = xxx, .unload = xxx}
- Pointers
- int value = 25; int *value_prt = &value; *(value_ptr) *= 2;
- Enums
- enum ConnectionState { ConnectionStateConnected = 1, ConnectionStateDisconnected = 2 }; int state_now; switch(state_now) { case ConnectionStateDisconnected: ...}
- Preprocessor statements
- #include <pebble.h>; #define IMAGE_WIDTH 144;
- Type Def: gives a type a name
- typedef unsigned char byte; typedef struct Books { .... } Book; Book b;
- Callbacks (handlers)
- implement a handler EXACTLY as the signature of a callback handler typedef including return type (NO COMPILER CHECK, BE CAREFUL)
- call subscribe API function
- Memory
- stack - around 2000 bytes for declaring new variables and managed by compiler, freed up when variable out of scope
- heap - around 64K minus code, must be deallocated when no longer used
- API objects - match create with destroy!
- TextLayer *text_layer;
- text_layer = text_layer_create(some_bounds);
- text_layer_destroy(text_layer);
- Watchfaces are selected using the Up & Down buttons and serve as the default display | watchapps are launched from pebble system menu
- Buttons are not available to watchfaces
- App - app_event_loop()
- App Communication - set bluetooth module sniff interval (so responsiveness etc.)
- AppMessage - bi-directional communication between phone app & pebble apps
- exchange arbitrary sets of key / value pairs in form of a dictionary
- symmetric, push-oriented, all messages acknowledged (or result time-out failure)
- one-send is allowed at one time
- strict limitations on format
- dictionary
- key must be integer
- value (http://developer.getpebble.com/guides/pebble-apps/pebblekit-js/js-app-comm/) :
- integers - convert to 32 bits signed integers
- strings
- byte arrays
- messages limited in size, can be chosen when call app_message_open()
- APP_MESSAGE_INBOX_SIZE_MINIMUM (124), APP_MESSAGE_OUTBOX_SIZE_MINIMUM (636 as of 2015) always succeed
- app_message_inbox_size_maximum() app_message_outbox_size_maximum() get available size
- best practice to get largest buffer available: app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum())
- call backs:
- app_message_register_inbox_received(), app_message_register_inbox_dropped(), app_message_register_outbox_sent(), app_message_register_outbox_failed()
- recommended call before open() so not missing message
- app_message_set_context() for context will be passed to all callbacks
- AppSync - data / UI synchronizing layer built upon AppMessage to simplify the task of synchronizing values between watch app & phone
- AppWorker
- what is worker?
- asynchronous operation run in background, independently (even front is closed), and can communicate with front
- constrained to 10.5k memory
- limited API
- only one active worker at a time
- can launch foreground
- see http://developer.getpebble.com/guides/pebble-apps/background/
- communication back/front end / phone
- persistent storage
- worker message
- data logging API with phone
- worker handling
- app_worker_launch(), app_worker_kill() - register launch / kill
- app_worker_message_subscribe(handler) / _unsubscribe() - subscribe to worker messages with handler
- app_worker_send_message
- programming worker
- see above guide for a basic main loop
- timer - use Wakeup API not background timer
- available / unavailable APIs
- no UI
- no AppMessage or resources
- yes Accelerometer
- yes Compasss
- yes DataLogging
- yes Storage
- DataLogging - enable logging data asynchronously to a Mobile App (not pebble javascript) / save data on buffer (limited) when phone not available to process it, about 640K for logging (shared)
- DataStructures
- Dictionary - data serialization utilities for app messages
- DictionaryIterator - reference to the dictionary
- operations
- dict_read_begin_from_buffer()
- dict_read_first()
- dict_read_next()
- dict_write_data()
- dict_write_cstring()
- Tuple contains
- uint32_t key
- TupleType type
- uint16_t length
- value
- TupleType
- TUPLE_BYTE_ARRAY
- TUPLE_CSTRING (zero-terminated UTF-8 C-string)
- TUPLE_UINT unsigned integer & tuple length determine size
- TUPLE_INT
- see http://developer.getpebble.com/guides/pebble-apps/communications/appmessage/ for how to convert received
- Event Service
- Accelerometer service
- AppFocusService - when apps become visible on screen (useful for high interactive app like game, i.e. pause / resume when covered up)
- Reasons of running & not on screen
- in middle of launching and revealed by animation
- covered by system window (notification)
- Battery State Service
- Bluetooth Connection Service - know when pebble connected to phone
- Compass
- TickTimerService - be called everytime one time unit changed (watch faces)
- Internationalization - get system locale
- Launch Reason - check reason of launch
- Logging
- APP_LOG(level, fmt, args....)
- Math (sin / cos lookup)
- Memory Management
- heap_bytes_free() / heap_bytes_used()
- Resources
- images & custom fonts, or any data file, always read only
- stored in flash & loaded as needed, so can have large number (>RAM)
- Storage (persistent)
- defined as collections of fields (create / modify / delete)
- a field is a key / value pair
- maximum size of byte arrays PERSIST_DATA_MAX_LENGTH (256 now)
- all persisted values <= 4K
- Timer - cause execution at some future point
- Wakeup - schedule to launch at future time even not running
- up to 8 wakeup events
- 1 minute duration window (not accurate)
- Wall time - format time string
- Watch info - information about the watch
- Draw paths - polygons
- Draw primitivs - pix, line, rectangle, circle ...
- Drawing Text
- Fonts - system & custom
- Graphic Context - the "canvas", most time provided by system as an argument passed to a render callback (the .update_proc of a Layer)
- Graphics types - basic types & utility functions
- Draw Commands - arbitrary path draw & fill
- Animation
- Clicks
- Events
- single click (& holds-to-repeat, i.e. repeated click)
- multi-click
- long click (press & hold)
- raw - button up / down
- to receive events
- void window_set_click_config_provider(Window *window, ClickConfigProvider click_config_provider)
- typedef void(* ClickConfigProvider)(void *context)
- this click config provider will be called every time when window becomes visible
- context is a pointer to the window by default but can be changed with window_set_click_config_provider_with_context()
- in this provider can call various subscribe functions to subscribe handlers
- click handlers
- click information (identification), when same handler serves different buttons & event types
- handler receives ClickRecognizerRef
- can call click_number_of_clicks_counted(), click_ecognizer_get_button_id(), click_recognizer_is_repeating() to get more information
- Back button
- by default return to previous window (and exit app if it's the last window)
- can be used (overrided)
- Layers
- on layers objects can be displayed
- layers can be nested inside each other
- window has a root layer, always the topmost layer
- refers to UI Layer chapter in the Guide
- Light - back light control
- Vibes
- Window
- Basic UI object
- Status Bar: to remove, call window_set_fullscreen before window pushed
- Special window
- NumberWindow - asks user to pick a number
- Window Stack - handles the window stack
background execution
- Format
- Locale - setlocale
- Math
- Memory
- void* malloc(size_t size)
- void* calloc(size_t count, size_t size) - counted objects
- void* realloc(void *ptr, size_t size) - re-alloc to change the length of the allocation, copy the content into new buffer
- void free(void* ptr) - free memory
- void* memcpy(void* dest, const void* src, size_t n)
- void* memmove(void* dest, const void* src, size_t n) - first copy to a temporary area so allow locations overlap
- void* memset(void* dest, int c, size_t n)
- String
- strcmp - compare strings
- strncmp - compare for up to n bytes
- strcpy - copy string
- strncpy - copy up to n bytes of string
- strcat
- strncat - copy up to n bytes
- strlen - length of string
- Time
- time_t time(time_t *tloc) - obtain number of seconds since epoch, adjusted for local time zones and daylight savings. tloc optionally points to an address to store time in, or NULL if just want the return value
- mktime(struct tm *timeptr) - convert tm structure to a time_t
- struct tm *localtime(const time_t *clock) - convert time value (clock) to struct tm contains adjusted for local time
- strftime - convert time value to string
- time_ms - number of seconds and milliseconds
Issues: after SDK change and worked with CloudPebble, sending message always get "no connection" error. Later found out Pebble changed JS to pkjs
https://developer.pebble.com/blog/2016/01/29/Multiple-JavaScript-Files/
So, my javascript was not loaded. After changing back to old "src/js", it works again.