Esempio n. 1
0
/**
 * This function stops an ongoing drag operation. Do not call this unless
 * dragging has been started with wtk_start_drag() first. This function erases
 * the drag handles and frees any allocated memory.
 *
 * \param last_pos Last position, as for wtk_continue_drag().
 */
static void wtk_stop_drag(struct win_point const *last_pos)
{
	/* Don't do any graphics if we did not get memory when drag started. */
	if (!wtk_drag_origin_pixmap || !wtk_drag_target_pixmap) {
		return;
	}

	/* 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);

	/* Restore screen underneath drag origin symbol. */
	gfx_put_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);

	/* Restore screen underneath drag target symbol. */
	gfx_put_pixmap(wtk_drag_target_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0,
			last_pos->x - WTK_DRAG_HANDLE_RADIUS,
			last_pos->y - WTK_DRAG_HANDLE_RADIUS,
			WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE);

	/* Free memory when not dragging. */
	membag_free(wtk_drag_origin_pixmap);
	membag_free(wtk_drag_target_pixmap);
}
Esempio n. 2
0
/**
 * This function updated the drag target handle graphics. Call this function
 * from the MOVE event handler of the dragging widget. This function needs
 * both the current position and the last used position. The last position will
 * be either the position handed to wtk_start_drag() or the "pos" parameter of
 * the last call to wtk_continue_drag(). The pointer event struct will keep this
 * value for you. No need to store it yourself.
 *
 * \param last_pos Last position.
 * \param pos Current position.
 */
static void wtk_continue_drag(struct win_point const *last_pos,
		struct win_point const *pos)
{
	/* Don't do any graphics if we did not get memory when drag started. */
	if (!wtk_drag_origin_pixmap || !wtk_drag_target_pixmap) {
		return;
	}

	/* 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);

	/* Restore screen underneath drag target symbol. */
	gfx_put_pixmap(wtk_drag_target_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0,
			last_pos->x - WTK_DRAG_HANDLE_RADIUS,
			last_pos->y - WTK_DRAG_HANDLE_RADIUS,
			WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE);

	/* Store screen underneath and draw new 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);
}
Esempio n. 3
0
/**
 * 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;
}
void gfx_ili9325_init(void)
{
	struct ili9325_opt_t g_ili9325_display_opt;

	/* initialize globals */
	gfx_width = ILI9325_LCD_WIDTH;
	gfx_height = ILI9325_LCD_HEIGHT;

	/* Enable peripheral clock */
	pmc_enable_periph_clk(ID_SMC);

	/* Configure SMC interface for Lcd */
	smc_set_setup_timing(SMC,ILI9325_LCD_CS,SMC_SETUP_NWE_SETUP(2)
			| SMC_SETUP_NCS_WR_SETUP(2)
			| SMC_SETUP_NRD_SETUP(2)
			| SMC_SETUP_NCS_RD_SETUP(2));
	smc_set_pulse_timing(SMC, ILI9325_LCD_CS , SMC_PULSE_NWE_PULSE(4)
			| SMC_PULSE_NCS_WR_PULSE(4)
			| SMC_PULSE_NRD_PULSE(10)
			| SMC_PULSE_NCS_RD_PULSE(10));
	smc_set_cycle_timing(SMC, ILI9325_LCD_CS, SMC_CYCLE_NWE_CYCLE(10)
			| SMC_CYCLE_NRD_CYCLE(22));
#if !defined(SAM4S)
	smc_set_mode(SMC, ILI9325_LCD_CS, SMC_MODE_READ_MODE
			| SMC_MODE_WRITE_MODE
			| SMC_MODE_DBW_8_BIT);
#else
	smc_set_mode(SMC, ILI9325_LCD_CS, SMC_MODE_READ_MODE
			| SMC_MODE_WRITE_MODE);
#endif

	/* Initialize display parameter */
	g_ili9325_display_opt.ul_width= ILI9325_LCD_WIDTH;
	g_ili9325_display_opt.ul_height = ILI9325_LCD_HEIGHT;
	g_ili9325_display_opt.foreground_color= COLOR_BLACK;
	g_ili9325_display_opt.background_color = COLOR_WHITE;

	/* Switch off backlight */
	aat31xx_disable_backlight();

	/* Initialize LCD */
	ili9325_init(&g_ili9325_display_opt);
	ili9325_display_on();
	/* Set backlight level */
	aat31xx_set_backlight(AAT31XX_AVG_BACKLIGHT_LEVEL);

