123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628 |
- /**
- * Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form, except as embedded into a Nordic
- * Semiconductor ASA integrated circuit in a product or a software update for
- * such product, must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- *
- * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * 4. This software, with or without modification, must only be used with a
- * Nordic Semiconductor ASA integrated circuit.
- *
- * 5. Any software provided in binary form under this license must not be reverse
- * engineered, decompiled, modified and/or disassembled.
- *
- * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- #include "sdk_common.h"
- #if NRF_MODULE_ENABLED(NRF_GFX)
- #include "nrf_gfx.h"
- #include <stdlib.h>
- #include "app_util_platform.h"
- #include "nrf_assert.h"
- #define NRF_LOG_MODULE_NAME gfx
- #include "nrf_log.h"
- NRF_LOG_MODULE_REGISTER();
- static inline void pixel_draw(nrf_lcd_t const * p_instance,
- uint16_t x,
- uint16_t y,
- uint32_t color)
- {
- uint16_t lcd_width = nrf_gfx_width_get(p_instance);
- uint16_t lcd_height = nrf_gfx_height_get(p_instance);
- if ((x >= lcd_width) || (y >= lcd_height))
- {
- return;
- }
- p_instance->lcd_pixel_draw(x, y, color);
- }
- static void rect_draw(nrf_lcd_t const * p_instance,
- uint16_t x,
- uint16_t y,
- uint16_t width,
- uint16_t height,
- uint32_t color)
- {
- uint16_t lcd_width = nrf_gfx_width_get(p_instance);
- uint16_t lcd_height = nrf_gfx_height_get(p_instance);
- if ((x >= lcd_width) || (y >= lcd_height))
- {
- return;
- }
- if (width > (lcd_width - x))
- {
- width = lcd_width - x;
- }
- if (height > (lcd_height - y))
- {
- height = lcd_height - y;
- }
- p_instance->lcd_rect_draw(x, y, width, height, color);
- }
- static void line_draw(nrf_lcd_t const * p_instance,
- uint16_t x_0,
- uint16_t y_0,
- uint16_t x_1,
- int16_t y_1,
- uint32_t color)
- {
- uint16_t x = x_0;
- uint16_t y = y_0;
- int16_t d;
- int16_t d_1;
- int16_t d_2;
- int16_t ai;
- int16_t bi;
- int16_t xi = (x_0 < x_1) ? 1 : (-1);
- int16_t yi = (y_0 < y_1) ? 1 : (-1);
- bool swapped = false;
- d_1 = abs(x_1 - x_0);
- d_2 = abs(y_1 - y_0);
- pixel_draw(p_instance, x, y, color);
- if (d_1 < d_2)
- {
- d_1 = d_1 ^ d_2;
- d_2 = d_1 ^ d_2;
- d_1 = d_2 ^ d_1;
- swapped = true;
- }
- ai = (d_2 - d_1) * 2;
- bi = d_2 * 2;
- d = bi - d_1;
- while ((y != y_1) || (x != x_1))
- {
- if (d >= 0)
- {
- x += xi;
- y += yi;
- d += ai;
- }
- else
- {
- d += bi;
- if (swapped)
- {
- y += yi;
- }
- else
- {
- x += xi;
- }
- }
- pixel_draw(p_instance, x, y, color);
- }
- }
- static void write_character(nrf_lcd_t const * p_instance,
- nrf_gfx_font_desc_t const * p_font,
- uint8_t character,
- uint16_t * p_x,
- uint16_t y,
- uint16_t font_color)
- {
- uint8_t char_idx = character - p_font->startChar;
- uint16_t bytes_in_line = CEIL_DIV(p_font->charInfo[char_idx].widthBits, 8);
- if (character == ' ')
- {
- *p_x += p_font->height / 2;
- return;
- }
- for (uint16_t i = 0; i < p_font->height; i++)
- {
- for (uint16_t j = 0; j < bytes_in_line; j++)
- {
- for (uint8_t k = 0; k < 8; k++)
- {
- if ((1 << (7 - k)) &
- p_font->data[p_font->charInfo[char_idx].offset + i * bytes_in_line + j])
- {
- pixel_draw(p_instance, *p_x + j * 8 + k, y + i, font_color);
- }
- }
- }
- }
- *p_x += p_font->charInfo[char_idx].widthBits + p_font->spacePixels;
- }
- ret_code_t nrf_gfx_init(nrf_lcd_t const * p_instance)
- {
- ASSERT(p_instance != NULL);
- ASSERT(p_instance->p_lcd_cb->state == NRFX_DRV_STATE_UNINITIALIZED);
- ASSERT(p_instance->lcd_init != NULL);
- ASSERT(p_instance->lcd_uninit != NULL);
- ASSERT(p_instance->lcd_pixel_draw != NULL);
- ASSERT(p_instance->lcd_rect_draw != NULL);
- ASSERT(p_instance->lcd_display != NULL);
- ASSERT(p_instance->lcd_rotation_set != NULL);
- ASSERT(p_instance->lcd_display_invert != NULL);
- ASSERT(p_instance->p_lcd_cb != NULL);
- ret_code_t err_code;
- err_code = p_instance->lcd_init();
- if (err_code == NRF_SUCCESS)
- {
- p_instance->p_lcd_cb->state = NRFX_DRV_STATE_INITIALIZED;
- }
- return err_code;
- }
- void nrf_gfx_uninit(nrf_lcd_t const * p_instance)
- {
- ASSERT(p_instance != NULL);
- ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
- p_instance->p_lcd_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
- p_instance->lcd_uninit();
- }
- void nrf_gfx_point_draw(nrf_lcd_t const * p_instance,
- nrf_gfx_point_t const * p_point,
- uint32_t color)
- {
- ASSERT(p_instance != NULL);
- ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
- ASSERT(p_point != NULL);
- pixel_draw(p_instance, p_point->x, p_point->y, color);
- }
- ret_code_t nrf_gfx_line_draw(nrf_lcd_t const * p_instance,
- nrf_gfx_line_t const * p_line,
- uint32_t color)
- {
- ASSERT(p_instance != NULL);
- ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
- ASSERT(p_line != NULL);
- uint16_t x_thick = 0;
- uint16_t y_thick = 0;
- if (((p_line->x_start > nrf_gfx_width_get(p_instance)) &&
- (p_line->x_end > nrf_gfx_height_get(p_instance))) ||
- ((p_line->y_start > nrf_gfx_width_get(p_instance)) &&
- (p_line->y_end > nrf_gfx_height_get(p_instance))))
- {
- return NRF_ERROR_INVALID_PARAM;
- }
- if (abs(p_line->x_start - p_line->x_end) > abs(p_line->y_start - p_line->y_end))
- {
- y_thick = p_line->thickness;
- }
- else
- {
- x_thick = p_line->thickness;
- }
- if ((p_line->x_start == p_line->x_end) || (p_line->y_start == p_line->y_end))
- {
- rect_draw(p_instance,
- p_line->x_start,
- p_line->y_start,
- abs(p_line->x_end - p_line->x_start) + x_thick,
- abs(p_line->y_end - p_line->y_start) + y_thick,
- color);
- }
- else
- {
- if (x_thick > 0)
- {
- for (uint16_t i = 0; i < p_line->thickness; i++)
- {
- line_draw(p_instance,
- p_line->x_start + i,
- p_line->y_start,
- p_line->x_end + i,
- p_line->y_end,
- color);
- }
- }
- else if (y_thick > 0)
- {
- for (uint16_t i = 0; i < p_line->thickness; i++)
- {
- line_draw(p_instance,
- p_line->x_start,
- p_line->y_start + i,
- p_line->x_end,
- p_line->y_end + i,
- color);
- }
- }
- else
- {
- line_draw(p_instance,
- p_line->x_start + x_thick,
- p_line->y_start + y_thick,
- p_line->x_end + x_thick,
- p_line->y_end + y_thick,
- color);
- }
- }
- return NRF_SUCCESS;
- }
- ret_code_t nrf_gfx_circle_draw(nrf_lcd_t const * p_instance,
- nrf_gfx_circle_t const * p_circle,
- uint32_t color,
- bool fill)
- {
- ASSERT(p_instance != NULL);
- ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
- ASSERT(p_circle != NULL);
- int16_t y = 0;
- int16_t err = 0;
- int16_t x = p_circle->r;
- if ((p_circle->x - p_circle->r > nrf_gfx_width_get(p_instance)) ||
- (p_circle->y - p_circle->r > nrf_gfx_height_get(p_instance)))
- {
- return NRF_ERROR_INVALID_PARAM;
- }
- while (x >= y)
- {
- if (fill)
- {
- if ((-y + p_circle->x < 0) || (-x + p_circle->x < 0))
- {
- rect_draw(p_instance, 0, (-x + p_circle->y), (y + p_circle->x + 1), 1, color);
- rect_draw(p_instance, 0, (-y + p_circle->y), (x + p_circle->x + 1), 1, color);
- rect_draw(p_instance, 0, (y + p_circle->y), (x + p_circle->x + 1), 1, color);
- rect_draw(p_instance, 0, (x + p_circle->y), (y + p_circle->x + 1), 1, color);
- }
- else
- {
- rect_draw(p_instance, (-y + p_circle->x), (-x + p_circle->y), (2 * y + 1), 1, color);
- rect_draw(p_instance, (-x + p_circle->x), (-y + p_circle->y), (2 * x + 1), 1, color);
- rect_draw(p_instance, (-x + p_circle->x), (y + p_circle->y), (2 * x + 1), 1, color);
- rect_draw(p_instance, (-y + p_circle->x), (x + p_circle->y), (2 * y + 1), 1, color);
- }
- }
- else
- {
- pixel_draw(p_instance, (y + p_circle->x), (x + p_circle->y), color);
- pixel_draw(p_instance, (-y + p_circle->x), (x + p_circle->y), color);
- pixel_draw(p_instance, (x + p_circle->x), (y + p_circle->y), color);
- pixel_draw(p_instance, (-x + p_circle->x), (y + p_circle->y), color);
- pixel_draw(p_instance, (-y + p_circle->x), (-x + p_circle->y), color);
- pixel_draw(p_instance, (y + p_circle->x), (-x + p_circle->y), color);
- pixel_draw(p_instance, (-x + p_circle->x), (-y + p_circle->y), color);
- pixel_draw(p_instance, (x + p_circle->x), (-y + p_circle->y), color);
- }
- if (err <= 0)
- {
- y += 1;
- err += 2 * y + 1;
- }
- if (err > 0)
- {
- x -= 1;
- err -= 2 * x + 1;
- }
- }
- return NRF_SUCCESS;
- }
- ret_code_t nrf_gfx_rect_draw(nrf_lcd_t const * p_instance,
- nrf_gfx_rect_t const * p_rect,
- uint16_t thickness,
- uint32_t color,
- bool fill)
- {
- ASSERT(p_instance != NULL);
- ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
- ASSERT(p_rect != NULL);
- uint16_t rect_width = p_rect->width - thickness;
- uint16_t rect_height = p_rect->height - thickness;
- if ((p_rect->width == 1) ||
- (p_rect->height == 1) ||
- (thickness * 2 > p_rect->width) ||
- (thickness * 2 > p_rect->height) ||
- ((p_rect->x > nrf_gfx_width_get(p_instance)) &&
- (p_rect->y > nrf_gfx_height_get(p_instance))))
- {
- return NRF_ERROR_INVALID_PARAM;
- }
- if (fill)
- {
- rect_draw(p_instance,
- p_rect->x,
- p_rect->y,
- p_rect->width,
- p_rect->height,
- color);
- }
- else
- {
- nrf_gfx_line_t line;
- // Top horizontal line.
- line.x_start = p_rect->x;
- line.y_start = p_rect->y;
- line.x_end = p_rect->x + p_rect->width;
- line.y_end = p_rect->y;
- line.thickness = thickness;
- (void)nrf_gfx_line_draw(p_instance, &line, color);
- // Bottom horizontal line.
- line.x_start = p_rect->x;
- line.y_start = p_rect->y + rect_height;
- line.x_end = p_rect->x + p_rect->width;
- line.y_end = p_rect->y + rect_height;
- (void)nrf_gfx_line_draw(p_instance, &line, color);
- // Left vertical line.
- line.x_start = p_rect->x;
- line.y_start = p_rect->y + thickness;
- line.x_end = p_rect->x;
- line.y_end = p_rect->y + rect_height;
- (void)nrf_gfx_line_draw(p_instance, &line, color);
- // Right vertical line.
- line.x_start = p_rect->x + rect_width;
- line.y_start = p_rect->y + thickness;
- line.x_end = p_rect->x + rect_width;
- line.y_end = p_rect->y + rect_height;
- (void)nrf_gfx_line_draw(p_instance, &line, color);
- }
- return NRF_SUCCESS;
- }
- void nrf_gfx_screen_fill(nrf_lcd_t const * p_instance, uint32_t color)
- {
- rect_draw(p_instance, 0, 0, nrf_gfx_width_get(p_instance), nrf_gfx_height_get(p_instance), color);
- }
- ret_code_t nrf_gfx_bmp565_draw(nrf_lcd_t const * p_instance,
- nrf_gfx_rect_t const * p_rect,
- uint16_t const * img_buf)
- {
- ASSERT(p_instance != NULL);
- ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
- ASSERT(p_rect != NULL);
- ASSERT(img_buf != NULL);
- if ((p_rect->x > nrf_gfx_width_get(p_instance)) || (p_rect->y > nrf_gfx_height_get(p_instance)))
- {
- return NRF_ERROR_INVALID_PARAM;
- }
- size_t idx;
- uint16_t pixel;
- uint8_t padding = p_rect->width % 2;
- for (int32_t i = 0; i < p_rect->height; i++)
- {
- for (uint32_t j = 0; j < p_rect->width; j++)
- {
- idx = (uint32_t)((p_rect->height - i - 1) * (p_rect->width + padding) + j);
- pixel = (img_buf[idx] >> 8) | (img_buf[idx] << 8);
- pixel_draw(p_instance, p_rect->x + j, p_rect->y + i, pixel);
- }
- }
- return NRF_SUCCESS;
- }
- void nrf_gfx_background_set(nrf_lcd_t const * p_instance, uint16_t const * img_buf)
- {
- ASSERT(p_instance != NULL);
- ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
- ASSERT(img_buf != NULL);
- const nrf_gfx_rect_t rectangle =
- {
- .x = 0,
- .y = 0,
- .width = nrf_gfx_width_get(p_instance),
- .height = nrf_gfx_height_get(p_instance)
- };
- (void)nrf_gfx_bmp565_draw(p_instance, &rectangle, img_buf);
- }
- void nrf_gfx_display(nrf_lcd_t const * p_instance)
- {
- ASSERT(p_instance != NULL);
- p_instance->lcd_display();
- }
- void nrf_gfx_rotation_set(nrf_lcd_t const * p_instance, nrf_lcd_rotation_t rotation)
- {
- ASSERT(p_instance != NULL);
- ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
- bool rotated = (bool)(p_instance->p_lcd_cb->rotation % 2);
- uint16_t height = !rotated ? nrf_gfx_height_get(p_instance) :
- nrf_gfx_width_get(p_instance);
- uint16_t width = !rotated ? nrf_gfx_width_get(p_instance) :
- nrf_gfx_height_get(p_instance);
- p_instance->p_lcd_cb->rotation = rotation;
- switch (rotation) {
- case NRF_LCD_ROTATE_0:
- p_instance->p_lcd_cb->height = height;
- p_instance->p_lcd_cb->width = width;
- break;
- case NRF_LCD_ROTATE_90:
- p_instance->p_lcd_cb->height = width;
- p_instance->p_lcd_cb->width = height;
- break;
- case NRF_LCD_ROTATE_180:
- p_instance->p_lcd_cb->height = height;
- p_instance->p_lcd_cb->width = width;
- break;
- case NRF_LCD_ROTATE_270:
- p_instance->p_lcd_cb->height = width;
- p_instance->p_lcd_cb->width = height;
- break;
- default:
- break;
- }
- p_instance->lcd_rotation_set(rotation);
- }
- void nrf_gfx_invert(nrf_lcd_t const * p_instance, bool invert)
- {
- ASSERT(p_instance != NULL);
- p_instance->lcd_display_invert(invert);
- }
- ret_code_t nrf_gfx_print(nrf_lcd_t const * p_instance,
- nrf_gfx_point_t const * p_point,
- uint16_t font_color,
- const char * string,
- const nrf_gfx_font_desc_t * p_font,
- bool wrap)
- {
- ASSERT(p_instance != NULL);
- ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
- ASSERT(p_point != NULL);
- ASSERT(string != NULL);
- ASSERT(p_font != NULL);
- uint16_t x = p_point->x;
- uint16_t y = p_point->y;
- if (y > (nrf_gfx_height_get(p_instance) - p_font->height))
- {
- // Not enough space to write even single char.
- return NRF_ERROR_INVALID_PARAM;
- }
- for (size_t i = 0; string[i] != '\0' ; i++)
- {
- if (string[i] == '\n')
- {
- x = p_point->x;
- y += p_font->height + p_font->height / 10;
- }
- else
- {
- write_character(p_instance, p_font, (uint8_t)string[i], &x, y, font_color);
- }
- uint8_t char_idx = string[i] - p_font->startChar;
- uint16_t char_width = string[i] == ' ' ? (p_font->height / 2) :
- p_font->charInfo[char_idx].widthBits;
- if (x > (nrf_gfx_width_get(p_instance) - char_width))
- {
- if (wrap)
- {
- x = p_point->x;
- y += p_font->height + p_font->height / 10;
- }
- else
- {
- break;
- }
- if (y > (nrf_gfx_height_get(p_instance) - p_font->height))
- {
- break;
- }
- }
- }
- return NRF_SUCCESS;
- }
- uint16_t nrf_gfx_height_get(nrf_lcd_t const * p_instance)
- {
- ASSERT(p_instance != NULL);
- return p_instance->p_lcd_cb->height;
- }
- uint16_t nrf_gfx_width_get(nrf_lcd_t const * p_instance)
- {
- ASSERT(p_instance != NULL);
- return p_instance->p_lcd_cb->width;
- }
- #endif //NRF_MODULE_ENABLED(NRF_GFX)
|