/**
 * \brief Graph task
 *
 * This task runs in the background to draw a pseudo-random graph to a dedicated
 * display buffer. If the user selects a different screen than the graph, it
 * will continue to update even though it is not visible until the graph screen
 * is selected again.
 *
 * \param params Parameters for the task. (Not used.)
 */
static void graph_task(void *params)
{
	gfx_coord_t x, y, old_y;
	uint8_t current_value;
	EventBits_t event_bits;
	const TickType_t ticks_to_wait = 10 / portTICK_PERIOD_MS;

	x = 0;
	current_value = graph_noise;

	for(;;) {
		/* Wait a maximum of 10ms for either bit 0 or bit 1 to be set within
		    the event group.  Not clear the bits before exiting. */
		event_bits = xEventGroupWaitBits(
				event_group,   /* The event group being tested. */
				EVENT_DISPLAY_INIT | EVENT_DISPLAY_GRAPH, /* The bits within the event group to wait for. */
				pdFALSE,        /* Bit should not be cleared before returning. */
				pdFALSE,       /* Don't wait for both bits, either bit will do. */
				ticks_to_wait);/* Wait a maximum of 10ms for either bit to be set. */

		if((event_bits & EVENT_DISPLAY_INIT) ||
				(event_bits & EVENT_DISPLAY_GRAPH)) {
			oled1_set_led_state(&oled1, OLED1_LED1_ID, true);

			// Compute new noise sample and value of current graph sample
			graph_noise = (graph_noise * 173) + 1;
			current_value = ((uint16_t)graph_noise + current_value) / 2;

			xSemaphoreTake(display_mutex, portMAX_DELAY);

			// Scale graph value so it fits within the canvas
			y = CANVAS_GRAPH_Y_OFFSET
					+ ((uint16_t)CANVAS_HEIGHT * current_value) / 256;

			// Clear previous graph point..
			gfx_mono_draw_vertical_line(x, CANVAS_GRAPH_Y_OFFSET, CANVAS_HEIGHT,
					GFX_PIXEL_CLR);

			// ..and draw a continuous graph using lines
			if (x == 0) {
				gfx_mono_draw_pixel(x, y, GFX_PIXEL_SET);
			} else {
				gfx_mono_draw_line(x - 1, old_y, x, y, GFX_PIXEL_SET);
			}

			xSemaphoreGive(display_mutex);

			old_y = y;
			if (++x >= CANVAS_WIDTH) {
				x = 0;
			}

			oled1_set_led_state(&oled1, OLED1_LED1_ID, false);
		}

		vTaskDelay(GRAPH_TASK_DELAY);
	}
}
Exemple #2
0
int main(void){

	struct gfx_mono_bitmap smiley;
	struct gfx_mono_bitmap smiley_flash;

	board_init();
	sysclk_init();

	/* Initialize GFX lib. Will configure the display controller and
	 * create a framebuffer in RAM if the controller lack two-way communication
	 */
	gfx_mono_init();

	// Setup bitmap struct for bitmap stored in RAM
	smiley.type = GFX_MONO_BITMAP_RAM;
	smiley.width = 8;
	smiley.height = 16;
	smiley.data.pixmap = smiley_data;

	// Setup bitmap for bitmap stored in FLASH
	smiley_flash.type = GFX_MONO_BITMAP_PROGMEM;
	smiley_flash.width = 8;
	smiley_flash.height = 16;
	smiley_flash.data.progmem = flash_bitmap;

	// Output bitmaps to display
	gfx_mono_put_bitmap(&smiley, 50, 0);
	gfx_mono_put_bitmap(&smiley_flash, 0, 0);

	//Draw  horizontal an vertical lines with length 128 and 32 pixels
	gfx_mono_draw_vertical_line(1, 0, 32, GFX_PIXEL_SET);
	gfx_mono_draw_horizontal_line(0, 2, 128, GFX_PIXEL_SET);

	// Draw a line from the top-left corner to the bottom right corner
	gfx_mono_draw_line(0, 0, 127, 31, GFX_PIXEL_SET);

	// Draw a rectangle with upper left corner at x=20,y=10 - width=height=10px
	gfx_mono_draw_rect(20, 10, 10, 10,GFX_PIXEL_SET);

	// Draw a 10x10 filled rectangle at x=10,y=10
	gfx_mono_draw_filled_rect(10, 10, 10, 10, GFX_PIXEL_SET);

	// Draw a whole circle at x=50,y=16 with radios=8 and all octants drawn
	gfx_mono_draw_circle(50, 16, 8, GFX_PIXEL_SET,GFX_WHOLE);

	// Draw a filled circle with all quadrant drawn
	gfx_mono_draw_filled_circle(80, 16, 10, GFX_PIXEL_SET, GFX_WHOLE);

	while(true) {
	// This while left intentionally blank to halt execution.
	}
}
Exemple #3
0
/**
 * \brief Graph task
 *
 * This task runs in the background to draw a pseudo-random graph to a dedicated
 * display buffer. If the user selects a different screen than the graph, it
 * will continue to update even though it is not visible until the graph screen
 * is selected again.
 *
 * \param params Parameters for the task. (Not used.)
 */