	/* Set clipping area to whole screen initially */
	gfx_set_clipping(0, 0, gfx_width, gfx_height);

	gfx_draw_filled_rect(0, 0, gfx_width, gfx_height,
			GFX_COLOR(0xFF, 0xFF, 0xFF));
}
void gfx_ili9341_init(void)
{
	/* initialize globals */
	gfx_width = ILI9341_DEFAULT_WIDTH;
	gfx_height = ILI9341_DEFAULT_HEIGHT;

	ili9341_init();
	ili9341_backlight_on();

	/* Set clipping area to whole screen initially */
	gfx_set_clipping(0, 0, gfx_width, gfx_height);

	gfx_draw_filled_rect(0, 0, gfx_width, gfx_height,
			GFX_COLOR_BLACK);
}
/**
 * \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);
}
Esempio n. 7
0
void gfx_ili9488_set_orientation(uint8_t flags)
{
	ili9488_set_orientation(flags);

	/* Switch width and height if XY is switched. */
	if ((flags & GFX_SWITCH_XY) != 0x00) {
		gfx_width = ILI9488_SWITCH_XY_WIDTH;
		gfx_height = ILI9488_SWITCH_XY_HEIGHT;
	} else {
		gfx_width = ILI9488_LCD_WIDTH;
		gfx_height = ILI9488_LCD_HEIGHT;
	}

#ifdef CONF_GFX_USE_CLIPPING
	/* Reset clipping region. */
	gfx_set_clipping(0, 0, gfx_width - 1, gfx_height - 1);
#endif
}
void gfx_hx8347a_set_orientation(uint8_t flags)
{
	hx8347a_set_orientation(flags);

	/* Switch width and height if XY is switched. */
	if ((flags & GFX_SWITCH_XY) != 0x00) {
		gfx_width = HX8347A_SWITCH_XY_WIDTH;
		gfx_height = HX8347A_SWITCH_XY_HEIGHT;
	} else {
		gfx_width = HX8347A_DEFAULT_WIDTH;
		gfx_height = HX8347A_DEFAULT_HEIGHT;
	}

#ifdef CONF_GFX_USE_CLIPPING
	/* Reset clipping region. */
	gfx_set_clipping(0, 0, gfx_width, gfx_height);
#endif
}
Esempio n. 9
0
/**
 * \brief Show an out of memory error on the display
 *
 * Shows a full screen error when called, signaling that the system
 * ran out of memory when initializing a WTK application.
 */
static void show_out_of_memory_error(void)
{
	const char memory_string[] = "OUT OF MEMORY";
	gfx_coord_t disp_width, disp_height;

	/* Get the display width and height */
	disp_width  = gfx_get_width();
	disp_height = gfx_get_height();

	/* Blank display */
	gfx_set_clipping(0, 0, disp_width, disp_height);
	gfx_draw_filled_rect(0, 0, disp_width, disp_height, GFX_COLOR_BLACK);

	/* Show centered out of memory error text */
	gfx_draw_string_aligned(memory_string,
		disp_width / 2, disp_height / 2,
		&sysfont,
		GFX_COLOR_TRANSPARENT, GFX_COLOR_RED,
		TEXT_POS_CENTER, TEXT_ALIGN_CENTER);
}
Esempio n. 10
0
void gfx_ili9488_init(void)
{
	struct ili9488_opt_t g_ili9488_display_opt;

	/* initialize globals */
	gfx_width = ILI9488_LCD_WIDTH;
	gfx_height = ILI9488_LCD_HEIGHT;

	/* Initialize display parameter */
	g_ili9488_display_opt.ul_width= ILI9488_LCD_WIDTH;
	g_ili9488_display_opt.ul_height = ILI9488_LCD_HEIGHT;
	g_ili9488_display_opt.foreground_color= COLOR_BLACK;
	g_ili9488_display_opt.background_color = COLOR_WHITE;

	ili9488_init(&g_ili9488_display_opt);
	ili9488_display_on();

	/* Set clipping area to whole screen initially */
	gfx_set_clipping(0, 0, gfx_width, gfx_height);

	gfx_draw_filled_rect(0, 0, gfx_width, gfx_height,
			GFX_COLOR_BLACK);
}
/**
 * \brief Load file data directly to screen worker
 *
 * This worker function puts the data fetched from the file system directly to
 * the screen.
 *
 * \param task Pointer to the current work queue task
 */
