Contenu connexe Similaire à Pebble Watch iOS SDK Overview (20) Pebble Watch iOS SDK Overview5. ☐ What is the Pebble
☐ Why you should develop for the Pebble
☐ How to develop for the Pebble
Agenda
13. ARM Cortex-M3 MCU
120 MHz
Apple A6
ARMv7 1.3 GHz
Dual Core
128 KB RAM
Up to 8 apps
1 GB RAM
Up to 64 GB storage
144 x 168 pixels
1-bit color
“e-paper”
1,136 × 640 pixels
24-bit Color
“Retina”
Pebble iPhone 5
CPU
Memory
Screen
14. Bluetooth 2.1 and
4.0 LE
Bluetooth 4.0
802.11a/b/g/n Wi-Fi
Cellular LTE
3-axis accelerometer
Ambient light
Magnetometer
Three-axis gyro
Accelerometer
Proximity sensor
Ambient light sensor
4 buttons
Vibration
Screen backlight
Touch screen
Buttons
Vibration
Camera
Pebble iPhone 5
Comm.
Sensors
IO
15. 2 to 14 days ~1 day
FreeRTOS
Pebble SDK
PebbleKit
iOS
iOS SDK
5 ATM water
resistance
22 mm watch band
Not water resistant
Can’t wear on wrist
Pebble iPhone 5
Battery
Software
Other
19. ☑ What is the Pebble
☐ Why you should develop for the Pebble
☐ How to develop for the Pebble
Agenda
42. “I agree to wear you
around and share a
lot of personal data
with you.”
- Customers
46. $10,266,846 - Pebble Watch (design)
$8,596,475 - OUYA (Android console)
$5,702,153 - Veronica Mars (movie)
$4,188,927 - Torment: Tides of Numenera (game)
$3,986,929 - Project Eternity (game)
56. ☑ What is the Pebble
☑ Why you should develop for the Pebble
☐ How to develop for the Pebble
Agenda
58. 1. Pebble SDK dependencies
2. Pebble SDK
3. ARM dependencies
4. Pebble ARM toolchain
Install
60. 1 #include "pebble_os.h"
2 #include "pebble_app.h"
3 #include "pebble_fonts.h"
4
5 #define MY_UUID {
6 0x20, 0xD9, 0xFB, 0x8F, 0xBE, 0xCF, 0x49,
7 0x94, 0xA9, 0xE8, 0x70, 0xC0, 0xEA, 0xC6,
8 0x50, 0x16
9 }
10
11 PBL_APP_INFO(
12 MY_UUID,
13 "Hello World",
14 "Acme Corp",
15 1, 0, /* App version */
16 DEFAULT_MENU_ICON,
17 APP_INFO_STANDARD_APP
18 );
61. 1 #include "pebble_os.h"
2 #include "pebble_app.h"
3 #include "pebble_fonts.h"
4
5 #define MY_UUID {
6 0x20, 0xD9, 0xFB, 0x8F, 0xBE, 0xCF, 0x49,
7 0x94, 0xA9, 0xE8, 0x70, 0xC0, 0xEA, 0xC6,
8 0x50, 0x16
9 }
10
11 PBL_APP_INFO(
12 MY_UUID,
13 "Hello World",
14 "Acme Corp",
15 1, 0, /* App version */
16 DEFAULT_MENU_ICON,
17 APP_INFO_STANDARD_APP
18 );
62. 1 #include "pebble_os.h"
2 #include "pebble_app.h"
3 #include "pebble_fonts.h"
4
5 #define MY_UUID {
6 0x20, 0xD9, 0xFB, 0x8F, 0xBE, 0xCF, 0x49,
7 0x94, 0xA9, 0xE8, 0x70, 0xC0, 0xEA, 0xC6,
8 0x50, 0x16
9 }
10
11 PBL_APP_INFO(
12 MY_UUID,
13 "Hello World",
14 "Acme Corp",
15 1, 0, /* App version */
16 DEFAULT_MENU_ICON,
17 APP_INFO_STANDARD_APP
18 );
63. 20 Window window;
21
22 void handle_init(AppContextRef ctx) {
23 window_init(&window, "Window Name");
24 window_stack_push(&window,true/*Animated*/);
25 }
26
27
28 void pbl_main(void *params) {
29 PebbleAppHandlers handlers = {
30 .init_handler = &handle_init
31 };
32 app_event_loop(params, &handlers);
33 }
64. 20 Window window;
21
22 void handle_init(AppContextRef ctx) {
23 window_init(&window, "Window Name");
24 window_stack_push(&window,true/*Animated*/);
25 }
26
27
28 void pbl_main(void *params) {
29 PebbleAppHandlers handlers = {
30 .init_handler = &handle_init
31 };
32 app_event_loop(params, &handlers);
33 }
65. 20 Window window;
21
22 void handle_init(AppContextRef ctx) {
23 window_init(&window, "Window Name");
24 window_stack_push(&window,true/*Animated*/);
25 }
26
27
28 void pbl_main(void *params) {
29 PebbleAppHandlers handlers = {
30 .init_handler = &handle_init
31 };
32 app_event_loop(params, &handlers);
33 }
66. 20 Window window;
21
22 void handle_init(AppContextRef ctx) {
23 window_init(&window, "Window Name");
24 window_stack_push(&window,true/*Animated*/);
25 }
26
27
28 void pbl_main(void *params) {
29 PebbleAppHandlers handlers = {
30 .init_handler = &handle_init
31 };
32 app_event_loop(params, &handlers);
33 }
67. 15 TextLayer hello_layer;
16
17 void handle_init(AppContextRef ctx) {
18
19 window_init(&window, "Window Name");
20 window_stack_push(&window, true /* Animated */);
21
22 text_layer_init(&hello_layer, GRect(0, 65, 144, 30));
23 text_layer_set_text_alignment(&hello_layer,GTextAlignmentCenter);
24 text_layer_set_text(&hello_layer, "Hello World!");
25 text_layer_set_font(
26 &hello_layer,
27 fonts_get_system_font(FONT_KEY_ROBOTO_CONDENSED_21)
28 );
29
30 layer_add_child(&window.layer, &hello_layer.layer);
31
32 }
68. 15 TextLayer hello_layer;
16
17 void handle_init(AppContextRef ctx) {
18
19 window_init(&window, "Window Name");
20 window_stack_push(&window, true /* Animated */);
21
22 text_layer_init(&hello_layer, GRect(0, 65, 144, 30));
23 text_layer_set_text_alignment(&hello_layer,GTextAlignmentCenter);
24 text_layer_set_text(&hello_layer, "Hello World!");
25 text_layer_set_font(
26 &hello_layer,
27 fonts_get_system_font(FONT_KEY_ROBOTO_CONDENSED_21)
28 );
29
30 layer_add_child(&window.layer, &hello_layer.layer);
31
32 }
102. 190 - (void)setTargetWatch:(PBWatch*)watch {
191
192 self.watch = watch;
193
194 // Test if the Pebble's firmware supports AppMessages
195 [watch appMessagesGetIsSupported:
^(PBWatch *watch, BOOL isAppMessagesSupported) {
196
197 if (isAppMessagesSupported) {
198
199 // Configure communications channel to target the weather app:
200 uint8_t bytes[] = {
201 0x42, 0xc8, 0x6e, 0xa4, 0x1c, 0x3e, 0x4a, 0x07,
202 0xb8, 0x89, 0x2c, 0xcc, 0xca, 0x91, 0x41, 0x98};
203 NSData *uuid = [NSData dataWithBytes:bytes length:sizeof(bytes)];
204 [watch appMessagesSetUUID:uuid];
205
206 [self updateWatch];
207
208 }
209
210 }];
211 }
iOS
103. 190 - (void)setTargetWatch:(PBWatch*)watch {
191
192 self.watch = watch;
193
194 // Test if the Pebble's firmware supports AppMessages
195 [watch appMessagesGetIsSupported:
^(PBWatch *watch, BOOL isAppMessagesSupported) {
196
197 if (isAppMessagesSupported) {
198
199 // Configure communications channel to target the weather app:
200 uint8_t bytes[] = {
201 0x42, 0xc8, 0x6e, 0xa4, 0x1c, 0x3e, 0x4a, 0x07,
202 0xb8, 0x89, 0x2c, 0xcc, 0xca, 0x91, 0x41, 0x98};
203 NSData *uuid = [NSData dataWithBytes:bytes length:sizeof(bytes)];
204 [watch appMessagesSetUUID:uuid];
205
206 [self updateWatch];
207
208 }
209
210 }];
211 }
iOS
104. 190 - (void)setTargetWatch:(PBWatch*)watch {
191
192 self.watch = watch;
193
194 // Test if the Pebble's firmware supports AppMessages
195 [watch appMessagesGetIsSupported:
^(PBWatch *watch, BOOL isAppMessagesSupported) {
196
197 if (isAppMessagesSupported) {
198
199 // Configure communications channel to target the weather app:
200 uint8_t bytes[] = {
201 0x42, 0xc8, 0x6e, 0xa4, 0x1c, 0x3e, 0x4a, 0x07,
202 0xb8, 0x89, 0x2c, 0xcc, 0xca, 0x91, 0x41, 0x98};
203 NSData *uuid = [NSData dataWithBytes:bytes length:sizeof(bytes)];
204 [watch appMessagesSetUUID:uuid];
205
206 [self updateWatch];
207
208 }
209
210 }];
211 }
iOS
105. 259 - (void)updateWatch {
260
261 NSDictionary *update = @{
262 kKeyWatchIcon:[NSNumber numberWithUint8:1],
263 kKeyWatchTemperature:[NSString stringWithFormat:@"%.1f u00B0F", @”90”]
264 };
265
266 [self.watch appMessagesPushUpdate:update onSent:
^(PBWatch *watch, NSDictionary *update, NSError *error) {
267
268 if (error) {
269 // Message was not sent
270 } else {
271 // Message was sent
272 }
273
274 }];
275
276 }
iOS
106. 259 - (void)updateWatch {
260
261 NSDictionary *update = @{
262 kKeyWatchIcon:[NSNumber numberWithUint8:1],
263 kKeyWatchTemperature:[NSString stringWithFormat:@"%.1f u00B0F", @”90”]
264 };
265
266 [self.watch appMessagesPushUpdate:update onSent:
^(PBWatch *watch, NSDictionary *update, NSError *error) {
267
268 if (error) {
269 // Message was not sent
270 } else {
271 // Message was sent
272 }
273
274 }];
275
276 }
iOS
107. 259 - (void)updateWatch {
260
261 NSDictionary *update = @{
262 kKeyWatchIcon:[NSNumber numberWithUint8:1],
263 kKeyWatchTemperature:[NSString stringWithFormat:@"%.1f u00B0F", @”90”]
264 };
265
266 [self.watch appMessagesPushUpdate:update onSent:
^(PBWatch *watch, NSDictionary *update, NSError *error) {
267
268 if (error) {
269 // Message was not sent
270 } else {
271 // Message was sent
272 }
273
274 }];
275
276 }
iOS
108. 296 - (BOOL)handleWatchUpdate:(PBWatch *)watch message:(NSDictionary *)message {
299
300 if ([message objectForKey:kKeyWatchRequestUpdate]) {
301 NSLog(@"Forecast update requested");
303 return YES;
304 }
305
306 return NO;
307
308 }
402 self.updateHandler = [self.watch appMessagesAddReceiveUpdateHandler:
^BOOL(PBWatch *watch, NSDictionary *update) {
403 return [self handleWatchUpdate:watch message:update];
404 }];
iOS
109. 296 - (BOOL)handleWatchUpdate:(PBWatch *)watch message:(NSDictionary *)message {
299
300 if ([message objectForKey:kKeyWatchRequestUpdate]) {
301 NSLog(@"Forecast update requested");
303 return YES;
304 }
305
306 return NO;
307
308 }
402 self.updateHandler = [self.watch appMessagesAddReceiveUpdateHandler:
^BOOL(PBWatch *watch, NSDictionary *update) {
403 return [self handleWatchUpdate:watch message:update];
404 }];
iOS
110. 296 - (BOOL)handleWatchUpdate:(PBWatch *)watch message:(NSDictionary *)message {
299
300 if ([message objectForKey:kKeyWatchRequestUpdate]) {
301 NSLog(@"Forecast update requested");
303 return YES;
304 }
305
306 return NO;
307
308 }
402 self.updateHandler = [self.watch appMessagesAddReceiveUpdateHandler:
^BOOL(PBWatch *watch, NSDictionary *update) {
403 return [self handleWatchUpdate:watch message:update];
404 }];
iOS
112. 171 void pbl_main(void *params) {
172
173 PebbleAppHandlers handlers = {
174
175 .init_handler = &app_init,
176 .deinit_handler = &app_deinit,
177 .messaging_info = {
178 .buffer_sizes = {
179 .inbound = 64,
180 .outbound = 16,
181 }
182 },
183 // Handle time updates
184 .tick_info = {
185 .tick_handler = &handle_minute_tick,
186 .tick_units = MINUTE_UNIT
187 }
188 };
189
190 app_event_loop(params, &handlers);
191
192 }
Pebble
113. 171 void pbl_main(void *params) {
172
173 PebbleAppHandlers handlers = {
174
175 .init_handler = &app_init,
176 .deinit_handler = &app_deinit,
177 .messaging_info = {
178 .buffer_sizes = {
179 .inbound = 64,
180 .outbound = 16,
181 }
182 },
183 // Handle time updates
184 .tick_info = {
185 .tick_handler = &handle_minute_tick,
186 .tick_units = MINUTE_UNIT
187 }
188 };
189
190 app_event_loop(params, &handlers);
191
192 }
Pebble
114. 171 void pbl_main(void *params) {
172
173 PebbleAppHandlers handlers = {
174
175 .init_handler = &app_init,
176 .deinit_handler = &app_deinit,
177 .messaging_info = {
178 .buffer_sizes = {
179 .inbound = 64,
180 .outbound = 16,
181 }
182 },
183 // Handle time updates
184 .tick_info = {
185 .tick_handler = &handle_minute_tick,
186 .tick_units = MINUTE_UNIT
187 }
188 };
189
190 app_event_loop(params, &handlers);
191
192 }
Pebble
115. 171 void pbl_main(void *params) {
172
173 PebbleAppHandlers handlers = {
174
175 .init_handler = &app_init,
176 .deinit_handler = &app_deinit,
177 .messaging_info = {
178 .buffer_sizes = {
179 .inbound = 64,
180 .outbound = 16,
181 }
182 },
183 // Handle time updates
184 .tick_info = {
185 .tick_handler = &handle_minute_tick,
186 .tick_units = MINUTE_UNIT
187 }
188 };
189
190 app_event_loop(params, &handlers);
191
192 }
Pebble
116. 171 void pbl_main(void *params) {
172
173 PebbleAppHandlers handlers = {
174
175 .init_handler = &app_init,
176 .deinit_handler = &app_deinit,
177 .messaging_info = {
178 .buffer_sizes = {
179 .inbound = 64,
180 .outbound = 16,
181 }
182 },
183 // Handle time updates
184 .tick_info = {
185 .tick_handler = &handle_minute_tick,
186 .tick_units = MINUTE_UNIT
187 }
188 };
189
190 app_event_loop(params, &handlers);
191
192 }
Pebble
117. 116 static void app_init(AppContextRef c) {
117
118 resource_init_current_app(&WEATHER_APP_RESOURCES);
119
120 Window* window = &s_data.window;
121 window_init(window, "PebbleWeather");
122 window_set_background_color(window, GColorBlack);
123 window_set_fullscreen(window, true);
124
...
149 // Watch <--> Phone communication
150 Tuplet initial_values[] = {
151 TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1),
152 TupletCString(WEATHER_TEMPERATURE_KEY, "-u00B0C"),
153 };
154 app_sync_init(&s_data.sync,
s_data.sync_buffer,
sizeof(s_data.sync_buffer),
initial_values,
ARRAY_LENGTH(initial_values),
sync_tuple_changed_callback, sync_error_callback, NULL);
155
156 window_stack_push(window, true);
157
168 }
Pebble
118. 116 static void app_init(AppContextRef c) {
117
118 resource_init_current_app(&WEATHER_APP_RESOURCES);
119
120 Window* window = &s_data.window;
121 window_init(window, "PebbleWeather");
122 window_set_background_color(window, GColorBlack);
123 window_set_fullscreen(window, true);
124
...
149 // Watch <--> Phone communication
150 Tuplet initial_values[] = {
151 TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1),
152 TupletCString(WEATHER_TEMPERATURE_KEY, "-u00B0C"),
153 };
154 app_sync_init(&s_data.sync,
s_data.sync_buffer,
sizeof(s_data.sync_buffer),
initial_values,
ARRAY_LENGTH(initial_values),
sync_tuple_changed_callback, sync_error_callback, NULL);
155
156 window_stack_push(window, true);
157
168 }
Pebble
119. 116 static void app_init(AppContextRef c) {
117
118 resource_init_current_app(&WEATHER_APP_RESOURCES);
119
120 Window* window = &s_data.window;
121 window_init(window, "PebbleWeather");
122 window_set_background_color(window, GColorBlack);
123 window_set_fullscreen(window, true);
124
...
149 // Watch <--> Phone communication
150 Tuplet initial_values[] = {
151 TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1),
152 TupletCString(WEATHER_TEMPERATURE_KEY, "-u00B0C"),
153 };
154 app_sync_init(&s_data.sync,
s_data.sync_buffer,
sizeof(s_data.sync_buffer),
initial_values,
ARRAY_LENGTH(initial_values),
sync_tuple_changed_callback, sync_error_callback, NULL);
155
156 window_stack_push(window, true);
157
168 }
Pebble
120. 116 static void app_init(AppContextRef c) {
117
118 resource_init_current_app(&WEATHER_APP_RESOURCES);
119
120 Window* window = &s_data.window;
121 window_init(window, "PebbleWeather");
122 window_set_background_color(window, GColorBlack);
123 window_set_fullscreen(window, true);
124
...
149 // Watch <--> Phone communication
150 Tuplet initial_values[] = {
151 TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1),
152 TupletCString(WEATHER_TEMPERATURE_KEY, "-u00B0C"),
153 };
154 app_sync_init(&s_data.sync,
s_data.sync_buffer,
sizeof(s_data.sync_buffer),
initial_values,
ARRAY_LENGTH(initial_values),
sync_tuple_changed_callback, sync_error_callback, NULL);
155
156 window_stack_push(window, true);
157
168 }
Pebble
121. 104 // Send message to phone asking for a weather update
105 void request_weather_update() {
106
107 vibes_double_pulse();
108
109 Tuplet values[] = {
110 TupletInteger(WEATHER_FORECAST_REQUEST_KEY, 1),
111 };
112 app_sync_set(&s_data.sync, values, ARRAY_LENGTH(values));
113
114 }
Pebble
122. 104 // Send message to phone asking for a weather update
105 void request_weather_update() {
106
107 vibes_double_pulse();
108
109 Tuplet values[] = {
110 TupletInteger(WEATHER_FORECAST_REQUEST_KEY, 1),
111 };
112 app_sync_set(&s_data.sync, values, ARRAY_LENGTH(values));
113
114 }
Pebble
123. 65 // Tuple changed
66 static void sync_tuple_changed_callback(
const uint32_t key,
const Tuple* new_tuple,
const Tuple* old_tuple,
void* context) {
67
68 switch (key) {
69 case WEATHER_ICON_KEY:
70 load_bitmap(WEATHER_ICONS[new_tuple->value->uint8]);
71 bitmap_layer_set_bitmap(
&s_data.icon_layer,
&s_data.icon_bitmap.bmp
);
72 break;
73
74 case WEATHER_TEMPERATURE_KEY:
75 text_layer_set_text(
&s_data.temperature_layer,
new_tuple->value->cstring
);
76 break;
77
78 default:
79 return;
80 }
81 }
Pebble
124. 65 // Tuple changed
66 static void sync_tuple_changed_callback(
const uint32_t key,
const Tuple* new_tuple,
const Tuple* old_tuple,
void* context) {
67
68 switch (key) {
69 case WEATHER_ICON_KEY:
70 load_bitmap(WEATHER_ICONS[new_tuple->value->uint8]);
71 bitmap_layer_set_bitmap(
&s_data.icon_layer,
&s_data.icon_bitmap.bmp
);
72 break;
73
74 case WEATHER_TEMPERATURE_KEY:
75 text_layer_set_text(
&s_data.temperature_layer,
new_tuple->value->cstring
);
76 break;
77
78 default:
79 return;
80 }
81 }
Pebble
125. 65 // Tuple changed
66 static void sync_tuple_changed_callback(
const uint32_t key,
const Tuple* new_tuple,
const Tuple* old_tuple,
void* context) {
67
68 switch (key) {
69 case WEATHER_ICON_KEY:
70 load_bitmap(WEATHER_ICONS[new_tuple->value->uint8]);
71 bitmap_layer_set_bitmap(
&s_data.icon_layer,
&s_data.icon_bitmap.bmp
);
72 break;
73
74 case WEATHER_TEMPERATURE_KEY:
75 text_layer_set_text(
&s_data.temperature_layer,
new_tuple->value->cstring
);
76 break;
77
78 default:
79 return;
80 }
81 }
Pebble
126. ☑ What is the Pebble
☑ Why you should develop for the Pebble
☑ How to develop for the Pebble
Agenda
128. Credits
Pictures
Pebble, Pebble Forums, Pebble SubReddit,
iFixIt, Wired, Verge, Lifehacker, BBC,
MyPebbleFaces, Kickstarter, indiegogo,
Wikipedia