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; }
/** * 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; }
/** * \brief Command event handler for the application's frame. * * This function handles the relevant command events for the application's * frame. In this application, only the exit-button requires handling, and will * cause an immediate exit from the application. * * \note The handler function of the \ref gfx_wtk "Widget toolkit" will destroy * the frame and the widgets when this function returns true. * * \param basic_frame Pointer to the application frame. * \param command_data Data for the command event. */ static bool tank_frame_handler(struct wtk_basic_frame *basic_frame, win_command_t command_data) { switch ((enum tank_command_id)(uintptr_t)command_data) { case CMD_EXIT: // Stop the application timer first. timer_stop(CONFIG_TIMER_ID, &tank_ctx->timer); // Free all memory and return to desktop. memcpy(&sysfont, &tank_ctx->old_sysfont, sizeof(struct font)); membag_free(tank_ctx); tank_ctx = NULL; app_desktop_restart(); return true; default: break; } return false; }
/** 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; }
/** * \brief Slider event handler. * * This is the window event handler for slider widgets. It handles the three * relevant event types sent to a slider's container window, i.e., drawing, * pointer and destroy events.\par * * For POINTER events, the slider value is only updated when the pointer moves, * and not upon press or release events. The handler will grab the pointer and * allow for it to move outside the actual widget window and still control the * slider knob. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_slider_handler(struct win_window *win, enum win_event_type type, void const *data) { struct win_pointer_event const *event; struct win_clip_region const *clip; struct win_command_event command; struct win_area const *area; struct wtk_slider *slider; struct win_point origin; gfx_color_t knob_color; gfx_coord_t position; gfx_coord_t length; uint8_t option; uint8_t value; bool send_command; slider = (struct wtk_slider *)win_get_custom_data(win); // There should not be other windows in this widget. assert(win == slider->container); switch (type) { case WIN_EVENT_DRAW: /* For DRAW events, the data parameter points to the * clipping region. */ clip = (struct win_clip_region const *)data; area = win_get_area(win); option = slider->option; if (slider->state == WTK_SLIDER_NORMAL) { knob_color = WTK_SLIDER_KNOB_COLOR_NORMAL; } else { knob_color = WTK_SLIDER_KNOB_COLOR_MOVING; } // Draw slider frame border. gfx_draw_rect(clip->origin.x, clip->origin.y, area->size.x, area->size.y, WTK_SLIDER_BORDER_COLOR); // Draw slider frame background within frame. gfx_draw_filled_rect(clip->origin.x + 1, clip->origin.y + 1, area->size.x - 2, area->size.y - 2, WTK_SLIDER_BACKGROUND_COLOR); // Draw the slider knob according to configured orientation. if (option & WTK_SLIDER_VERTICAL) { // Draw slider knob border. gfx_draw_rect(clip->origin.x, clip->origin.y + slider->position, area->size.x, WTK_SLIDER_KNOB_WIDTH, WTK_SLIDER_BORDER_COLOR); // Draw slider knob. gfx_draw_filled_rect(clip->origin.x + 1, clip->origin.y + slider->position + 1, area->size.x - 2, WTK_SLIDER_KNOB_WIDTH - 2, knob_color); } else { gfx_draw_rect(clip->origin.x + slider->position, clip->origin.y, WTK_SLIDER_KNOB_WIDTH, area->size.y, WTK_SLIDER_BORDER_COLOR); gfx_draw_filled_rect(clip->origin.x + slider->position + 1, clip->origin.y + 1, WTK_SLIDER_KNOB_WIDTH - 2, area->size.y - 2, knob_color); } /* Always accept DRAW events, as the return value is ignored * anyway for that event type. */ return true; case WIN_EVENT_POINTER: /* For POINTER events, the data parameter points to the pointer * event information. */ event = (struct win_pointer_event const *)data; area = win_get_area(win); option = slider->option; send_command = false; origin = slider->root_pos; switch (event->type) { case WIN_POINTER_PRESS: /* Grab the pointer and redraw a highlighted slider. * Slider value is not updated yet. */ if (slider->state == WTK_SLIDER_NORMAL) { slider->state = WTK_SLIDER_MOVING; win_grab_pointer(win); win_redraw(win); }; #if WTK_SLIDER_PARENT_MOVE_SUPPORT // Update root position. win_translate_win_to_root(win, &slider->root_pos); #endif break; case WIN_POINTER_MOVE: /* The slider is only updated when the pointer moves * and the window was previously pressed. The pointer * does not need to remain within the window to control * the knob as only the position along the slider's * direction of orientation is used. */ if (slider->state == WTK_SLIDER_MOVING) { /* Get the position of the pointer relative to * slider knob's origin, and the length of the * slider itself. */ if (option & WTK_SLIDER_VERTICAL) { position = event->pos.y - origin.y; length = area->size.y; } else { position = event->pos.x - origin.x; length = area->size.x; } // Subtract offsets due to slider knob size. position -= WTK_SLIDER_KNOB_WIDTH / 2; length -= WTK_SLIDER_KNOB_WIDTH; /* Bound the value if pointer is outside window. * Otherwise, compute the slider value from the * knob position. */ if (position < 0) { value = 0; } else if (position > length) { value = slider->maximum; } else { value = wtk_rescale_value(position, length, slider->maximum); } // Update slider only if this is a new value. if (slider->value != value) { slider->value = value; /* Compute knob position from value to * get correct positioning. */ slider->position = wtk_rescale_value(value, slider->maximum, length); if (option & WTK_SLIDER_CMD_MOVE) { send_command = true; } win_redraw(win); } } break; case WIN_POINTER_RELEASE: /* Release the pointer and redraw a normal slider. * The slider's value is not updated. Hence, a pointer * press directly followed by a release will leave the * slider value unchanged. */ if (slider->state == WTK_SLIDER_MOVING) { slider->state = WTK_SLIDER_NORMAL; win_grab_pointer(NULL); win_redraw(win); if (option & WTK_SLIDER_CMD_RELEASE) { send_command = true; } } break; default: break; } // Prepare and send command, if it was flagged. if (send_command) { command.sender = slider->container; command.recipient = slider->container; command.data = slider->command; win_queue_command_event(&command); } /* Accept all POINTER events since all acitivity inside the * widget window is relevant. */ return true; case WIN_EVENT_DESTROY: /* Memory allocated for windows will be automatically destroyed * by the window system. We must destroy other allocations. */ membag_free(slider); /* Always accept DESTROY events, as the return value is ignored * anyway for that event type. */ return true; default: // Reject unknown event types. return false; } }
/** * \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; }
/** * \brief Progress bar event handler. * * This is the window event handler for progress bar widgets. It handles the two * relevant event types sent to a progress bar's container window, i.e., * drawing, and destroy events. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_progress_bar_handler(struct win_window *win, enum win_event_type type, void const *data) { struct win_clip_region const *clip; struct win_area const *area; struct wtk_progress_bar *bar; uint8_t position; uint8_t option; bar = (struct wtk_progress_bar *)win_get_custom_data(win); /* Window receiving the event should be the widget's containing window. */ Assert(win == bar->container); switch (type) { case WIN_EVENT_DRAW: /* For DRAW events, the data parameter points to the clipping * region. The window area parameter is needed because it * contains the size of the widget. */ clip = (struct win_clip_region const *)data; area = win_get_area(win); position = bar->position; option = bar->option; /* Draw a window border. */ gfx_draw_rect(clip->origin.x, clip->origin.y, area->size.x, area->size.y, WTK_PROGRESS_BAR_BORDER_COLOR); /* Draw progress bar interior according to orientation. * An inverted progress bar is drawn in the same way as a * non-inverted, as this option is handled in the functions * for setting the bar's colors and value. */ if (option & WTK_PROGRESS_BAR_VERTICAL) { /* Draw the top section of the bar. */ gfx_draw_filled_rect(clip->origin.x + 1, clip->origin.y + 1, area->size.x - 2, position, bar->fill_color); /* Draw the bottom section of the bar. */ gfx_draw_filled_rect(clip->origin.x + 1, clip->origin.y + 1 + position, area->size.x - 2, area->size.y - 2 - position, bar->background_color); } else { /* Draw the left section of the bar. */ gfx_draw_filled_rect(clip->origin.x + 1, clip->origin.y + 1, bar->position, area->size.y - 2, bar->fill_color); /* Draw the right section of the bar. */ gfx_draw_filled_rect(clip->origin.x + 1 + position, clip->origin.y + 1, area->size.x - 2 - position, area->size.y - 2, bar->background_color); } /* Always accept DRAW events, as the return value is ignored * anyway for that event type. */ return true; case WIN_EVENT_DESTROY: /* Free up all memory allocated by widget. * The window is freed by the window system */ membag_free(bar); return true; default: return false; } }
/** * 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; }
/** * This function is the window event handler for frame widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_frame_handler(struct win_window *win, enum win_event_type type, void const *data) { /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_frame *frame = (struct wtk_frame *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; struct win_area const *area = win_get_area(win); /* Draw frame decorations if this is the container window. */ if (win == frame->container) { /* Draw left border. */ gfx_draw_filled_rect(clip->origin.x, clip->origin.y, WTK_FRAME_LEFTBORDER, area->size.y, WTK_FRAME_BORDER_COLOR); /* Draw right border. */ gfx_draw_filled_rect(clip->origin.x + area->size.x - WTK_FRAME_RIGHTBORDER, clip->origin.y, WTK_FRAME_RIGHTBORDER, area->size.y, WTK_FRAME_BORDER_COLOR); /* Draw top border. */ gfx_draw_filled_rect(clip->origin.x + WTK_FRAME_LEFTBORDER, clip->origin.y, area->size.x - WTK_FRAME_LEFTBORDER - WTK_FRAME_RIGHTBORDER, WTK_FRAME_TOPBORDER, WTK_FRAME_BORDER_COLOR); /* Draw bottom border. */ gfx_draw_filled_rect(clip->origin.x + WTK_FRAME_LEFTBORDER, clip->origin.y + area->size.y - WTK_FRAME_BOTTOMBORDER, area->size.x - WTK_FRAME_LEFTBORDER - WTK_FRAME_RIGHTBORDER, WTK_FRAME_BOTTOMBORDER, WTK_FRAME_BORDER_COLOR); /* Draw title bar background. */ gfx_draw_filled_rect(clip->origin.x + WTK_FRAME_LEFTBORDER, clip->origin.y + WTK_FRAME_TOPBORDER, area->size.x - WTK_FRAME_LEFTBORDER - WTK_FRAME_RIGHTBORDER, WTK_FRAME_TITLEBAR_HEIGHT, WTK_FRAME_TITLEBAR_COLOR); /* Draw caption string. */ gfx_draw_string(frame->caption, clip->origin.x + WTK_FRAME_LEFTBORDER + WTK_FRAME_CAPTION_X, clip->origin.y + WTK_FRAME_TOPBORDER + WTK_FRAME_CAPTION_Y, &sysfont, GFX_COLOR_TRANSPARENT, WTK_FRAME_CAPTION_COLOR); } /* Draw resize handle if this is the resize window. */ else if (win == frame->resize) { gfx_draw_filled_circle(clip->origin.x + area->size.x - 1, clip->origin.y + area->size.y - 1, WTK_FRAME_RESIZE_RADIUS, WTK_FRAME_RESIZE_COLOR, GFX_QUADRANT1); } /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_POINTER: { /* For POINTER events, the data parameter points to the * pointer event information. */ struct win_pointer_event const *event = (struct win_pointer_event const *)data; /* Handle move if this is the container window. */ if (win == frame->container) { switch (event->type) { case WIN_POINTER_PRESS: wtk_handle_frame_press(frame, event); break; case WIN_POINTER_MOVE: wtk_handle_frame_move(frame, event); break; case WIN_POINTER_RELEASE: wtk_handle_frame_release(frame, event); break; default: break; } } /* Handle resize if this is the resize handle. */ else if (win == frame->resize) { switch (event->type) { case WIN_POINTER_PRESS: wtk_handle_resize_press(frame, event); break; case WIN_POINTER_MOVE: wtk_handle_resize_move(frame, event); break; case WIN_POINTER_RELEASE: wtk_handle_resize_release(frame, event); break; default: break; } } /* Accept all POINTER events so that it does not * propagate up the window tree to our parent in case * we did not click anything useful inside the frame. */ return true; } case WIN_EVENT_DESTROY: { /* When the container window is destroyed, also destroy * the rest of the non-window frame allocations. */ if (win == frame->container) { /* Memory allocated for windows will be * automatically destroyed by the window * system. We must destroy other allocations. */ membag_free(frame->caption); membag_free(frame); } /* Always accept DESTROY events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_COMMAND: { /* When commands are received either directly or * propagated from child widgets and windows, send it * to the frame handler. */ if (win == frame->container) { if (frame->frame_handler) { /* If the frame handler returns true, * it wants us to destroy the frame. * This is normally used by CLOSE * buttons. */ bool shouldDestroy = frame->frame_handler(frame, (win_command_t) data); /* It is safe to destroy it here, since * the event handling finished right * after this handler returns, and no * other references to this frame or * its contents will be done. */ if (shouldDestroy) { win_destroy(frame->container); } /* Accept the event if there was a * handler installed. */ return true; } } /* Reject the event if there was no handler, or this * was not the container window at all. */ return false; } default: /* Reject unknown event types. */ return false; } }
/** * \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; }
/** * This function is the window event handler for check box widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_check_box_handler(struct win_window *win, enum win_event_type type, void const *data) { struct win_command_event command; /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_check_box *check_box = (struct wtk_check_box *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* There should not be other windows in this widget. */ Assert(win == check_box->container); /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; /* Draw check box square. */ gfx_draw_rect(clip->origin.x + WTK_CHECKBOX_BOX_X, clip->origin.y + WTK_CHECKBOX_BOX_Y, WTK_CHECKBOX_BOX_SIZE, WTK_CHECKBOX_BOX_SIZE, WTK_CHECKBOX_BOX_COLOR); /* Draw check box square background. */ if (WTK_CHECKBOX_BACKGROUND_COLOR != GFX_COLOR_TRANSPARENT) { gfx_draw_filled_rect(clip->origin.x + WTK_CHECKBOX_BOX_X + 1, clip->origin.y + WTK_CHECKBOX_BOX_Y + 1, WTK_CHECKBOX_BOX_SIZE - 2, WTK_CHECKBOX_BOX_SIZE - 2, WTK_CHECKBOX_BACKGROUND_COLOR); } /* Draw check box select marker if selected. */ if (check_box->selected) { gfx_draw_filled_rect(clip->origin.x + WTK_CHECKBOX_BOX_X + 2, clip->origin.y + WTK_CHECKBOX_BOX_Y + 2, WTK_CHECKBOX_BOX_SIZE - 4, WTK_CHECKBOX_BOX_SIZE - 4, WTK_CHECKBOX_SELECT_COLOR); } /* Draw caption. */ gfx_draw_string(check_box->caption, clip->origin.x + WTK_CHECKBOX_CAPTION_X, clip->origin.y + WTK_CHECKBOX_CAPTION_Y, &sysfont, GFX_COLOR_TRANSPARENT, WTK_CHECKBOX_CAPTION_COLOR); /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_POINTER: { /* There should not be other windows in this widget. */ Assert(win == check_box->container); /* For POINTER events, the data parameter points to the * pointer event information. */ struct win_pointer_event const *event = (struct win_pointer_event const *)data; switch (event->type) { case WIN_POINTER_PRESS: /* When check box pressed, grab pointer and * wait for release inside widget borders. * Other widgets won't get pointer events * before it is released, and the pointer * ungrabbed by us. */ if (check_box->state == WTK_CHECKBOX_NORMAL) { win_grab_pointer(check_box->container); check_box->state = WTK_CHECKBOX_PRESSED; win_redraw(check_box->container); } break; case WIN_POINTER_RELEASE: /* When check box released, take action only if * released inside widget extents. */ if (check_box->state == WTK_CHECKBOX_PRESSED) { bool is_inside; /* Ungrab pointer. */ win_grab_pointer(NULL); check_box->state = WTK_CHECKBOX_NORMAL; win_redraw(check_box->container); /* Check release position. */ is_inside = win_is_inside_window (check_box->container, &(event->pos)); /* Toggle check box if inside. */ if (is_inside) { wtk_check_box_toggle(check_box); /* Send non-zero command. */ if (check_box->command) { command.sender = check_box->container; command.recipient = check_box->container; command.data = check_box->command; win_queue_command_event (&command); } } } break; default: break; } /* Accept all POINTER events since all acitivity inside * the widget extents is relevant to us. */ return true; } case WIN_EVENT_DESTROY: /* There should not be other windows in this widget. */ Assert(win == check_box->container); /* Memory allocated for windows will be automatically destroyed * by the window system. We must destroy other allocations. */ membag_free(check_box->caption); membag_free(check_box); /* Always accept DESTROY events, as the return value is ignored * anyway for that event type. */ return true; default: /* Reject unknown event types. */ return false; } }
/** * \brief Application loader. * * This worker function loads the alarm light bitmaps, then loads the background * image before showing all the widgets and starting the process simulation. * * If memory for bitmaps cannot be allocated, or the background image cannot be * loaded, the application will exit immediately. * * \param task Workqueue task for this worker function. */ static void tank_loader(struct workqueue_task *task) { enum status_code result; hugemem_ptr_t bitmap_data; /* Handle the individual bitmap load states. * * All states, except LOAD_FINISHED, will cause the current workqueue * task to be re-enqueued after loading of the corresponding bitmap has * completed. This task worker will thus go through the states in * sequence. */ switch (tank_ctx->loader_state) { case LOAD_RED_LIGHT: // Enqueue loading of the red alarm light bitmap. bitmap_data = load_file_to_hugemem(BITMAP_RED_LIGHT_FILENAME, task); /* If memory could be allocated for the bitmap, update the * pointer in the bitmap metadata and set next load state. * Otherwise, exit the application load error. */ if (bitmap_data != HUGEMEM_NULL) { tank_bitmap_data[BITMAP_RED_LIGHT] = bitmap_data; tank_ctx->bitmaps[BITMAP_RED_LIGHT].data.hugemem = bitmap_data; tank_ctx->loader_state = LOAD_GREEN_LIGHT; } else { goto exit_load_error; } break; case LOAD_GREEN_LIGHT: bitmap_data = load_file_to_hugemem(BITMAP_GREEN_LIGHT_FILENAME, task); if (bitmap_data != HUGEMEM_NULL) { tank_bitmap_data[BITMAP_GREEN_LIGHT] = bitmap_data; tank_ctx->bitmaps[BITMAP_GREEN_LIGHT].data.hugemem = bitmap_data; tank_ctx->loader_state = LOAD_BACKGROUND; } else { goto exit_load_error; } break; case LOAD_BACKGROUND: // Now load the background image. result = load_file_to_screen(BITMAP_BACKGROUND_FILENAME, BITMAP_BACKGROUND_POSITION_X, BITMAP_BACKGROUND_POSITION_Y, BITMAP_BACKGROUND_SIZE_X, BITMAP_BACKGROUND_SIZE_Y, task); if (result == STATUS_OK) { tank_ctx->loader_state = LOAD_FINISHED; } else { goto exit_load_error; } break; case LOAD_FINISHED: // Now show the application's frame. This will draw all widgets. win_show(wtk_basic_frame_as_child(tank_ctx->frame)); // Set the worker function that updates the application. workqueue_task_set_work_func(task, tank_worker); // Set the timer alarm to trigger application updates. timer_start(CONFIG_TIMER_ID, &tank_ctx->timer); timer_set_alarm(CONFIG_TIMER_ID, &tank_ctx->timer, tank_ctx->timer_delay); break; default: // Should not end up here. unhandled_case(tank_ctx->loader_state); break; } return; // If a load error occurred, go back to the desktop. exit_load_error: win_destroy(wtk_basic_frame_as_child(tank_ctx->frame)); memcpy(&sysfont, &tank_ctx->old_sysfont, sizeof(struct font)); membag_free(tank_ctx); tank_ctx = NULL; app_desktop_restart(); }
/** * This function is the window event handler for label widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_label_handler(struct win_window *win, enum win_event_type type, void const *data) { /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_label *label = (struct wtk_label *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* There should not be other windows in this widget. */ Assert(win == label->container); /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; struct win_area const *area = win_get_area(win); if (label->align_right == false) { /* Draw caption string. */ gfx_draw_string(label->caption, clip->origin.x, clip->origin.y, &sysfont, GFX_COLOR_TRANSPARENT, label->text_color); } else { /* Get string size and draw the caption text right * aligned. */ gfx_coord_t width; gfx_coord_t height; gfx_get_string_bounding_box(label->caption, &sysfont, &width, &height); gfx_draw_string(label->caption, clip->origin.x + area->size.x - width, clip->origin.y, &sysfont, GFX_COLOR_TRANSPARENT, label->text_color); } /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_DESTROY: /* There should not be other windows in this widget. */ Assert(win == label->container); /* Memory allocated for windows will be automatically destroyed * by the window system. We must destroy other allocations. */ membag_free(label->caption); membag_free(label); /* Always accept DESTROY events, as the return value is ignored * anyway for that event type. */ return true; default: /* Reject unknown event types. */ return false; } }
/** * This function is the window event handler for icon button widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_icon_button_handler(struct win_window *win, enum win_event_type type, void const *data) { struct win_command_event command; /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_icon_button *icon_button = (struct wtk_icon_button *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; struct win_area const *area = win_get_area(win); /* There should not be other windows in this widget. */ Assert(win == icon_button->container); /* Draw icon button select marker if selected. */ if (icon_button->group->selected == icon_button) { gfx_draw_rect(clip->origin.x, clip->origin.y, area->size.x, area->size.y, WTK_ICONBUTTON_SELECT_COLOR); } /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_POINTER: { /* There should not be other windows in this widget. */ Assert(win == icon_button->container); /* For POINTER events, the data parameter points to the * pointer event information. */ struct win_pointer_event const *event = (struct win_pointer_event const *)data; switch (event->type) { case WIN_POINTER_PRESS: /* When icon button pressed, grab pointer and * wait for release inside widget borders. * Other widgets won't get pointer events * before it is released, and the pointer * ungrabbed by us. */ if (icon_button->state == WTK_ICONBUTTON_NORMAL) { win_grab_pointer(icon_button->container); icon_button->state = WTK_ICONBUTTON_PRESSED; win_redraw(icon_button->container); } break; case WIN_POINTER_RELEASE: /* When button released, take action only if * released inside widget extents. */ if (icon_button->state == WTK_ICONBUTTON_PRESSED) { bool is_inside; /* Ungrab pointer. */ win_grab_pointer(NULL); icon_button->state = WTK_ICONBUTTON_NORMAL; win_redraw(icon_button->container); /* Check release position. */ is_inside = win_is_inside_window (icon_button-> container, &(event->pos)); /* Select this icon button if inside. */ if (is_inside) { wtk_icon_button_select (icon_button); /* Send non-zero command. */ if (icon_button->command) { command.sender = icon_button-> container; command.recipient = icon_button-> container; command.data = icon_button->command; win_queue_command_event (&command); } } } break; default: break; } /* Accept all POINTER events since all activity inside * the widget extents is relevant to us. */ return true; } case WIN_EVENT_DESTROY: /* There should not be other windows in this widget. */ Assert(win == icon_button->container); /* Destroy icon group as well if we are the last one in the * group. If not, remove ourselves from the group. */ --(icon_button->group->num_references); if (!icon_button->group->num_references) { membag_free(icon_button->group); } else { if (icon_button->group->selected == icon_button) { icon_button->group->selected = NULL; } } membag_free(icon_button); /* Always accept DESTROY events, as the return value is ignored * anyway for that event type. */ return true; default: /* Reject unknown event types. */ 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; }
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; }
void core_free(void *ptr){ membag_free(ptr); }
/** * \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; }
/** * This function is the window event handler for radio button widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_radio_button_handler(struct win_window *win, enum win_event_type type, void const *data) { struct win_command_event command; /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_radio_button *radio_button = (struct wtk_radio_button *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; /* There should not be other windows in this widget. */ Assert(win == radio_button->container); /* Draw radio button circle. */ gfx_draw_circle(clip->origin.x + WTK_RADIOBUTTON_BUTTON_X, clip->origin.y + WTK_RADIOBUTTON_BUTTON_Y, WTK_RADIOBUTTON_RADIUS, WTK_RADIOBUTTON_BUTTON_COLOR, GFX_WHOLE); /* Draw radio button filled circle background. */ if (WTK_RADIOBUTTON_BACKGROUND_COLOR != GFX_COLOR_TRANSPARENT) { gfx_draw_filled_circle(clip->origin.x + WTK_RADIOBUTTON_BUTTON_X, clip->origin.y + WTK_RADIOBUTTON_BUTTON_Y, WTK_RADIOBUTTON_RADIUS - 1, WTK_RADIOBUTTON_BACKGROUND_COLOR, GFX_WHOLE); } /* Draw radio button select marker if selected. */ if (radio_button->group->selected == radio_button) { gfx_draw_filled_circle(clip->origin.x + WTK_RADIOBUTTON_BUTTON_X, clip->origin.y + WTK_RADIOBUTTON_BUTTON_Y, WTK_RADIOBUTTON_RADIUS - 2, WTK_RADIOBUTTON_SELECT_COLOR, GFX_WHOLE); } /* Draw caption. */ gfx_draw_string(radio_button->caption, clip->origin.x + WTK_RADIOBUTTON_CAPTION_X, clip->origin.y + WTK_RADIOBUTTON_CAPTION_Y, &sysfont, GFX_COLOR_TRANSPARENT, WTK_RADIOBUTTON_CAPTION_COLOR); /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_POINTER: { /* There should not be other windows in this widget. */ Assert(win == radio_button->container); /* For POINTER events, the data parameter points to the * pointer event information. */ struct win_pointer_event const *event = (struct win_pointer_event const *)data; switch (event->type) { case WIN_POINTER_PRESS: /* When radio button pressed, grab pointer and * wait for release inside widget borders. * Other widgets won't get pointer events * before it is released, and the pointer * ungrabbed by us. */ if (radio_button->state == WTK_RADIOBUTTON_NORMAL) { win_grab_pointer(radio_button-> container); radio_button->state = WTK_RADIOBUTTON_PRESSED; win_redraw(radio_button->container); } break; case WIN_POINTER_RELEASE: /* When button released, take action only if * released inside widget extents. */ if (radio_button->state == WTK_RADIOBUTTON_PRESSED) { bool is_inside; /* Ungrab pointer. */ win_grab_pointer(NULL); radio_button->state = WTK_RADIOBUTTON_NORMAL; win_redraw(radio_button->container); /* Check release position. */ is_inside = win_is_inside_window (radio_button-> container, &(event->pos)); /* Select this radio button if inside. */ if (is_inside) { wtk_radio_button_select (radio_button); /* Send non-zero command. */ if (radio_button->command) { command.sender = radio_button-> container; command.recipient = radio_button-> container; command.data = radio_button->command; win_queue_command_event (&command); } } } break; default: break; } /* Accept all POINTER events since all acitivity inside * the widget extents is relevant to us. */ return true; } case WIN_EVENT_DESTROY: /* There should not be other windows in this widget. */ Assert(win == radio_button->container); /* Memory allocated for windows will be automatically destroyed * by the window system. We must destroy other allocations. */ membag_free(radio_button->caption); /* Destroy radio group as well if we are the last one in the * group. If not, remove ourselves from the group. */ --(radio_button->group->num_references); if (!radio_button->group->num_references) { membag_free(radio_button->group); } else { if (radio_button->group->selected == radio_button) { radio_button->group->selected = NULL; } } membag_free(radio_button); /* Always accept DESTROY events, as the return value is ignored * anyway for that event type. */ return true; default: /* Reject unknown event types. */ 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; }
/** * \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; }
/** * 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 Application task worker * * Waits for the touch release events generated after the user has touched a * calibration circle drawn on screen, then stores the calibration data and * draws the circle for the next calibration point. * * Three such calibration points are stored before the calibration matrix for * the touch driver is computed and assigned to it. * * \sa touch_driver_group * * \note If the raw samples of a calibration point do not differ by at least * \ref CAL_TRESHOLD from the previous calibration point, it is interpreted as * an unintended touch and ignored. * * \param task Workqueue task for this worker function */ static void touch_calibrate_task_handler(struct workqueue_task *task) { int16_t dx; int16_t dy; struct touch_calibrate_context *cal_ctx; cal_ctx = container_of(task, struct touch_calibrate_context, task); switch (cal_ctx->state) { case 0: /* Fall through */ case 1: case 2: // Schedule task to run once more workqueue_add_task(&main_workqueue, &cal_ctx->task); // Run until touch is released if (cal_ctx->event.type != TOUCH_RELEASE) break; // Store calibration values cal_ctx->event.type = TOUCH_NO_EVENT; cal_ctx->cal_points[cal_ctx->state].raw_x = cal_ctx->event.point.raw_x; cal_ctx->cal_points[cal_ctx->state].raw_y = cal_ctx->event.point.raw_y; dx = cal_ctx->cal_points[cal_ctx->state - 1].raw_x - cal_ctx->cal_points[cal_ctx->state].raw_x; dy = cal_ctx->cal_points[cal_ctx->state - 1].raw_y - cal_ctx->cal_points[cal_ctx->state].raw_y; dx = abs(dx); dy = abs(dy); // If point is too close to the last one, wait for another touch if ((dx < CAL_TRESHOLD) && (dy < CAL_TRESHOLD)) break; // Clear old circle before moving on. gfx_draw_circle(cal_ctx->cal_points[cal_ctx->state].panel_x, cal_ctx->cal_points[cal_ctx->state].panel_y, CAL_RADIUS, CAL_BG_COLOR, GFX_WHOLE); // Move to next point cal_ctx->state++; /* Skip drawing last circles if we're done. */ if (cal_ctx->state >= 3) break; // Draw next circle. gfx_draw_circle(cal_ctx->cal_points[cal_ctx->state].panel_x, cal_ctx->cal_points[cal_ctx->state].panel_y, CAL_RADIUS, CAL_FG_COLOR, GFX_WHOLE); break; case 3: // Calibration completed // Clear circle before moving on. gfx_draw_circle(cal_ctx->cal_points[2].panel_x, cal_ctx->cal_points[2].panel_y, CAL_RADIUS, CAL_BG_COLOR, GFX_WHOLE); // Compute and assign the calibration matrix to the driver. touch_compute_calibration_matrix(cal_ctx->cal_points, &cal_ctx->cal_matrix); touch_set_calibration_matrix(&cal_ctx->cal_matrix); // Restore handler touch_set_event_handler(cal_ctx->old_handler); // Can now free memory membag_free(calibrate_context); // Schedule task if available if (calibrate_context->completed_task) { workqueue_add_task(&main_workqueue, calibrate_context->completed_task); } break; } }
/** * This function is the window event handler for button widgets. * It handles all events sent to the windows composing the widget. * * \param win Window receiving the event. * \param type The event type. * \param data Custom data, depending on event type. * * \return True if the event was recognized and accepted. */ static bool wtk_button_handler(struct win_window *win, enum win_event_type type, void const *data) { /* Custom data for windows of a widget points back to the widget itself. */ struct wtk_button *button = (struct wtk_button *)win_get_custom_data(win); switch (type) { case WIN_EVENT_DRAW: { /* For DRAW events, the data parameter points to the * clipping region. */ struct win_clip_region const *clip = (struct win_clip_region const *)data; struct win_area const *area = win_get_area(win); /* Preare background and caption colors depending on state of * button. If pressed/highlighted, the colors are inverted. */ gfx_color_t background_color; gfx_color_t caption_color; /* There should not be other windows in this widget. */ Assert(win == button->container); switch (button->state) { case WTK_BUTTON_NORMAL: background_color = WTK_BUTTON_BACKGROUND_COLOR; caption_color = WTK_BUTTON_CAPTION_COLOR; break; case WTK_BUTTON_PRESSED: background_color = WTK_BUTTON_CAPTION_COLOR; caption_color = WTK_BUTTON_BACKGROUND_COLOR; break; default: Assert(false); background_color = WTK_BUTTON_BACKGROUND_COLOR; caption_color = WTK_BUTTON_CAPTION_COLOR; } /* Draw background. */ gfx_draw_filled_rect(clip->origin.x, clip->origin.y, area->size.x, area->size.y, background_color); /* Draw border. */ gfx_draw_rect(clip->origin.x, clip->origin.y, area->size.x, area->size.y, WTK_BUTTON_BORDER_COLOR); /* Draw caption. */ gfx_draw_string_aligned(button->caption, clip->origin.x + (area->size.x / 2), clip->origin.y + (area->size.y / 2), &sysfont, GFX_COLOR_TRANSPARENT, caption_color, TEXT_POS_CENTER, TEXT_ALIGN_CENTER); /* Always accept DRAW events, as the return value is * ignored anyway for that event type. */ return true; } case WIN_EVENT_POINTER: { /* There should not be other windows in this widget. */ Assert(win == button->container); /* For POINTER events, the data parameter points to the * pointer event information. */ struct win_pointer_event const *event = (struct win_pointer_event const *)data; switch (event->type) { case WIN_POINTER_PRESS: /* When button pressed, grab pointer and wait * for release inside button borders. Other * widgets won't get pointer events before it * is released, and the pointer ungrabbed by * us. */ if (button->state == WTK_BUTTON_NORMAL) { win_grab_pointer(button->container); button->state = WTK_BUTTON_PRESSED; win_redraw(button->container); } break; case WIN_POINTER_RELEASE: /* When button released, take action only if * released inside widget extents. */ if (button->state == WTK_BUTTON_PRESSED) { /* Ungrab pointer. */ win_grab_pointer(NULL); button->state = WTK_BUTTON_NORMAL; win_redraw(button->container); /* Check release position. */ bool isInside = win_is_inside_window (button->container, &(event->pos)); /* Send command event if inside. */ if (isInside) { struct win_command_event command; command.sender = button-> container; command.recipient = button-> container; command.data = button-> command; win_queue_command_event (&command); } } break; default: break; } /* Accept all POINTER events since all acitivity inside * the widget extents is relevant to us. */ return true; } case WIN_EVENT_DESTROY: { /* There should not be other windows in this widget. */ Assert(win == button->container); /* Memory allocated for windows will be automatically * destroyed by the window system. We must destroy * other allocations. */ membag_free(button->caption); membag_free(button); /* Always accept DESTROY events, as the return value is * ignored anyway for that event type. */ return true; } default: /* Reject unknown event types. */ return false; } }