/** * \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); } }
/** * \internal * \brief Helper function that draws a character from a font in progmem * to the display * * This function will first calculate the start offset in the font character * data before iterating over the specific character data. * * Only pixels in the character that should be enabled are done so, the caller * is required to prepare the drawing area before printing a character to it. * This is done by the gfx_mono_draw_string() and * gfx_mono_draw_progmem_string() functions. * * \param ch Character to be drawn * \param x X coordinate on screen. * \param y Y coordinate on screen. * \param font Font to draw character in */ static void gfx_mono_draw_char_progmem(const char ch, const gfx_coord_t x, const gfx_coord_t y, const struct font *font) { uint8_t PROGMEM_PTR_T glyph_data; uint16_t glyph_data_offset; uint8_t char_row_size; uint8_t rows_left; uint8_t i; /* Sanity check on parameters, assert if font is NULL. */ Assert(font != NULL); gfx_coord_t inc_x = x; gfx_coord_t inc_y = y; char_row_size = font->width / CONFIG_FONT_PIXELS_PER_BYTE; if (font->width % CONFIG_FONT_PIXELS_PER_BYTE) { char_row_size++; } glyph_data_offset = char_row_size * font->height * ((uint8_t)ch - font->first_char); glyph_data = font->data.progmem + glyph_data_offset; rows_left = font->height; do { uint8_t glyph_byte = 0; uint8_t pixelsToDraw = font->width; for (i = 0; i < pixelsToDraw; i++) { if (i % CONFIG_FONT_PIXELS_PER_BYTE == 0) { glyph_byte = PROGMEM_READ_BYTE(glyph_data); glyph_data++; } if ((glyph_byte & 0x80)) { gfx_mono_draw_pixel(inc_x, inc_y, GFX_PIXEL_SET); } inc_x += 1; glyph_byte <<= 1; } inc_y += 1; inc_x = x; rows_left--; } while (rows_left > 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); } }
/** * \internal * \brief Helper function that draws a character from a font in hugemem * to the display * * This function will first calculate the start offset in the font character * data before iterating over the specific character data. * * Only pixels in the character that should be enabled are done so, the caller * is required to prepare the drawing area before printing a character to it. * This is done by the gfx_mono_draw_string() and * gfx_mono_draw_progmem_string() functions. * * \param ch Character to be drawn * \param x X coordinate on screen. * \param y Y coordinate on screen. * \param font Font to draw character in */ static void gfx_mono_draw_char_hugemem(const char ch, const gfx_coord_t x, const gfx_coord_t y, const struct font *font) { uint8_t i; uint8_t char_row_size; uint8_t glyph_size; uint16_t glyph_data_offset; uint8_t char_buff[EXTMEM_BUF_SIZE]; uint8_t buffer_pos; uint8_t rows_left; /* Sanity check on parameters, assert if font is NULL. */ Assert(font != NULL); gfx_coord_t inc_x = x; gfx_coord_t inc_y = y; char_row_size = font->width / CONFIG_FONT_PIXELS_PER_BYTE; if (font->width % CONFIG_FONT_PIXELS_PER_BYTE) { char_row_size++; } glyph_size = char_row_size * font->height; glyph_data_offset = glyph_size * ((uint8_t)ch - font->first_char); buffer_pos = EXTMEM_BUF_SIZE; rows_left = font->height; do { static uint8_t glyph_byte = 0; uint8_t pixelsToDraw = font->width; for (i = 0; i < pixelsToDraw; i++) { if (i % CONFIG_FONT_PIXELS_PER_BYTE == 0) { /* Read another byte from hugemem */ if (buffer_pos >= EXTMEM_BUF_SIZE) { hugemem_ptr_t source = font->data.hugemem; source = (hugemem_ptr_t) ((uint32_t)source + glyph_data_offset); hugemem_read_block(char_buff, source, EXTMEM_BUF_SIZE); glyph_data_offset += EXTMEM_BUF_SIZE; buffer_pos = 0; } glyph_byte = char_buff[buffer_pos]; buffer_pos++; } /* Draw bit of glyph to screen */ if ((glyph_byte & 0x80)) { gfx_mono_draw_pixel(inc_x, inc_y, GFX_PIXEL_SET); } inc_x += 1; glyph_byte <<= 1; } inc_y += 1; inc_x = x; } while (--rows_left > 0); }