static void graph_task(void *params)
{
	gfx_coord_t x, y, old_y;
	uint8_t current_value;

	x = 0;
	current_value = graph_noise;

	for(;;) {
		oled1_set_led_state(&oled1, OLED1_LED1_ID, true);

		// Compute new noise sample and value of current graph sample
		graph_noise = (graph_noise * 173) + 1;
		current_value = ((uint16_t)graph_noise + current_value) / 2;

		xSemaphoreTake(display_mutex, portMAX_DELAY);

		// Scale graph value so it fits within the canvas
		y = CANVAS_GRAPH_Y_OFFSET
				+ ((uint16_t)CANVAS_HEIGHT * current_value) / 256;

		// Clear previous graph point..
		gfx_mono_draw_vertical_line(x, CANVAS_GRAPH_Y_OFFSET, CANVAS_HEIGHT,
				GFX_PIXEL_CLR);

		// ..and draw a continuous graph using lines
		if (x == 0) {
			gfx_mono_draw_pixel(x, y, GFX_PIXEL_SET);
		} else {
			gfx_mono_draw_line(x - 1, old_y, x, y, GFX_PIXEL_SET);
		}

		xSemaphoreGive(display_mutex);

		old_y = y;
		if (++x >= CANVAS_WIDTH) {
			x = 0;
		}

		oled1_set_led_state(&oled1, OLED1_LED1_ID, false);

		vTaskDelay(GRAPH_TASK_DELAY);
	}
}
Exemple #4
0
/**
 * \internal
 * \brief Test drawing a vertical line
 *
 * This test draws a vertical line and checks that this is done.
 *
 * \param test Current test case.
 */
static void run_draw_vertical_line_test(const struct test_case *test)
{
	uint8_t actual[GFX_MONO_LCD_WIDTH];
	uint8_t expected_page1[GFX_MONO_LCD_WIDTH];
	uint8_t expected_page2[GFX_MONO_LCD_WIDTH];
	uint8_t expected_empty[GFX_MONO_LCD_WIDTH];
	uint8_t page;

	// Clear entire display
	gfx_mono_draw_filled_rect(0, 0, GFX_MONO_LCD_WIDTH, GFX_MONO_LCD_HEIGHT,
			GFX_PIXEL_CLR);

	// Fill page buffer holding the top of the line
	set_buffer(expected_page1, 0x00);
	expected_page1[4] = 0xFC;

	// Fill page buffer holding the bottom of the line
	set_buffer(expected_page2, 0x00);
	expected_page2[4] = 0x1F;

	// Fill empty page buffer
	set_buffer(expected_empty, 0x00);

	// Draw a vertical line at position 4, 2 with length 11
	gfx_mono_draw_vertical_line(4, 2, 11, GFX_PIXEL_SET);

	// Get all pages from display and check that the line is drawn
	for (page = 0; page < GFX_MONO_LCD_PAGES; page++) {
		gfx_mono_get_page(actual, page, 0, GFX_MONO_LCD_WIDTH);
		if (page == 0) {
			test_assert_true(test, is_page_correct(actual, expected_page1),
					"Page %d with line not matching expected page",
					page);
		} else if (page == 1) {
			test_assert_true(test, is_page_correct(actual, expected_page2),
					"Page %d with line not matching expected page",
					page);
		} else {
			test_assert_true(test, is_page_correct(actual, expected_empty),
					"Empty page %d not matching expected page", page);
		}
	}
}
Exemple #5
0
/**
 * \brief Main demo task
 *
 * This task keeps track of which screen the user has selected, which tasks
 * to resume/suspend to draw the selected screen, and also draws the menu bar.
 *
 * The menu bar shows which screens the user can select by clicking the
 * corresponding buttons on the OLED1 Xplained Pro:
 * - \ref graph_task() "graph" (selected at start-up)
 * - \ref terminal_task() "term."
 * - \ref about_task() "about"
 *
 * \param params Parameters for the task. (Not used.)
 */