static void load_to_screen_worker(struct workqueue_task *task)
{
	struct file_loader      *floader = &the_file_loader;
	enum status_code        result;

	gfx_set_clipping(0, 0, gfx_get_width(), gfx_get_height());

	gfx_put_pixmap((gfx_color_t *)floader->buffer,
			floader->load_size,
			0,
			0,
			floader->current_x + floader->offset_x,
			floader->current_y + floader->offset_y,
			floader->load_size,
			1);

	floader->current_x += floader->load_size;
	if (floader->current_x >= floader->width) {
		floader->current_y++;
		floader->current_x = 0;
	}

	floader->load_size = min_u((floader->width - floader->current_x),
			MAX_LOAD_PIXELS);

	result = tsfs_read(&myfs, &floader->file, &floader->buffer,
			floader->load_size * sizeof(gfx_color_t),
			&floader->task);

	// If file we are done, run the image done task
	if ((result != STATUS_OK) || (floader->current_y > floader->height)) {
		floader->busy = false;

		if (floader->done_task)
			workqueue_add_task(&main_workqueue, floader->done_task);
	}
}
/**
 * \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 Application worker function.
 *
 * This task worker updates the parameters of the simulated process and the
 * display unless the application context has been cleared, in which case the
 * function returns immediately.
 *
 * Refer to the detailed description of \ref apps_tank_group for information on
 * the simulated process.
 *
 * If the tank level reaches 0, the indicator for demand will change color to
 * indicate that the supply is insufficient. If, on the other hand, it reaches
 * \ref VALUE_LEVEL_MAXIMUM, the alarm light changes color to indicate that the
 * supply is too great.
 *
 * \note The task for this worker function is enqueued by the timer callback
 * function.
 *
 * \param task Workqueue task for this worker function.
 */
static void tank_worker(struct workqueue_task *task)
{
	struct gfx_bitmap   *alarm_bitmap = NULL;
	bool                alarm_update = false;
	int32_t             rand;
	uint8_t             supply;
	uint16_t            demand;
	int16_t             flow;
	int16_t             level;

	// Quit immediately if application context has been cleared.
	if (!tank_ctx) {
		return;
	}

	// Get current values of the process parameters.
	level = wtk_progress_bar_get_value(tank_ctx->level);
	supply = wtk_slider_get_value(tank_ctx->supply);
	demand = wtk_progress_bar_get_value(tank_ctx->demand);
	rand = tank_ctx->rand;

	// Update the random variable if enough ticks have passed.
	if (--(tank_ctx->rand_ticks) == 0) {
		tank_ctx->rand_ticks = TICKS_PER_RANDOM_UPDATE;

		// Flip some LSBs to help avoid a stuck process.
		rand ^= demand & 0x03;

		// Compute new random value and store it for next iteration.
		rand = tank_logistic_map(rand);
		tank_ctx->rand = rand;
	}

	// Now, compute the new demand from a weighted scheme.
	demand = rand + (2 * demand) + level;
	demand /= 4;
	demand = min_u(demand, VALUE_DEMAND_MAXIMUM);

	/* Compute the total flow and scale it down for a smoother
	 * simulation.
	 */
	flow = supply;
	flow -= demand;
	flow /= 4;

	// Compute new level for the tank.
	level += flow;

	/* Update the demand indicator. Change its color if the demand
	 * exceeds the supply and available water in the tank.
	 */
	if (level <= 0) {
		if (!tank_ctx->flow_alarm) {
			tank_ctx->flow_alarm = true;
			wtk_progress_bar_set_colors(tank_ctx->demand,
					COLOR_DEMAND_CRITICAL,
					COLOR_DEMAND_BACKGROUND);
		}
		level = 0;
	} else {
		if (tank_ctx->flow_alarm) {
			tank_ctx->flow_alarm = false;
			wtk_progress_bar_set_colors(tank_ctx->demand,
					COLOR_DEMAND_NORMAL,
					COLOR_DEMAND_BACKGROUND);
		}
	}
	wtk_progress_bar_set_value(tank_ctx->demand, demand);

	/* Update the tank level indicator.
	 * The level of the tank cannot exceed the defined maximum,
	 * and its alarm light must be updated whenever this level
	 * is crossed.
	 */
	if (level >= VALUE_LEVEL_MAXIMUM) {
		if (!tank_ctx->level_alarm) {
			tank_ctx->level_alarm = true;
			alarm_update = true;
			alarm_bitmap = &tank_ctx->bitmaps[BITMAP_RED_LIGHT];
		}
		level = VALUE_LEVEL_MAXIMUM;
	} else {
		if (tank_ctx->level_alarm) {
			tank_ctx->level_alarm = false;
			alarm_update = true;
			alarm_bitmap = &tank_ctx->bitmaps[BITMAP_GREEN_LIGHT];
		}
	}
	wtk_progress_bar_set_value(tank_ctx->level, level);

	/* If a level alarm update occurred, set up clipping area and draw
	 * the new alarm light bitmap.
	 */
	if (alarm_update) {
#ifdef CONFIG_GFX_USE_CLIPPING
		gfx_set_clipping(BITMAP_LIGHT_POSITION_X,
				BITMAP_LIGHT_POSITION_Y,
				BITMAP_LIGHT_POSITION_X
					+ BITMAP_LIGHT_SIZE_X - 1,
				BITMAP_LIGHT_POSITION_Y
					+ BITMAP_LIGHT_SIZE_Y - 1
				);
#endif /* CONFIG_GFX_USE_CLIPPING */
		gfx_draw_bitmap(alarm_bitmap,
				BITMAP_LIGHT_POSITION_X,
				BITMAP_LIGHT_POSITION_Y);
	}
}
Esempio n. 14
0
/**
 * \brief Handle maXTouch messages
 *
 * This function handles the maXTouch messages, triggering the drawing of
 * squares around new or moved touches, and removing the squares around
 * released touches.
 *
 * \param device Pointer to mxt_device struct
 */
