I've been designing a personal news feed app for the original pebble which displays news content in a menu layer. I have two C files, one which contains a window that displays a loading image and handles the data transfer between the js on the phone and my watch app. The data is saved into some extern variables which are shared between the files but is irrelevant in the example I show below (all of that works fine I believe).
I'm calling news_list_window_init()
in my main .c file within a function when certain conditions are met. Right now I'm just trying to display a window with a scrollable menu to test that my menu looks acceptable. The problem I'm having is that my app crashes when I try to scroll. The window appears, all my menu items are there but when I scroll the app exists with:
ault_handling.c:78> App fault! {f5ec8c0d-9f21-471a-9a5c-c83320f7477d} PC: 0x800fd5b LR: ???
Program Counter (PC) : 0x800fd5b ???
Link Register (LR) : ??? ???
I've tested my .c file below independently, where I create a new project with only this code, comment out the non-relevant news_list.h
and externs.h
header files, and comment in the main function at the bottom of the file. This works fine, my menu scrolls and there are no crashes and everything looks fine.
I don't see how the problem could be in my main file, because the only function I call in it which is contained in this file is news_list_window_init()
, moreover the menu does indeed display correctly. I can even close the app properly with the back button. Trying to scroll however crashes the application. I'm sort of at a loss as to what could be causing this error. Does anybody have any suggestions? Thanks!
This is the relevant .c file:
// news_list.c
#include "pebble.h"
#include "news_list.h"
#include "externs.h"
#define NUM_MENU_SECTIONS 1
static Window *news_list_window;
static MenuLayer *menu_layer;
static uint16_t menu_get_num_sections_callback(MenuLayer *menu_layer, void *data) {
return NUM_MENU_SECTIONS;
}
static uint16_t menu_get_num_rows_callback(MenuLayer *menu_layer, uint16_t section_index, void *data) {
return str_count; // Variable story count
}
static int16_t menu_get_header_height_callback(MenuLayer *menu_layer, uint16_t section_index, void *data) {
return MENU_CELL_BASIC_HEADER_HEIGHT;
}
static void menu_draw_header_callback(GContext* ctx, const Layer *cell_layer, uint16_t section_index, void *data) {
menu_cell_basic_header_draw(ctx, cell_layer, "Header");
}
static void menu_draw_row_callback(GContext* ctx, const Layer *cell_layer, MenuIndex *cell_index, void *data) {
menu_cell_basic_draw(ctx, cell_layer, "Menu Item", NULL, NULL);
}
static void menu_select_callback(MenuLayer *menu_layer, MenuIndex *cell_index, void *data) {
// Currently Empty
}
int16_t menu_get_cell_height_callback(struct MenuLayer *menu_layer, MenuIndex *cell_index, void *callback_context)
{
return 40;
}
static void news_list_window_load(Window *window) {
// Now we prepare to initialize the menu layer
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_frame(window_layer);
// Create the menu layer
menu_layer = menu_layer_create(bounds);
menu_layer_set_callbacks(menu_layer, NULL, (MenuLayerCallbacks){
.get_num_sections = menu_get_num_sections_callback,
.get_num_rows = menu_get_num_rows_callback,
.get_header_height = menu_get_header_height_callback,
.draw_header = menu_draw_header_callback,
.draw_row = menu_draw_row_callback,
.select_click = menu_select_callback,
.get_cell_height = menu_get_cell_height_callback,
});
// Bind the menu layer's click config provider to the window for interactivity
menu_layer_set_click_config_onto_window(menu_layer, window);
layer_add_child(window_layer, menu_layer_get_layer(menu_layer));
}
static void news_list_window_unload(Window *window) {
// Destroy the menu layer
menu_layer_destroy(menu_layer);
}
void news_list_window_init() {
news_list_window = window_create();
window_set_window_handlers(news_list_window, (WindowHandlers) {
.load = news_list_window_load,
.unload = news_list_window_unload,
});
window_stack_push(news_list_window, true);
}
void news_list_window_deinit() {
window_destroy(news_list_window);
}
// int main(void) {
// news_list_window_init();
// app_event_loop();
// news_list_window_deinit();
// }
This is the relevant .h file:
// news_list.h
#ifndef NEWS_LIST_H
#define NEWS_LIST_H
// Public Function list
void news_list_window_init(void);
void news_list_window_deinit(void);
#endif
I've had this happen when I'm running really low on memory, or if I'm corrupting memory somehow.
I'd suggest checking all return values for NULL and logging and bailing if they are (menu_layer_create, malloc etc.).
Also, try logging how much free memory you have - if you are working on an original Pebble, and allocating large memory buffers for communication, you can very quickly run out of memory.
Finally, walk through all code that allocates and uses memory to be absolutely sure you are not accidentally writing past the end of an array, or passing a value allocated on the stack into a pebble call. I like to use calloc rather than malloc to be sure I don't think I have a value in a malloc'd structure when I don't.
I've been here before - it isn't easy, but likely totally unrelated to your UI code - the crash is just a symptom. If all else fails maybe post the complete code in github so that we can take a look at the complete app...
Damian