/** Unit test to check that the Membag re-allocates previously allocated and * subsequently freed blocks of memory correctly. * * \param test Pointer to the unit test case instance */ static void run_membag_realloc_test(const struct test_case *test) { void *data; /* Initialize membag system. */ membag_init(); /* Allocate as many small chunks as there are sufficiently sized blocks. */ while (membag_get_largest_free_block_size() >= CONF_TEST_ALLOC_SIZE_SMALL) { data = membag_alloc(CONF_TEST_ALLOC_SIZE_SMALL); test_assert_false(test, data == NULL, "Unable to allocate a small chunk!"); } /* Free last allocated chunk of memory */ membag_free(data); /* Re-allocate a small chunk, should succeed by re-using the last freed * block of memory. */ data = membag_alloc(CONF_TEST_ALLOC_SIZE_SMALL); test_assert_false(test, data == NULL, "Unable to re-allocate a small chunk!"); }
/** Unit test to check that the Membag frees previously allocated memory * correctly. * * \param test Pointer to the unit test case instance */ static void run_membag_free_test(const struct test_case *test) { void *data1, *data2, *data3; /* Initialize membag system. */ membag_init(); /* Allocate three small chunks of data. */ data1 = membag_alloc(CONF_TEST_ALLOC_SIZE_SMALL); data2 = membag_alloc(CONF_TEST_ALLOC_SIZE_SMALL); data3 = membag_alloc(CONF_TEST_ALLOC_SIZE_SMALL); /* Check that all three membag allocations completed successfully. */ test_assert_false(test, (data1 == NULL) || (data2 == NULL) || (data3 == NULL), "Less than three small chunks were allocated!"); /* Check that all three membag allocations actually reserved sufficient *memory. */ test_assert_false(test, (membag_get_total() - membag_get_total_free()) < (CONF_TEST_ALLOC_SIZE_SMALL * 3), "Not enough memory was allocated!"); membag_free(data1); membag_free(data2); membag_free(data3); /* Check that all memory has been returned to the membag. */ test_assert_true(test, membag_get_total() == membag_get_total_free(), "Not all memory is free!"); }
/** Unit test to check that the Membag allocates small and large chunks of * memory correctly, and fails when a chunk that is too large is requested. * * \param test Pointer to the unit test case instance */ static void run_membag_alloc_test(const struct test_case *test) { void *data; /* Initialize membag system. */ membag_init(); /* Try to allocate a small chunk, should succeed. */ data = membag_alloc(CONF_TEST_ALLOC_SIZE_SMALL); test_assert_false(test, data == NULL, "Unable to allocate a small chunk!"); /* Re-initialize the membag system. */ membag_init(); /* Try to allocate a large chunk, should succeed. */ data = membag_alloc(CONF_TEST_ALLOC_SIZE_LARGE); test_assert_false(test, data == NULL, "Unable to allocate a large chunk!"); /* Try to allocate a massive (too large) chunk, should fail. */ data = membag_alloc(CONF_TEST_ALLOC_SIZE_TOO_LARGE); test_assert_true(test, data == NULL, "Should not be able to allocate a too-large chunk!"); }
/** * This function creates a new check box widget. It allocates required memory * and intializes necessary windows to create the widget. If there is not enough * memory, the function returns NULL. * * To destroy the widget and all its contents, and free its memory, call * win_destroy() on the check box' child reference, given by * wtk_check_box_as_child(), like this: * "win_destroy(wtk_check_box_as_child(my_check_box_ptr));". * Usually it will be destroyed automatically when it's parent is destroyed. * * \param parent Parent window, possibly wtk_frame_as_parent(my_frame_ptr). * \param area Area of the internal contents. * \param caption Pointer to caption string. Will be copied into widget. * \param selected Initial state of check box, true if checked/selected. * \param command Command to send to parent window. Must be non-zero to be * enabled. * * \return Pointer to check box, or NULL if failed. */ struct wtk_check_box *wtk_check_box_create(struct win_window *parent, struct win_area const *area, char const *caption, bool selected, win_command_t command) { struct win_attributes attr; struct wtk_check_box *check_box; Assert(area); Assert(caption); Assert(parent); /* Allocate memory for check box control data. */ check_box = membag_alloc(sizeof(struct wtk_check_box)); if (!check_box) { goto outofmem_check_box; } check_box->state = WTK_CHECKBOX_NORMAL; check_box->selected = selected; check_box->command = command; /* Allocate memory for caption string, and copy text. */ check_box->caption = membag_alloc((strlen(caption) + 1) * sizeof(char)); if (!check_box->caption) { goto outofmem_caption; } wtk_copy_string(check_box->caption, caption); /* Handling information. */ attr.event_handler = wtk_check_box_handler; attr.custom = check_box; /* Prepare container frame. */ attr.area = *area; attr.background = NULL; attr.behavior = WIN_BEHAVIOR_REDRAW_PARENT; check_box->container = win_create(parent, &attr); if (!check_box->container) { goto outofmem_container; } return check_box; outofmem_container: membag_free(check_box->caption); outofmem_caption: membag_free(check_box); outofmem_check_box: return NULL; }
/** * This function creates a new button widget. It allocates required memory and * intializes necessary windows to create the widget. If there is not enough * memory, the function returns NULL. * * To destroy the widget and all its contents, and free its memory, call * win_destroy() on the button's child reference, given by * wtk_button_as_child(), like this: * "win_destroy(wtk_button_as_child(myButtonPtr));". * Usually it will be destroyed automatically when it's parent is destroyed. * * \param parent Parent window, possibly wtk_frame_as_parent(myFramePtr). * \param area Area of the internal contents. * \param caption Pointer to caption string. Will be copied into widget. * \param command_data Custom data to put into a command event when "clicked". * * \return Pointer to button, or NULL if failed. */ struct wtk_button *wtk_button_create(struct win_window *parent, struct win_area const *area, char const *caption, win_command_t command_data) { struct win_attributes attr; struct wtk_button *button; Assert(area); Assert(caption); Assert(parent); /* Allocate memory for button control data. */ button = membag_alloc(sizeof(struct wtk_button)); if (!button) { goto outofmem_button; } button->state = WTK_BUTTON_NORMAL; button->command = command_data; /* Allocate memory for caption string, and copy text. */ button->caption = membag_alloc((strlen(caption) + 1) * sizeof(char)); if (!button->caption) { goto outofmem_caption; } wtk_copy_string(button->caption, caption); /* Handling information. */ attr.event_handler = wtk_button_handler; attr.custom = button; /* Prepare container frame. */ attr.area = *area; attr.background = NULL; attr.behavior = 0x00; button->container = win_create(parent, &attr); if (!button->container) { goto outofmem_container; } return button; outofmem_container: membag_free(button->caption); outofmem_caption: membag_free(button); outofmem_button: return NULL; }
/** * This function starts the drag operation. It will allocate memory to store * the screen behind the drag handles and draw the handles themselves. * Do not call this function unless wtk_prepare_drag() has been called first * with the drag origin position. * If there is not enough memory, this function will no draw anything, but it * is still safe to call wtk_continue_drag() and wtk_stop_drag(). * * \param pos Current position of drag target. */ static void wtk_start_drag(struct win_point const *pos) { /* Allocate memory for bitmaps. */ wtk_drag_origin_pixmap = membag_alloc( (WTK_DRAG_PIXMAP_SIZE * WTK_DRAG_PIXMAP_SIZE) * sizeof(gfx_color_t) ); if (!wtk_drag_origin_pixmap) { goto outofmem_origin; } wtk_drag_target_pixmap = membag_alloc( (WTK_DRAG_PIXMAP_SIZE * WTK_DRAG_PIXMAP_SIZE) * sizeof(gfx_color_t) ); if (!wtk_drag_target_pixmap) { goto outofmem_target; } /* Make sure we can draw on the entire screen, since dragging is not * necessarily limited to within one window. */ gfx_set_clipping(0, 0, gfx_get_width() - 1, gfx_get_height() - 1); /* Store screen underneath and draw drag origin symbol. */ gfx_get_pixmap(wtk_drag_origin_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0, wtk_drag_origin.x - WTK_DRAG_HANDLE_RADIUS, wtk_drag_origin.y - WTK_DRAG_HANDLE_RADIUS, WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE); gfx_draw_filled_circle(wtk_drag_origin.x, wtk_drag_origin.y, WTK_DRAG_HANDLE_RADIUS, WTK_DRAG_ORIGIN_COLOR, GFX_WHOLE); /* Store screen underneath and draw drag target symbol. */ gfx_get_pixmap(wtk_drag_target_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0, pos->x - WTK_DRAG_HANDLE_RADIUS, pos->y - WTK_DRAG_HANDLE_RADIUS, WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE); gfx_draw_filled_circle(pos->x, pos->y, WTK_DRAG_HANDLE_RADIUS, WTK_DRAG_TARGET_COLOR, GFX_WHOLE); return; outofmem_target: membag_free(wtk_drag_origin_pixmap); wtk_drag_origin_pixmap = NULL; outofmem_origin: return; }
/** Unit test to check that the Membag is initialized and re-initialized * correctly. * * \param test Pointer to the unit test case instance */ static void run_membag_init_test(const struct test_case *test) { /* Initialize membag system. */ membag_init(); /* Check that no memory is currently allocated */ test_assert_true(test, membag_get_total() == membag_get_total_free(), "Initialized membag should contain no allocated memory!"); /* Allocate a small chunk of memory */ membag_alloc(CONF_TEST_ALLOC_SIZE_SMALL); /* Check that sufficient memory was allocated */ test_assert_false(test, (membag_get_total() - membag_get_total_free()) < CONF_TEST_ALLOC_SIZE_SMALL, "Not enough memory was allocated!"); /* Re-Initialize membag system. */ membag_init(); /* Check that no memory is now allocated */ test_assert_true(test, membag_get_total() == membag_get_total_free(), "Re-Initialized membag should contain no allocated memory!"); }
/** Unit test to check that the Membag functions to determine memory status work * correctly. * * \param test Pointer to the unit test case instance */ static void run_membag_get_test(const struct test_case *test) { void *data; size_t prev_total_free, chunk_size; /* Initialize membag system. */ membag_init(); prev_total_free = membag_get_total_free(); /* Keep allocating chunks until all memory allocated */ while (membag_get_total_free() > 0) { /* Keep track of how much memory we have left and the largest * block size */ prev_total_free = membag_get_total_free(); chunk_size = membag_get_largest_free_block_size(); /* Allocate the next largest block sized chunk of memory */ data = membag_alloc(chunk_size); test_assert_false(test, data == NULL, "Unable to allocate a block sized chunk!"); /* Check that the new memory usage was calculated correctly */ test_assert_true(test, membag_get_total_free() == (prev_total_free - chunk_size), "Failed to calculate correct memory usage!"); } }
int mon_rtc(int argc, char **argv){ int time_buf_size = MD_BUF_SIZE; char *time_buf; uint8_t yr, dt, mo, dw, hr, mn, sc; if(argc<2){ printf("wrong number of args to set time\n"); return -1; } if(strcmp(argv[1],"get")==0){ time_buf = membag_alloc(time_buf_size); if(time_buf==NULL) core_panic(); rtc_get_time_str(time_buf,time_buf_size); printf("Time: %s\n",time_buf); membag_free(time_buf); } else if(strcmp(argv[1],"set")==0){ if(argc!=9){ printf("please specify yr dt mo dw hr mn sc\n"); return -1; } yr = atoi(argv[2]); mo = atoi(argv[3]); dt = atoi(argv[4]); dw = atoi(argv[5]); hr = atoi(argv[6]); mn = atoi(argv[7]); sc = atoi(argv[8]); if(i2c_rtc_set_time(sc,mn,hr,dw,dt,mo,yr)!=0) printf("error setting RTC\n"); else{ time_buf = membag_alloc(time_buf_size); if(time_buf==NULL) core_panic(); rtc_get_time_str(time_buf,time_buf_size); printf("Set time to: %s\n",time_buf); membag_free(time_buf); } } else{ printf("bad arguments to rtc\n"); return -1; } return 0; }
/** * This function creates a new icon button widget. It allocates required memory * and initializes necessary windows to create the widget. If there is not enough * memory, the function returns NULL. * To destroy the widget and all its contents, and free its memory, call * win_destroy() on the icon button's child reference, given by * wtk_icon_button_as_child(), like this: * "win_destroy(wtk_icon_button_as_child(myButtonPtr));". * Usually it will be destroyed automatically when it's parent is destroyed. * * \param parent Parent window, possibly wtk_frame_as_parent(myFramePtr). * \param area Area of the internal contents. * \param icon Bitmap to draw as the icon. * \param selected Initial state of icon button, true if checked/selected. * \param group Icon button group to be a member of. * \param command Command to send to parent window. Must be non-zero to be * enabled. * * \return Pointer to icon button, or NULL if failed. */ struct wtk_icon_button *wtk_icon_button_create(struct win_window *parent, struct win_area const *area, struct gfx_bitmap *icon, bool selected, struct wtk_icon_group *group, win_command_t command) { struct wtk_icon_button *icon_button; struct win_attributes attr; Assert(group); Assert(area); Assert(icon); Assert(parent); /* Allocate memory for check box control data. */ icon_button = membag_alloc(sizeof(struct wtk_icon_button)); if (!icon_button) { goto outofmem_icon_button; } icon_button->state = WTK_ICONBUTTON_NORMAL; icon_button->group = group; icon_button->command = command; /* Handling information. */ attr.event_handler = wtk_icon_button_handler; attr.custom = icon_button; /* Prepare container frame. */ attr.area = *area; attr.background = icon; attr.behavior = 0; icon_button->container = win_create(parent, &attr); if (!icon_button->container) { goto outofmem_container; } /* Select the icon button in the group if either no icon button is * currently selected (empty group), or the user has requested it takes * over the selection */ if (selected || (group->selected == NULL)) { /* Add ourselves to the icon group, take over selection if required. */ wtk_icon_button_select(icon_button); } /* Make sure we haven't filled up the group reference count, and * increment. */ Assert(group->num_references < (wtk_icon_group_size_t)-1L); ++(group->num_references); return icon_button; outofmem_container: membag_free(icon_button); outofmem_icon_button: return NULL; }
//Core memory functions void* core_malloc(int size){ void* ptr; ptr = membag_alloc(size); if(ptr==NULL) core_panic(); memset(ptr,0x0,size); return ptr; }
/** Unit test to check that the Membag allocations fail once all suitable bags * are already * allocated. * * \param test Pointer to the unit test case instance */ static void run_membag_alloc_when_full_test(const struct test_case *test) { void *data; /* Initialize membag system. */ membag_init(); /* Allocate as many small chunks as there are sufficiently sized blocks. */ while (membag_get_largest_free_block_size() >= CONF_TEST_ALLOC_SIZE_SMALL) { data = membag_alloc(CONF_TEST_ALLOC_SIZE_SMALL); test_assert_false(test, data == NULL, "Unable to allocate a small chunk!"); } /* Try to allocate one more small chunk, should fail */ data = membag_alloc(CONF_TEST_ALLOC_SIZE_SMALL); test_assert_true(test, data == NULL, "Should not be able to allocate small chunk while full!"); /* Re-initialize the membag system. */ membag_init(); /* Allocate as many large chunks as there are sufficiently sized blocks. */ while (membag_get_largest_free_block_size() >= CONF_TEST_ALLOC_SIZE_LARGE) { data = membag_alloc(CONF_TEST_ALLOC_SIZE_LARGE); test_assert_false(test, data == NULL, "Unable to allocate a large chunk!"); } /* Try to allocate one more large chunk, should fail */ data = membag_alloc(CONF_TEST_ALLOC_SIZE_LARGE); test_assert_true(test, data == NULL, "Should not be able to allocate large chunk while full!"); }
/** * \brief Set up calibration * * Allocates and initializes the application context; sets up the font, touch * event handler and calibration data; updates the display and then schedules * the calibration task. * * \param completed_task Task to schedule when calibration is complete */ void app_touch_calibrate_setup(struct workqueue_task *completed_task) { calibrate_context = membag_alloc(sizeof(struct touch_calibrate_context)); assert(calibrate_context != NULL); // Use twice as large font for this application. memcpy(&sysfont2x, &sysfont, sizeof(sysfont)); sysfont2x.scale = 2; // Temporarily replace touch event handler. calibrate_context->old_handler = touch_get_event_handler(); touch_set_event_handler(touch_calibrate_event_handler); // Clear the screen and draw the calibration guide text. gfx_set_clipping(0, 0, gfx_get_width(), gfx_get_height()); gfx_draw_filled_rect(0, 0, gfx_get_width(), gfx_get_height(), CAL_BG_COLOR); gfx_draw_progmem_string((const char __progmem_arg *) &calibrate_help_text, 10, 80, &sysfont2x, CAL_FG_COLOR, GFX_COLOR_TRANSPARENT); // Set panel coordinates for all calibration points. calibrate_context->cal_points[0].panel_x = (gfx_get_width() - CAL_OFFSET - 1); calibrate_context->cal_points[0].panel_y = (gfx_get_height() - CAL_OFFSET - 1); calibrate_context->cal_points[1].panel_x = (CAL_OFFSET); calibrate_context->cal_points[1].panel_y = (gfx_get_height() - CAL_OFFSET - 1); calibrate_context->cal_points[2].panel_x = (CAL_OFFSET); calibrate_context->cal_points[2].panel_y = (CAL_OFFSET); // Draw circle for first calibration point. gfx_draw_circle(calibrate_context->cal_points[0].panel_x, calibrate_context->cal_points[0].panel_y, CAL_RADIUS, CAL_FG_COLOR, GFX_WHOLE); // Initialize the calibration state and tasks before scheduling it. calibrate_context->state = 0; calibrate_context->completed_task = completed_task; workqueue_task_init(&calibrate_context->task, touch_calibrate_task_handler); workqueue_add_task(&main_workqueue, &calibrate_context->task); }
/** * This function creates a new radio button group, allocating required memory * and properly initializing the object. If there is not enough memory, the * function returns NULL. * The radio button group will keep a reference count for its members, and * will be automatically destroyed when the last member is destroyed. * * \return Pointer to radio button group, or NULL if failed. */ struct wtk_radio_group *wtk_radio_group_create(void) { /* Allocate memory for radio group data. */ struct wtk_radio_group *radio_group = membag_alloc(sizeof(struct wtk_radio_group)); if (!radio_group) { goto outofmem_radio_group; } /* Initialize. */ radio_group->num_references = 0; radio_group->selected = NULL; return radio_group; outofmem_radio_group: return NULL; }
/** * This function creates a new icon button group, allocating required memory * and properly initializing the object. If there is not enough memory, the * function returns NULL. * The icon button group will keep a reference count for its members, and * will be automatically destroyed when the last member is destroyed. * * \return Pointer to icon button group, or NULL if failed. */ struct wtk_icon_group *wtk_icon_group_create(void) { /* Allocate memory for icon group data. */ struct wtk_icon_group *icon_group = membag_alloc(sizeof(struct wtk_icon_group)); if (!icon_group) { goto outofmem_icon_group; } /* Initialize. */ icon_group->num_references = 0; icon_group->selected = NULL; return icon_group; outofmem_icon_group: return NULL; }
/** Set new caption for label, return false if out of mem. */ bool wtk_label_change(struct wtk_label *label, const char *caption) { Assert(label); Assert(caption); uint8_t new_len = strlen(caption); uint8_t old_len = 0; if (caption) { old_len = strlen(label->caption); } /* Only free old memory if new length is longer than the * previous label. */ if (new_len > old_len) { /* Free old caption, if present. */ if (caption) { membag_free(label->caption); } /* Allocate memory for caption string, and copy text. */ label->caption = membag_alloc((new_len + 1) * sizeof(char)); if (!label->caption) { goto outofmem_caption; } } wtk_copy_string(label->caption, caption); /* Redraw if visible. */ win_redraw(label->container); return true; outofmem_caption: return false; }
/** * This function creates a new label widget. It allocates required memory * and intializes necessary windows to create the widget. If there is not enough * memory, the function returns NULL. * * To destroy the widget and all its contents, and free its memory, call * win_destroy() on the label's child reference, given by * wtk_label_as_child(), * like this: "win_destroy(wtk_label_as_child(myStaticTextPtr));". * Usually it will be destroyed automatically when it's parent is destroyed. * * \param parent Parent window, possibly wtk_frame_as_parent(myFramePtr). * \param area Area of the internal contents. * \param caption Pointer to caption string. Will be copied into widget. * \param text_color Foreground color of the text when drawn. * \param background Background of the label. * \param align_right True if caption is to be aligned to the right, * false otherwise. * \return Pointer to label, or NULL if failed. */ struct wtk_label *wtk_label_create(struct win_window *parent, struct win_area const *area, char const *caption, gfx_color_t text_color, struct gfx_bitmap *background, bool align_right) { struct win_attributes attr; struct wtk_label *label; Assert(area); Assert(caption); Assert(parent); /* Allocate memory for label control data. */ label = membag_alloc(sizeof(struct wtk_label)); if (!label) { goto outofmem_label; } label->text_color = text_color; label->align_right = align_right; /* Allocate memory for caption string, and copy text. */ label->caption = membag_alloc((strlen(caption) + 1) * sizeof(char)); if (!label->caption) { goto outofmem_caption; } wtk_copy_string(label->caption, caption); /* Handling information. */ attr.event_handler = wtk_label_handler; attr.custom = label; /* Prepare container frame. */ attr.area = *area; /* Set background for label. */ if (background) { attr.background = background; attr.behavior = 0; } else { attr.background = NULL; attr.behavior = WIN_BEHAVIOR_REDRAW_PARENT; } label->container = win_create(parent, &attr); if (!label->container) { goto outofmem_container; } return label; outofmem_container: membag_free(label->caption); outofmem_caption: membag_free(label); outofmem_label: return NULL; }
/** * \brief Launch the water tank application. * * This function allocates memory, creates the application frame and widgets, * initializes the timer and initiates loading of the required bitmaps. * * One basic frame is created, along with four widgets: one slider, two progress * bars and a command button. These are not shown until the background image has * been loaded. * * If the alarm light bitmaps have already been loaded, i.e., the application * has already been run, the application will skip directly to loading of the * background image. * * If memory for the application context cannot be allocated or the frame or * widgets cannot be created, the application will exit immediately. * * \param task Workqueue task to use for the application's worker functions. */ void app_tank_launch(struct workqueue_task *task) { struct win_attributes attr; struct win_window *win; struct gfx_bitmap bitmap; struct wtk_basic_frame *frame; struct wtk_slider *slider; struct wtk_button *button; struct wtk_progress_bar *pbar; struct timer *timer; timer_res_t timer_res; uint32_t timer_clk; assert(task); // Clear the screen right away. #ifdef CONFIG_GFX_USE_CLIPPING gfx_set_clipping(0, 0, gfx_get_width(), gfx_get_height()); #endif /* CONFIG_GFX_USE_CLIPPING */ gfx_draw_filled_rect(0, 0, gfx_get_width(), gfx_get_height(), COLOR_WIN_BACKGROUND); // Allocate the application context first. tank_ctx = membag_alloc(sizeof(struct tank_context)); if (!tank_ctx) goto exit_no_context; // Use larger sysfont for this app. memcpy(&tank_ctx->old_sysfont, &sysfont, sizeof(struct font)); sysfont.scale = 2; // Create a basic frame to contain the widgets. attr.area.pos.x = 0; attr.area.pos.y = 0; attr.area.size.x = gfx_get_width(); attr.area.size.y = gfx_get_height(); frame = wtk_basic_frame_create(win_get_root(), &attr.area, NULL, NULL, tank_frame_handler, NULL); if (!frame) { goto exit_no_frame; } tank_ctx->frame = frame; // Get the frame's window to use as parent for widgets. win = wtk_basic_frame_as_child(frame); // Initialize the application timer. timer = &tank_ctx->timer; timer_init(CONFIG_TIMER_ID, timer, tank_timer_callback); timer_res = timer_set_resolution(CONFIG_TIMER_ID, timer, TICK_RATE); timer_write_resolution(CONFIG_TIMER_ID, timer, timer_res); // Get the timer alarm delay to use for the configured tick rate. timer_clk = timer_get_resolution(CONFIG_TIMER_ID, timer, timer_res); tank_ctx->timer_delay = timer_clk / TICK_RATE; // Initialize random variable and tick count. tank_ctx->rand = 1; tank_ctx->rand_ticks = TICKS_PER_RANDOM_UPDATE; // Create the supply slider. attr.area.pos.x = WIDGET_SUPPLY_POSITION_X; attr.area.pos.y = WIDGET_SUPPLY_POSITION_Y; attr.area.size.x = WIDGET_SUPPLY_SIZE_X; attr.area.size.y = WIDGET_SUPPLY_SIZE_Y; slider = wtk_slider_create(win, &attr.area, VALUE_SUPPLY_MAXIMUM, VALUE_SUPPLY_INITIAL, WTK_SLIDER_VERTICAL | WTK_SLIDER_INVERT, CMD_NONE); if (!slider) { goto exit_no_widget; } tank_ctx->supply = slider; win_show(wtk_slider_as_child(slider)); // Create the tank level progress bar. attr.area.pos.x = WIDGET_LEVEL_POSITION_X; attr.area.pos.y = WIDGET_LEVEL_POSITION_Y; attr.area.size.x = WIDGET_LEVEL_SIZE_X; attr.area.size.y = WIDGET_LEVEL_SIZE_Y; pbar = wtk_progress_bar_create(win, &attr.area, VALUE_LEVEL_MAXIMUM, VALUE_LEVEL_INITIAL, COLOR_LEVEL_FILL, COLOR_LEVEL_BACKGROUND, WTK_PROGRESS_BAR_VERTICAL | WTK_PROGRESS_BAR_INVERT); if (!pbar) { goto exit_no_widget; } tank_ctx->level = pbar; win_show(wtk_progress_bar_as_child(pbar)); // Create the demand progress bar. attr.area.pos.x = WIDGET_DEMAND_POSITION_X; attr.area.pos.y = WIDGET_DEMAND_POSITION_Y; attr.area.size.x = WIDGET_DEMAND_SIZE_X; attr.area.size.y = WIDGET_DEMAND_SIZE_Y; pbar = wtk_progress_bar_create(win, &attr.area, VALUE_DEMAND_MAXIMUM, VALUE_DEMAND_INITIAL, COLOR_DEMAND_NORMAL, COLOR_DEMAND_BACKGROUND, WTK_PROGRESS_BAR_VERTICAL | WTK_PROGRESS_BAR_INVERT); if (!pbar) { goto exit_no_widget; } tank_ctx->demand = pbar; win_show(wtk_progress_bar_as_child(pbar)); // Create the exit button with the standard settings. attr.area.pos.x = APP_EXIT_BUTTON_POS_X; attr.area.pos.y = APP_EXIT_BUTTON_POS_Y; attr.area.size.x = APP_EXIT_BUTTON_SIZE_X; attr.area.size.y = APP_EXIT_BUTTON_SIZE_Y; button = wtk_button_create(win, &attr.area, APP_EXIT_BUTTON_TEXT, (win_command_t)CMD_EXIT); if (!button) { goto exit_no_widget; } win_show(wtk_button_as_child(button)); // Set the tank alarm to trigger initial drawing of alarm light. tank_ctx->level_alarm = true; tank_ctx->flow_alarm = false; tank_ctx->task = task; /* Initialize bitmap data and set initial application loader state: * If the alarm light bitmaps have already been loaded, skip right to * loading of the application background bitmap. */ bitmap.width = BITMAP_LIGHT_SIZE_X; bitmap.height = BITMAP_LIGHT_SIZE_Y; bitmap.type = BITMAP_HUGEMEM; tank_ctx->bitmaps[BITMAP_RED_LIGHT] = bitmap; tank_ctx->bitmaps[BITMAP_GREEN_LIGHT] = bitmap; if (tank_bitmap_data[BITMAP_GREEN_LIGHT]) { tank_ctx->loader_state = LOAD_BACKGROUND; tank_ctx->bitmaps[BITMAP_RED_LIGHT].data.hugemem = tank_bitmap_data[BITMAP_RED_LIGHT]; tank_ctx->bitmaps[BITMAP_GREEN_LIGHT].data.hugemem = tank_bitmap_data[BITMAP_GREEN_LIGHT]; } else { tank_ctx->loader_state = LOAD_RED_LIGHT; } workqueue_task_set_work_func(task, tank_loader); workqueue_add_task(&main_workqueue, task); return; // Handle allocation errors. exit_no_widget: win_destroy(wtk_basic_frame_as_child(tank_ctx->frame)); exit_no_frame: memcpy(&sysfont, &tank_ctx->old_sysfont, sizeof(struct font)); membag_free(tank_ctx); exit_no_context: app_desktop_restart(); return; }
/** * \brief Create a new slider widget. * * Allocates the necessary memory and intializes the window and data for slider * widgets. If there is not enough memory, the function returns NULL.\n * To destroy a slider widget and all its contents, and free its memory, call * \ref win_destroy() on the slider's child reference, given by * \ref wtk_slider_as_child(), like this: * "win_destroy(wtk_slider_as_child(my_slider_ptr));".\par * * Slider widgets fill the specified area and perform a mapping of the slider * knob's position to a value between 0 and maximum. The length of the slider * cannot exceed 255 pixels.\par * * By default, the value 0 corresponds to the top-most position for a vertical * slider, and the left-most position for a horizontal one. The slider's * orientation and inversion of the value can be configured.\par * * A slider can be configured to issue command events whenever its value is * changed by a pointer and/or when a pointer releases it.\par * * Refer to <gfx/wtk.h> for available configuration options. * * \todo Revisit, support larger sliders and values given a config symbol. * * \param parent Pointer to parent win_window struct. * \param area Pointer to win_area struct with position and size of the slider. * \param maximum Maximum value of the slider. * \param value Initial value of the slider. * \param option Configuration options for slider. * See \ref gfx_wtk_slider_options * \param command Command to send to parent window. Must be non-zero if used. * * \return Pointer to new slider, if memory allocation was successful. */ struct wtk_slider *wtk_slider_create(struct win_window *parent, struct win_area const *area, uint8_t maximum, uint8_t value, uint8_t option, win_command_t command) { struct win_attributes attr; struct wtk_slider *slider; uint8_t length; // Do sanity check on parameters. assert(maximum > 0); assert(area); assert(parent); // Allocate memory for the control data. slider = membag_alloc(sizeof(struct wtk_slider)); if (!slider) { goto outofmem_slider; } // Initialize the slider data. slider->state = WTK_SLIDER_NORMAL; slider->maximum = maximum; slider->value = value; slider->option = option; // Invert the initial value if slider is inverted. if (option & WTK_SLIDER_INVERT) { value = maximum - value; } slider->value = value; // Enforce a non-zero command value, if these are enabled. if (option & (WTK_SLIDER_CMD_MOVE | WTK_SLIDER_CMD_RELEASE)) { assert(command > 0); slider->command = command; } // Set up event handling for the widget window. attr.event_handler = wtk_slider_handler; attr.custom = slider; // Do a sanity check of the specified window area parameters. attr.area = *area; assert(attr.area.size.x > 0); assert(attr.area.size.y > 0); if (option & WTK_SLIDER_VERTICAL) { assert(attr.area.size.x > 3); assert(attr.area.size.x <= (uint8_t) ~ 0); assert(attr.area.size.y > WTK_SLIDER_KNOB_WIDTH); length = attr.area.size.y; } else { assert(attr.area.size.x > WTK_SLIDER_KNOB_WIDTH); assert(attr.area.size.y <= (uint8_t) ~ 0); assert(attr.area.size.y > 3); length = attr.area.size.x; } // Set slider knob position according to initial value. length -= WTK_SLIDER_KNOB_WIDTH; slider->position = wtk_rescale_value(value, maximum, length); /* All drawing is done in wtk_slider_handler() to reduce overhead. * Slider has no transparent areas, so parent does not need redrawing. */ attr.background = NULL; attr.behavior = 0; // Create the widget window. slider->container = win_create(parent, &attr); if (!slider->container) { goto outofmem_container; } // Store absolute position win_translate_win_to_root(slider->container, &slider->root_pos); return slider; outofmem_container: membag_free(slider); outofmem_slider: return NULL; }
/** * \brief Setup widget demo * * Allocates memory for the application context, and creates all widgets that * make up its interface. If memory allocation or widget creation fails, the * application exits immediately. * * \return Boolean true if the application was launched successfully, false if * a memory allocation occurred. */ bool app_widget_launch(void) { struct win_window *parent; struct win_area area; struct wtk_button *button; /* Create a new context for the GUI */ widget_ctx = membag_alloc(sizeof(struct widget_context)); if (!widget_ctx) { return false; } /* Initialize context data. */ widget_ctx->frame_bg.type = GFX_BITMAP_SOLID; widget_ctx->frame_bg.data.color = GFX_COLOR(220, 220, 220); /* Set the area for the GUI window */ area = win_get_attributes(win_get_root())->area; win_inflate_area(&area, -20); /* Create and show the main GUI frame */ widget_ctx->frame = wtk_basic_frame_create( win_get_root(), &area, &widget_ctx->frame_bg, NULL, widget_frame_command_handler, widget_ctx); if (!widget_ctx->frame) { goto error_frame; } parent = wtk_basic_frame_as_child(widget_ctx->frame); win_show(parent); /* Set the background information for the plot widget */ widget_ctx->plot_bg.type = GFX_BITMAP_SOLID; widget_ctx->plot_bg.data.color = GFX_COLOR_WHITE; /* Adjust area for the plot widget */ area.size.y -= 80; area.size.x -= 40; /* Create and show the plot widget with vertical axis marks */ widget_ctx->plot = wtk_plot_create(parent, &area, 100, 10, GFX_COLOR_RED, &widget_ctx->plot_bg, WTK_PLOT_LEFT_TO_RIGHT); if (!widget_ctx->plot) { goto error_widget; } wtk_plot_set_grid(widget_ctx->plot, WTK_PLOT_TICKS_VERTICAL, 10, 0, 10, 0, GFX_COLOR_BLUE, GFX_COLOR_GREEN); win_show(wtk_plot_as_child(widget_ctx->plot)); /* Adjust area for the slider widget */ area.pos.y += area.size.y + 10; area.size.y = 40; area.size.x -= 60; /* Create and show the slider widget */ widget_ctx->slider = wtk_slider_create(parent, &area, 100, 0, WTK_SLIDER_HORIZONTAL, (win_command_t)SLIDER_ID); if (!widget_ctx->slider) { goto error_widget; } win_show(wtk_slider_as_child(widget_ctx->slider)); /* Adjust area for the button widget */ area.pos.x += area.size.x + 10; area.size.x = 50; /* Create and show the button widget */ button = wtk_button_create(parent, &area, "Add", (win_command_t)BUTTON_ID); if (!button) { goto error_widget; } win_show(wtk_button_as_child(button)); return true; /* Error handling to clean up allocations after an error */ error_widget: win_destroy(wtk_basic_frame_as_child(widget_ctx->frame)); error_frame: membag_free(widget_ctx); return false; }
/** * \brief Create a new progress bar widget. * * Allocates the necessary memory and intializes the window and data for * progress bar widgets. If there is not enough memory, the function returns * NULL.\n To destroy a progress bar widget and all its contents, and free its * memory, call \ref win_destroy() on the progress bar's child reference, given * by \ref wtk_progress_bar_as_child(), like this: * "win_destroy(wtk_progress_bar_as_child(my_progress_bar_ptr));".\par * * Progress bar widgets divide their window area in two non-overlapping * rectangles: one with a fill color, and one with a background color. * The ratio between the two rectangles' sizes is given by the progress bar's * value relative to its maximum: a higher value gives a larger fill.\par * * By default, a vertically oriented progress bar fills from the top, while a * horizontal one fills from the left. The progress bar's orientation and fill * direction can both be configured at the time of creation. The fill and * background colors can be changed at runtime.\par * * Refer to <gfx/wtk.h> for available configuration options. * * \param parent Pointer to parent win_window struct. * \param area Pointer to win_area struct with position and size of the * progress bar. Minimum size in both x and y direction is 3 pixels. * \param maximum Maximum value of the progress bar. * \param value Initial value of the progress bar. * \param fill_color Color for filled area. * \param background_color Color for background area. * \param option Configuration options for progress bar. * * \return Pointer to new progress bar, if memory allocation was successful. */ struct wtk_progress_bar *wtk_progress_bar_create(struct win_window *parent, struct win_area const *area, uint8_t maximum, uint8_t value, gfx_color_t fill_color, gfx_color_t background_color, uint8_t option) { uint8_t length; /* Do sanity check on parameters. */ Assert(maximum > 0); Assert(value <= maximum); Assert(area); Assert(parent); /* Attributes scratchpad. */ struct win_attributes attr; /* Allocate memory for the control data. */ struct wtk_progress_bar *bar = membag_alloc(sizeof(struct wtk_progress_bar)); if (!bar) { goto outofmem_bar; } /* Initialize the progress bar data. */ bar->maximum = maximum; bar->value = value; bar->option = option; /* Set the progress bar's colors and prepare the value for computation * of the bar's end position according to the invert option. */ if (option & WTK_PROGRESS_BAR_INVERT) { bar->fill_color = background_color; bar->background_color = fill_color; value = maximum - value; } else { bar->fill_color = fill_color; bar->background_color = background_color; } /* Set up handling information. */ attr.event_handler = wtk_progress_bar_handler; attr.custom = bar; /* Do sanity check of specified window area parameters * according to the orientation of the progress bar. */ attr.area = *area; Assert(attr.area.size.x > 3); Assert(attr.area.size.y > 3); if (option & WTK_PROGRESS_BAR_VERTICAL) { Assert(attr.area.size.y < (uint8_t) ~0); length = attr.area.size.y; } else { Assert(attr.area.size.x < (uint8_t) ~0); length = attr.area.size.x; } length -= 2; /* Set the progress bar's end position. */ bar->position = wtk_rescale_value(value, maximum, length); /* All drawing is done in wtk_progress_bar_handler() so no background is * needed. */ attr.background = NULL; /* Since the widget has no transparent areas, the parent does not need * to be redrawn. */ attr.behavior = 0; /* Create a new window for the progress bar. */ bar->container = win_create(parent, &attr); if (!bar->container) { goto outofmem_container; } return bar; outofmem_container: membag_free(bar); outofmem_bar: return NULL; }
/** * This function creates a new frame widget. It allocates required memory and * intializes necessary windows to create the widget. If there is not enough * memory, the function returns NULL. * * To destroy the widget and all its contents, and free its memory, call * win_destroy() on the frame's child reference, given by wtk_frame_as_child(), * like this: "win_destroy(wtk_frame_as_child(my_frame_ptr));". * The frame's internal area will equal the area parameter, but the total * extents will be slightly larger, to accommodate for titlebar, borders etc. * * \param parent Parent window. * \param area Area of the internal contents. * \param caption Pointer to caption string. Will be copied into widget. * \param allow_resize True if resize handle should be included on the frame. * \param frame_handler Optional command event handler, for applications. * \param custom_data Optional custom data link, for applications. * * \return Pointer to frame, or NULL if failed. */ struct wtk_frame *wtk_frame_create(struct win_window *parent, struct win_area const *area, char const *caption, bool allow_resize, wtk_frame_handler_t frame_handler, void *custom_data) { struct win_attributes attr; struct wtk_frame *frame; Assert(area); Assert(caption); Assert(parent); /* Allocate memory for frame control data. */ frame = membag_alloc(sizeof(struct wtk_frame)); if (!frame) { goto outofmem_frame; } frame->state = WTK_FRAME_NORMAL; frame->frame_handler = frame_handler; frame->custom_data = custom_data; /* Allocate memory for caption string, and copy text. */ frame->caption = membag_alloc((strlen(caption) + 1) * sizeof(char)); if (!frame->caption) { goto outofmem_caption; } wtk_copy_string(frame->caption, caption); /* Start with valid area info, but only contents frame will keep the * original area. The other frames will be resized properly at the end. * All windows have the same event handler, and the same link back to * the widget object. */ attr.area = *area; attr.event_handler = wtk_frame_handler; attr.custom = frame; /* Prepare container frame, which will contain title bar, border, size, * handle etc. */ attr.background = NULL; attr.behavior = WIN_BEHAVIOR_RAISE_ON_PRESS; /* Create the container window, the proper size will be set later. */ frame->container = win_create(parent, &attr); if (!frame->container) { goto outofmem_container; } /* Prepare the contents frame, which will contain whatever controls * owned by the frame. Size will be equal to the given area parameter. */ attr.area.pos.x = WTK_FRAME_LEFTBORDER; attr.area.pos.y = WTK_FRAME_TOPBORDER + WTK_FRAME_TITLEBAR_HEIGHT; attr.background = &wtk_frame_background; attr.behavior = 0; frame->contents = win_create(frame->container, &attr); if (!frame->contents) { goto outofmem_contents; } /* Only create resize handle window if resize is allowed. */ if (allow_resize) { /* Prepare resize handle. Proper position will be set later. * Size is set here, though. */ attr.area.size.x = WTK_FRAME_RESIZE_WIDTH; attr.area.size.y = WTK_FRAME_RESIZE_HEIGHT; attr.background = NULL; attr.behavior = 0; frame->resize = win_create(frame->container, &attr); if (!frame->resize) { goto outofmem_resize; } win_show(frame->resize); } else { frame->resize = NULL; } /* Now, resize and rearrange according to size of contents frame, which * is equal to the given area parameter. */ wtk_resize_frame(frame, area); /* Make sure internals are visible when frame is mapped. */ win_show(frame->contents); return frame; outofmem_resize: win_destroy(frame->contents); outofmem_contents: win_destroy(frame->container); outofmem_container: membag_free(frame->caption); outofmem_caption: membag_free(frame); outofmem_frame: return NULL; }
void monitor(void){ uint32_t prev_tick=0; //allocate memory for buffers and flush them cmd_buf = membag_alloc(CMD_BUF_SIZE); if(!cmd_buf) core_panic(); memset(cmd_buf,0x0,CMD_BUF_SIZE); //initialize the power packet buffers tx_pkt = &power_pkts[0]; cur_pkt = &power_pkts[1]; //both are empty tx_pkt->status = POWER_PKT_EMPTY; cur_pkt->status = POWER_PKT_EMPTY; //initialize runtime configs wemo_config.echo = false; wemo_config.debug_level = DEBUG_ERROR; wemo_config.collect_data = true; //collect power data //check if we are on USB if(gpio_pin_is_high(VBUS_PIN)){ rgb_led_set(LED_LT_BLUE,0); //don't start wifi because we are configuring b_wifi_enabled=false; //don't collect power data wemo_config.collect_data = false; } //check if the plug is in calibrate mode if(wemo_config.calibrate){ //start the calibration PWM pwm_channel_enable_interrupt(PWM,CAL_PWM_CHANNEL,CAL_PWM_CHANNEL); pwm_channel_enable(PWM,CAL_PWM_CHANNEL); //don't start wifi because we are in calibration mode b_wifi_enabled=false; wemo_config.standalone = true; wemo_config.collect_data = false; //indicate cal mode with a purple LED rgb_led_set(LED_PURPLE,0); } //check if reset is pressed if(gpio_pin_is_low(BUTTON_PIN)){ //erase the configs memset(wemo_config.nilm_id,0x0,MAX_CONFIG_LEN); memset(wemo_config.nilm_ip_addr,0x0,MAX_CONFIG_LEN); memset(wemo_config.wifi_ssid,0x0,MAX_CONFIG_LEN); memset(wemo_config.wifi_pwd,0x0,MAX_CONFIG_LEN); //save the erased config fs_write_config(); core_log("erased config"); //erase the stored data //spin until button is released rgb_led_set(LED_ORANGE,500); while(gpio_pin_is_low(BUTTON_PIN)); rgb_led_set(LED_ORANGE,0); //disable blink } //setup WIFI if(b_wifi_enabled){ if(wifi_init()!=0){ rgb_led_set(LED_PURPLE,0); } else{ //good to go! turn light green rgb_led_set(LED_LT_GREEN,0); } } //initialize the wifi_rx buffer and flag wifi_rx_buf_full = false; memset(wifi_rx_buf,0x0,WIFI_RX_BUF_SIZE); while (1) { //***** SYS TICK ACTIONS ****** if(sys_tick!=prev_tick){ //check if there is a valid wemo sample if(wemo_sample.valid==true && wemo_config.collect_data){ core_log_power_data(&wemo_sample); } wemo_read_power(); wdt_restart(WDT); prev_tick = sys_tick; } //check for pending data from the Internet if(wifi_rx_buf_full){ core_process_wifi_data(); wifi_rx_buf_full=false; } //see if we have any commands to run if(cmd_buf_full){ runcmd(cmd_buf); // run it //clear the buffer cmd_buf_idx = 0; memset(cmd_buf,0x0,CMD_BUF_SIZE); if(wemo_config.echo) printf("\r> "); //print the prompt cmd_buf_full=false; } } }
void core_process_wifi_data(void){ int BUF_SIZE=XL_BUF_SIZE; char *buf; int chan_num, data_size, r; unsigned int red,green,blue, blink; unsigned int yr,mo,dt,dw,hr,mn,sc; int time_buf_size = MD_BUF_SIZE; char *time_buf; //match against the data if(strlen(wifi_rx_buf)>BUF_SIZE){ printf("can't process rx'd packet, too large\n"); core_log("can't process rx'd packet, too large"); return; } //allocate memory buf = core_malloc(BUF_SIZE); r=sscanf(wifi_rx_buf,"\r\n+IPD,%d,%d:%s", &chan_num, &data_size, buf); if(r!=3){ printf("rx'd corrupt data, ignoring\n"); core_log("rx'd corrupt data, ignoring\n"); //free memory core_free(buf); return; } if(wemo_config.debug_level>DEBUG_INFO) printf("Got [%d] bytes on channel [%d]\n", data_size, chan_num); //discard responses from the NILM to power logging packets, but keep the response //if another core function has requested some data, this is done with the callback //function. The requesting core function registers a callback and this function calls //it and then resets the callback to NULL if(chan_num==4){ //close the socket wifi_send_cmd("AT+CIPCLOSE=4","Unlink",buf,BUF_SIZE,1); //execute the callback if(tx_callback!=NULL){ (*tx_callback)(wifi_rx_buf); tx_callback=NULL; } //clear the server buffer memset(wifi_rx_buf,0x0,WIFI_RX_BUF_SIZE); //free memory core_free(buf); return; } /////////////////// //this data must be inbound to the server port, process the command // // RELAY ON if(strcmp(buf,"relay_on")==0){ gpio_set_pin_high(RELAY_PIN); printf("relay ON\n"); //return "OK" to indicate success wifi_send_txt(0,"OK"); } // RELAY OFF else if(strcmp(buf,"relay_off")==0){ gpio_set_pin_low(RELAY_PIN); printf("relay OFF\n"); //return "OK" to indicate success wifi_send_txt(0,"OK"); } // LED SET else if(strstr(buf,"set_led")==buf){ if(sscanf(buf,"set_led_%u_%u_%u_%u.",&red,&green,&blue,&blink)!=4){ core_log("corrupt led_set request"); } else { rgb_led_set(red,green,blue,blink); if(wemo_config.echo) printf("set led: [%u, %u, %u, %u]\n",red,green,blue,blink); wifi_send_txt(0,"OK"); } } // RTC SET else if(strstr(buf,"set_rtc")==buf){ if(sscanf(buf,"set_rtc_%u_%u_%u_%u_%u_%u_%u.", &yr,&mo,&dt,&dw,&hr,&mn,&sc)!=7){ core_log("corrupt rtc_set request"); } else { if(i2c_rtc_set_time(sc,mn,hr,dw,dt,mo,yr)!=0) printf("error setting RTC\n"); else{ time_buf = membag_alloc(time_buf_size); if(time_buf==NULL) core_panic(); rtc_get_time_str(time_buf,time_buf_size); if(wemo_config.echo) printf("wifi set rtc to: %s\n",time_buf); core_log("wifi set rtc"); membag_free(time_buf); wifi_send_txt(0,"OK"); } } } // SEND DATA else if(strcmp(buf,"send_data")==0){ if(tx_pkt->status!=POWER_PKT_READY){ r = wifi_send_txt(chan_num,"error: no data"); if(r==TX_ERR_MODULE_RESET) while(wifi_init()!=0); //fail!!! anger!!!! reset the module } else { //send the data r=wifi_send_raw(chan_num,(uint8_t*)tx_pkt,sizeof(*tx_pkt)); if(r==TX_ERR_MODULE_RESET){ while(wifi_init()!=0); //fail!! anger!!! reset the module } else { //clear out the packet so we can start again memset(tx_pkt,0,sizeof(*tx_pkt)); tx_pkt->status=POWER_PKT_EMPTY; if(wemo_config.debug_level>=DEBUG_INFO) printf("sent data\n"); } } } else{ printf("unknown command: %s\n",buf); wifi_send_txt(chan_num,"error: unknown command"); //free memory core_free(buf); return; } //clear the server buffer memset(wifi_rx_buf,0x0,WIFI_RX_BUF_SIZE); //free the memory core_free(buf); return; }
/** * This function creates a new radio button widget. It allocates required memory * and intializes necessary windows to create the widget. If there is not enough * memory, the function returns NULL. * To destroy the widget and all its contents, and free its memory, call * win_destroy() on the radio button's child reference, given by * wtk_radio_button_as_child(), like this: * "win_destroy(wtk_radio_button_as_child(myButtonPtr));". * Usually it will be destroyed automatically when it's parent is destroyed. * * \param parent Parent window, possibly wtk_frame_as_parent(myFramePtr). * \param area Area of the internal contents. * \param caption Pointer to caption string. Will be copied into widget. * \param selected Initial state of radio button, true if checked/selected. * \param group Radio button group to be a member of. * \param command Command to send to parent window. Must be non-zero to be * enabled. * * \return Pointer to radio button, or NULL if failed. */ struct wtk_radio_button *wtk_radio_button_create(struct win_window *parent, struct win_area const *area, char const *caption, bool selected, struct wtk_radio_group *group, win_command_t command) { struct wtk_radio_button *radio_button; struct win_attributes attr; Assert(group); Assert(area); Assert(caption); Assert(parent); /* Allocate memory for check box control data. */ radio_button = membag_alloc(sizeof(struct wtk_radio_button)); if (!radio_button) { goto outofmem_radio_button; } radio_button->state = WTK_RADIOBUTTON_NORMAL; radio_button->group = group; radio_button->command = command; /* Allocate memory for caption string, and copy text. */ radio_button->caption = membag_alloc( (strlen(caption) + 1) * sizeof(char)); if (!radio_button->caption) { goto outofmem_caption; } wtk_copy_string(radio_button->caption, caption); /* Handling information. */ attr.event_handler = wtk_radio_button_handler; attr.custom = radio_button; /* Prepare container frame. */ attr.area = *area; attr.background = NULL; attr.behavior = WIN_BEHAVIOR_REDRAW_PARENT; radio_button->container = win_create(parent, &attr); if (!radio_button->container) { goto outofmem_container; } /* Select the radio button in the group if either no radio button is * currently selected (empty group), or the user has requested it takes * over the selection */ if (selected || (group->selected == NULL)) { wtk_radio_button_select(radio_button); } /* Make sure we haven't filled up the group reference count, and * increment. */ Assert(group->num_references < (wtk_radio_group_size_t)-1L); ++(group->num_references); return radio_button; outofmem_container: membag_free(radio_button->caption); outofmem_caption: membag_free(radio_button); outofmem_radio_button: return NULL; }
/** * \brief Setup widget demo * * Allocates memory for the application context, and creates all widgets that * make up its interface. If memory allocation or widget creation fails, the * application exits immediately. * * \return Boolean true if the application was launched successfully, false if * a memory allocation occurred. */ bool app_widget_launch(void) { struct win_window *parent; struct win_area area; struct wtk_check_box *cb; struct wtk_radio_group *rg; struct wtk_radio_button *rb; struct wtk_button *btn; /* Create a new context for the GUI */ widget_ctx = membag_alloc(sizeof(struct widget_context)); if (!widget_ctx) { return false; } /* Initialize context data. */ widget_ctx->color_scheme = 0; widget_ctx->color_invert = 0; /* Set the background information for the GUI window */ widget_ctx->frame_bg.type = GFX_BITMAP_SOLID; widget_ctx->frame_bg.data.color = APP_BACKGROUND_COLOR; /* Set the area for the GUI window */ area = win_get_attributes(win_get_root())->area; win_inflate_area(&area, -20); /* Create and show the main GUI frame */ widget_ctx->frame = wtk_basic_frame_create( win_get_root(), &area, &widget_ctx->frame_bg, NULL, widget_frame_command_handler, widget_ctx); if (!widget_ctx->frame) { goto error_frame; } parent = wtk_basic_frame_as_child(widget_ctx->frame); win_show(parent); /* Update area for the slider widget */ area.pos.x = WIDGET_POS_X; area.pos.y = WIDGET_POS_Y + SLIDER_POS_Y; area.size.x = SLIDER_SIZE_X; area.size.y = SLIDER_SIZE_Y; /* Create slider inside frame */ widget_ctx->slider = wtk_slider_create(parent, &area, 100, 50, WTK_SLIDER_HORIZONTAL | WTK_SLIDER_CMD_MOVE | WTK_SLIDER_CMD_RELEASE, (win_command_t)SLIDER_ID); if (!widget_ctx->slider) { goto error_widget; } win_show(wtk_slider_as_child(widget_ctx->slider)); /* Update area for the progress bar widget */ area.pos.x += area.size.x + SLIDER_PB_SPACING_X; area.size.x = PB_SIZE_X; area.size.y = PB_SIZE_Y; /* Create progress bar to the right of the slider */ widget_ctx->pb = wtk_progress_bar_create(parent, &area, 100, 50, GFX_COLOR_BLACK, GFX_COLOR_BLACK, WTK_PROGRESS_BAR_HORIZONTAL); if (!widget_ctx->pb) { goto error_widget; } win_show(wtk_progress_bar_as_child(widget_ctx->pb)); app_widget_update_colors(widget_ctx); /* Update area for the checkbox widget */ area.pos.x = WIDGET_POS_X; area.pos.y += area.size.y + CHECK_BOX_SPACING_Y; wtk_check_box_size_hint(&area.size, checkbox_string); /* Create check box below slider and progress bar */ cb = wtk_check_box_create(parent, &area, checkbox_string, false, (win_command_t)CHECK_BOX_ID); if (!cb) { goto error_widget; } win_show(wtk_check_box_as_child(cb)); /* Create a logical group for the radio buttons */ rg = wtk_radio_group_create(); if (!rg) { goto error_widget; } /* Update area for the first radio button widget */ area.pos.y += area.size.y + RADIO_BUTTON_SPACING_Y; wtk_radio_button_size_hint(&area.size, rb1_string); /* Create first radio button widget */ rb = wtk_radio_button_create(parent, &area, rb1_string, true, rg, (win_command_t)RADIO_BUTTON_1_ID); if (!rb) { goto error_widget; } win_show(wtk_radio_button_as_child(rb)); /* Update area for the second radio button widget */ area.pos.y += area.size.y + RADIO_BUTTON_SPACING_Y; wtk_radio_button_size_hint(&area.size, rb2_string); /* Create second radio button widget */ rb = wtk_radio_button_create(parent, &area, rb2_string, false, rg, (win_command_t)RADIO_BUTTON_2_ID); if (!rb) { goto error_widget; } win_show(wtk_radio_button_as_child(rb)); /* Update area for the button widget */ area.pos.y += area.size.y + BUTTON_SPACING_Y; area.size.x = SLIDER_SIZE_X + SLIDER_PB_SPACING_X + PB_SIZE_X; area.size.y = BUTTON_SIZE_Y; /* Create button widget */ btn = wtk_button_create(parent, &area, btn_string, (win_command_t)BUTTON_ID); wtk_button_size_hint(&area.size, btn_string); if (!btn) { goto error_widget; } win_show(wtk_button_as_child(btn)); return true; /* Error handling to clean up allocations after an error */ error_widget: win_destroy(wtk_basic_frame_as_child(widget_ctx->frame)); error_frame: membag_free(widget_ctx); return false; }
/** * \brief Create a new plot widget. * * Allocates the necessary memory and intializes the window and data for * plot widgets. If there is not enough memory, the function returns * NULL.\n To destroy a plot widget and all its contents, and free its * memory, call \ref win_destroy() on the plot's child reference, given * by \ref wtk_plot_as_child(), similar to: * \code win_destroy(wtk_plot_as_child(my_plot_ptr)); \endcode * * The plotted graph will shift from right to left as new data values are added. * Data values will be overwritten in the ring buffer as they shift out of * the plot window. * The maximum parameter scales the input value to fit the plot dimensions. * * The num_datapoints parameter must not exceed the maximum membag size, * and never over 255. * * * Refer to <gfx/wtk.h> for available configuration options. * * \param parent Pointer to parent win_window struct. * \param area Pointer to win_area struct with position and size of the * plot. Minimum size in both x and y direction is 4 pixels. * \param maximum Maximum value of the plot. * \param num_datapoints Number of datapoints of the plot. * \param draw_color Plot drawing color. * \param background Pointer to background bitmap for frame. NULL for * transparent background. When background is transparent * the parent window will automatically be redrawn * when the basic frame is drawn. * \param option Configuration options for plot. * * \return Pointer to new plot, if memory allocation was successful. */ struct wtk_plot *wtk_plot_create(struct win_window *parent, struct win_area const *area, uint8_t maximum, uint8_t num_datapoints, gfx_color_t draw_color, struct gfx_bitmap *background, uint8_t option) { uint16_t length; /* Do sanity check on parameters. */ Assert(maximum > 0); Assert(area); Assert(parent); Assert(num_datapoints > 1); /* Attributes scratchpad. */ struct win_attributes attr; /* Allocate memory for the control data. */ struct wtk_plot *plot = membag_alloc(sizeof(struct wtk_plot)); if (!plot) { goto outofmem_plot; } /* Allocate memory for the control data. */ plot->plot_buffer = membag_alloc(num_datapoints); if (!plot->plot_buffer) { goto outofmem_plot_buffer; } /* Initialize the plot data. */ plot->maximum = maximum; plot->num_datapoints = num_datapoints; plot->buffer_start = 0; plot->option = option; plot->draw_color = draw_color; plot->background = background; plot->axis_option = 0; plot->axis_spacing_x = 0; plot->axis_offset_x = 0; plot->axis_spacing_y = 0; plot->axis_offset_y = 0; plot->axis_color = 0; plot->axis_zero_color = 0; /* Do sanity check of specified window area parameters * according to the orientation of the plot. */ attr.area = *area; Assert(attr.area.size.x > 3); Assert(attr.area.size.y > 3); /* Makes the plot fit inside the window border. */ length = attr.area.size.x; length -= 2; /* Calculate the spacing between datapoints. */ plot->spacing = length / (num_datapoints - 1); /* Calculate the fixed-point remainder of the above operation. */ plot->spacing_error = (uint8_t)( (((uint16_t)(length - plot->spacing * (num_datapoints - 1))) * WTK_PLOT_SCALE_FACTOR) / ((uint16_t)(num_datapoints - 1))); /* Set up handling information. */ attr.event_handler = wtk_plot_handler; attr.custom = plot; /* Set background for window */ if (background) { attr.background = background; attr.behavior = 0; } else { attr.background = NULL; if (option & WTK_PLOT_DONT_REDRAW_PARENT) { attr.behavior = 0; } else { attr.behavior = WIN_BEHAVIOR_REDRAW_PARENT; } } /* Create a new window for the plot. */ plot->container = win_create(parent, &attr); if (!plot->container) { goto outofmem_container; } return plot; outofmem_container: membag_free(plot->plot_buffer); outofmem_plot_buffer: membag_free(plot); outofmem_plot: return NULL; }