static void mxt_handler(struct mxt_device *device)
{
	struct mxt_touch_event touch_event;
	gfx_coord_t screen_touch_x, screen_touch_y, screen_touch_size;

	do {
		/* Get the first touch event in queue */
		if (mxt_read_touch_event(device, &touch_event) != STATUS_OK) {
			continue;
		}

		/* Discard non press, movement or release events */
		if (!(touch_event.status &
				(MXT_PRESS_EVENT | MXT_MOVE_EVENT | MXT_RELEASE_EVENT))) {
			continue;
		}

		/* Rescale from 4k touch X-coordinate to the display width */
		screen_touch_x = ((uint32_t)(4096 - touch_event.x) * gfx_get_width()) / 4096;

		/* Rescale from 4k touch Y-coordinate to the display height */
		screen_touch_y = ((uint32_t)(4096 - touch_event.y) * gfx_get_height()) / 4096;

		/* Scale the touch size to a value suitable for the target display */
		screen_touch_size = touch_event.size;

		/* Check if the touch is within the drawing area */
		if (screen_touch_y < (gfx_get_height() - PALLET_HEIGHT)) {
			/* Obtain the color to draw from the pallet colors */
			gfx_color_t draw_color = pallet_colors[selected_pallet_color];

			/* Color pallet index 0 selects multi-color mode */
			if (selected_pallet_color == 0) {
				draw_color = get_next_rainbow_color();
			}

			/* Set clipping area */
			gfx_set_clipping(0, 0, gfx_get_width(),
					(gfx_get_height() - PALLET_HEIGHT - 2));

			/* Draw touch point on the screen in the selected color */
			gfx_draw_filled_circle(screen_touch_x, screen_touch_y,
					screen_touch_size, draw_color, GFX_WHOLE);

			/* Reset clipping area */
			gfx_set_clipping(0, 0, gfx_get_width(), gfx_get_height());

		} else if (touch_event.status & MXT_PRESS_EVENT) {
			/* Calculate the pressed pallet entry */
			uint8_t pallete_index = (screen_touch_x / PALLET_COLOR_WIDTH);

			/* The last entry in the pallet clears the screen */
			if (pallete_index == (NUM_PALLET_COLORS - 1)) {
				/* Indicate display is being cleared */
				draw_pallet_labels(true);

				/* Clear the display */
				gfx_draw_filled_rect(0, 0, gfx_get_width(),
						(gfx_get_height() - PALLET_HEIGHT - 1),
						GFX_COLOR_BLACK);

				/* Indicate display has been cleared */
				draw_pallet_labels(false);
			} else {
				/* Change color selection based on the color chosen */
				selected_pallet_color = pallete_index;

				/* Draw new selection box around chosen color */
				update_pallet_selection();
			}
		}

	} while (mxt_is_message_pending(device));
}