static void main_task(void *params)
{
	bool graph_buffer_initialized = false;
	bool selection_changed = true;
	bool select_graph_buffer;
	enum menu_items current_selection = MENU_ITEM_GRAPH;
	gfx_coord_t x, y, display_y_offset;
	xTaskHandle temp_task_handle = NULL;

	for(;;) {
		// Show that task is executing
		oled1_set_led_state(&oled1, OLED1_LED3_ID, true);

		// Check buttons to see if user changed the selection
		if (oled1_get_button_state(&oled1, OLED1_BUTTON1_ID)
					&& (current_selection != MENU_ITEM_GRAPH)) {
			current_selection = MENU_ITEM_GRAPH;
			selection_changed = true;
		} else if (oled1_get_button_state(&oled1, OLED1_BUTTON2_ID)
					&& (current_selection != MENU_ITEM_TERMINAL)) {
			current_selection = MENU_ITEM_TERMINAL;
			selection_changed = true;
		} else if (oled1_get_button_state(&oled1, OLED1_BUTTON3_ID)
					&& (current_selection != MENU_ITEM_ABOUT)) {
			current_selection = MENU_ITEM_ABOUT;
			selection_changed = true;
		}

		// If selection changed, handle the selection
		if (selection_changed) {
			// Wait for and take the display semaphore before doing any changes.
			xSemaphoreTake(display_mutex, portMAX_DELAY);

			// We can now safely suspend the previously resumed task
			if (temp_task_handle) {
				vTaskSuspend(temp_task_handle);
				temp_task_handle = NULL;
			}

			// Select the new drawing task and corresponding display buffer
			switch (current_selection) {
			case MENU_ITEM_GRAPH:
				// Graph task runs continuously, no need to set task handle
				select_graph_buffer = true;
				break;

			case MENU_ITEM_TERMINAL:
				temp_task_handle = terminal_task_handle;
				select_graph_buffer = false;
				break;

			default:
			case MENU_ITEM_ABOUT:
				temp_task_handle = about_task_handle;
				select_graph_buffer = false;
			}

			// Select and initialize display buffer to use.
			display_y_offset = select_graph_buffer ? CANVAS_GRAPH_Y_OFFSET : 0;

			// Draw the menu bar (only needs to be done once for graph)
			if (!select_graph_buffer || !graph_buffer_initialized) {
				// Clear the selected display buffer first
				gfx_mono_draw_filled_rect(0, display_y_offset,
						GFX_MONO_LCD_WIDTH, GFX_MONO_LCD_HEIGHT / 2,
						GFX_PIXEL_CLR);

				// Draw menu lines, each item with height MENU_HEIGHT pixels
				y = display_y_offset + CANVAS_HEIGHT;
				gfx_mono_draw_horizontal_line(0, y, GFX_MONO_LCD_WIDTH,
						GFX_PIXEL_SET);

				x = MENU_ITEM_WIDTH;
				y++;

				for (uint8_t i = 0; i < (MENU_NUM_ITEMS - 1); i++) {
					gfx_mono_draw_vertical_line(x, y, MENU_HEIGHT,
							GFX_PIXEL_SET);
					x += 1 + MENU_ITEM_WIDTH;
				}

				// Highlight the current selection
				gfx_mono_draw_rect(current_selection * (1 + MENU_ITEM_WIDTH), y,
						MENU_ITEM_WIDTH, MENU_HEIGHT, GFX_PIXEL_SET);

				// Draw the menu item text
				x = (MENU_ITEM_WIDTH / 2) - ((5 * SYSFONT_WIDTH) / 2);
				y += (MENU_HEIGHT / 2) - (SYSFONT_HEIGHT / 2);

				for (uint8_t i = 0; i < MENU_NUM_ITEMS; i++) {
					gfx_mono_draw_string(menu_items_text[i], x, y, &sysfont);
					x += 1 + MENU_ITEM_WIDTH;
				}

				graph_buffer_initialized = true;
			}

			// Set display controller to output the new buffer
			ssd1306_set_display_start_line_address(display_y_offset);

			// We are done modifying the display, so give back the mutex
			xSemaphoreGive(display_mutex);

			selection_changed = false;

			// If a task handle was specified, resume it now
			if (temp_task_handle) {
				vTaskResume(temp_task_handle);
			}
		}

		// Show that task is done
		oled1_set_led_state(&oled1, OLED1_LED3_ID, false);

		vTaskDelay(MAIN_TASK_DELAY);
	}
}