Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nickshl/DevCore.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornickshl <nicolai.shlapunov@gmail.com>2018-10-05 04:23:23 +0300
committernickshl <nicolai.shlapunov@gmail.com>2018-10-05 04:23:23 +0300
commitdea80e6a1743a02e119fe0a9bb4a00c3e6301d1e (patch)
tree808bc1a5ca97e81650b6ab0fe8e22164b78f5eb2
parent07550101d661d0c1d6bbb4d84c3ca3f1a11b4daf (diff)
DevCore - initial version
-rw-r--r--DevCfg.cpp85
-rw-r--r--DevCfg.h157
-rw-r--r--Display/DisplayDrv.cpp573
-rw-r--r--Display/DisplayDrv.h202
-rw-r--r--Display/Fonts.c1312
-rw-r--r--Display/Fonts.h47
-rw-r--r--Display/ILI9341.cpp566
-rw-r--r--Display/ILI9341.h258
-rw-r--r--Display/Image.cpp366
-rw-r--r--Display/Image.h178
-rw-r--r--Display/Primitives.cpp326
-rw-r--r--Display/Primitives.h161
-rw-r--r--Display/Strings.cpp242
-rw-r--r--Display/Strings.h146
-rw-r--r--Display/TiledMap.cpp179
-rw-r--r--Display/TiledMap.h131
-rw-r--r--Display/VisObject.cpp125
-rw-r--r--Display/VisObject.h199
-rw-r--r--Display/XPT2046.cpp145
-rw-r--r--Display/XPT2046.h129
-rw-r--r--Drivers/StHalIic.cpp245
-rw-r--r--Drivers/StHalIic.h153
-rw-r--r--Drivers/StHalSpi.cpp335
-rw-r--r--Drivers/StHalSpi.h162
-rw-r--r--Drivers/StHalUart.cpp202
-rw-r--r--Drivers/StHalUart.h131
-rw-r--r--Framework/AppTask.cpp274
-rw-r--r--Framework/AppTask.h185
-rw-r--r--Framework/Result.h232
-rw-r--r--FreeRtosWrapper/Rtos.cpp108
-rw-r--r--FreeRtosWrapper/Rtos.h124
-rw-r--r--FreeRtosWrapper/RtosMutex.cpp124
-rw-r--r--FreeRtosWrapper/RtosMutex.h59
-rw-r--r--FreeRtosWrapper/RtosQueue.cpp363
-rw-r--r--FreeRtosWrapper/RtosQueue.h157
-rw-r--r--FreeRtosWrapper/RtosSemaphore.cpp125
-rw-r--r--FreeRtosWrapper/RtosSemaphore.h89
-rw-r--r--FreeRtosWrapper/RtosTick.cpp103
-rw-r--r--FreeRtosWrapper/RtosTick.h106
-rw-r--r--FreeRtosWrapper/RtosTimer.cpp269
-rw-r--r--FreeRtosWrapper/RtosTimer.h144
-rw-r--r--Interfaces/IIic.h156
-rw-r--r--Interfaces/ISpi.h156
-rw-r--r--Interfaces/IUart.h104
-rw-r--r--Libraries/BoschBME280.cpp402
-rw-r--r--Libraries/BoschBME280.h306
-rw-r--r--Libraries/Eeprom24.cpp114
-rw-r--r--Libraries/Eeprom24.h107
-rw-r--r--Tasks/InputDrv.cpp728
-rw-r--r--Tasks/InputDrv.h415
-rw-r--r--Tasks/SoundDrv.cpp273
-rw-r--r--Tasks/SoundDrv.h155
-rw-r--r--UiEngine/UiButton.cpp129
-rw-r--r--UiEngine/UiButton.h116
-rw-r--r--UiEngine/UiCheckbox.cpp99
-rw-r--r--UiEngine/UiCheckbox.h89
-rw-r--r--UiEngine/UiEngine.h64
-rw-r--r--UiEngine/UiMenu.cpp280
-rw-r--r--UiEngine/UiMenu.h157
-rw-r--r--UiEngine/UiMsgBox.cpp198
-rw-r--r--UiEngine/UiMsgBox.h128
-rw-r--r--UiEngine/UiScroll.cpp220
-rw-r--r--UiEngine/UiScroll.h126
63 files changed, 13739 insertions, 0 deletions
diff --git a/DevCfg.cpp b/DevCfg.cpp
new file mode 100644
index 0000000..353e07b
--- /dev/null
+++ b/DevCfg.cpp
@@ -0,0 +1,85 @@
+//******************************************************************************
+// @file DevCfg.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Config file, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+
+// *****************************************************************************
+// *** new operator ********************************************************
+// *****************************************************************************
+void* operator new(size_t sz)
+{
+ return pvPortMalloc(sz);
+}
+
+// *****************************************************************************
+// *** new operator for arrays *********************************************
+// *****************************************************************************
+void* operator new[](size_t sz)
+{
+ return pvPortMalloc(sz);
+}
+
+// *****************************************************************************
+// *** delete operator *****************************************************
+// *****************************************************************************
+void operator delete(void* p)
+{
+ vPortFree(p);
+}
+
+// *****************************************************************************
+// *** delete operator for arrays ******************************************
+// *****************************************************************************
+void operator delete[](void* p)
+{
+ vPortFree(p);
+}
+
+// *****************************************************************************
+// *** Placement new operator **********************************************
+// *****************************************************************************
+void* operator new(size_t size, void* p)
+{
+ (void)size;
+ return p;
+}
+
+// *****************************************************************************
+// *** Placement new operator for arrays ***********************************
+// *****************************************************************************
+void* operator new[](size_t size, void* p)
+{
+ (void)size;
+ return p;
+}
+
+// *****************************************************************************
+// *** Placement delete operator *******************************************
+// *****************************************************************************
+void operator delete(void*, void*)
+{
+}
+
+// *****************************************************************************
+// *** Placement delete operator for arrays ********************************
+// *****************************************************************************
+void operator delete[](void*, void*)
+{
+}
diff --git a/DevCfg.h b/DevCfg.h
new file mode 100644
index 0000000..ce3fd28
--- /dev/null
+++ b/DevCfg.h
@@ -0,0 +1,157 @@
+//******************************************************************************
+// @file DevCfg.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Config file, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef DevCfg_h
+#define DevCfg_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "Result.h"
+#include "Rtos.h"
+
+// Include for all hardware stuff
+#include "main.h"
+
+// *** ADC *****************************************************************
+#ifdef HAL_ADC_MODULE_ENABLED
+#include "adc.h"
+#else
+typedef uint32_t ADC_HandleTypeDef; // Dummy ADC handle for compilation
+#endif
+// *** SPI *****************************************************************
+#ifdef HAL_SPI_MODULE_ENABLED
+#include "spi.h"
+#else
+typedef uint32_t SPI_HandleTypeDef; // Dummy SPI handle for compilation
+#endif
+// *** I2C *****************************************************************
+#ifdef HAL_I2C_MODULE_ENABLED
+#include "i2c.h"
+#else
+typedef uint32_t I2C_HandleTypeDef; // Dummy I2C handle for compilation
+#endif
+// *** TIM *****************************************************************
+#ifdef HAL_TIM_MODULE_ENABLED
+#include "tim.h"
+#else
+typedef uint32_t TIM_HandleTypeDef; // Dummy TIM handle for compilation
+#endif
+// *** DAC *****************************************************************
+#ifdef HAL_DAC_MODULE_ENABLED
+#include "dac.h"
+#else
+typedef uint32_t DAC_HandleTypeDef; // Dummy DAC handle for compilation
+#endif
+
+#include "usb_device.h"
+
+// *****************************************************************************
+// *** Configuration *******************************************************
+// *****************************************************************************
+
+// *** SPI Handles *********************************************************
+#ifdef HAL_SPI_MODULE_ENABLED
+ // Display SPI handle
+ static SPI_HandleTypeDef* const TFT_HSPI = &hspi1;
+ // Touchscreen SPI handle
+ static SPI_HandleTypeDef* const TOUCH_HSPI = &hspi1;
+#endif
+// *** I2C Handles *********************************************************
+#ifdef HAL_I2C_MODULE_ENABLED
+ // BME280 I2C handle
+ static I2C_HandleTypeDef& BME280_HI2C = hi2c1;
+#endif
+// *** TIM Handles *********************************************************
+#ifdef HAL_TIM_MODULE_ENABLED
+ // Sound Timer handle
+ static TIM_HandleTypeDef* const SOUND_HTIM = &htim4;
+ // Sound Timer channel
+ static const uint32_t SOUND_CHANNEL = TIM_CHANNEL_2;
+#endif
+
+// *** Applications tasks stack sizes ****************************************
+const static uint16_t APPLICATION_TASK_STACK_SIZE = 1024U;
+const static uint16_t EXAMPLE_MSG_TASK_STACK_SIZE = configMINIMAL_STACK_SIZE;
+// *** Applications tasks priorities *****************************************
+const static uint8_t APPLICATION_TASK_PRIORITY = tskIDLE_PRIORITY + 2U;
+const static uint8_t EXAMPLE_MSG_TASK_PRIORITY = tskIDLE_PRIORITY + 2U;
+// *****************************************************************************
+
+// *** System tasks stack sizes **********************************************
+const static uint16_t DISPLAY_DRV_TASK_STACK_SIZE = 256U;
+const static uint16_t INPUT_DRV_TASK_STACK_SIZE = configMINIMAL_STACK_SIZE;
+const static uint16_t SOUND_DRV_TASK_STACK_SIZE = configMINIMAL_STACK_SIZE;
+// *** System tasks priorities ***********************************************
+const static uint8_t DISPLAY_DRV_TASK_PRIORITY = tskIDLE_PRIORITY + 1U;
+const static uint8_t INPUT_DRV_TASK_PRIORITY = tskIDLE_PRIORITY + 2U;
+const static uint8_t SOUND_DRV_TASK_PRIORITY = tskIDLE_PRIORITY + 3U;
+// *****************************************************************************
+
+// *****************************************************************************
+// *** Macroses ************************************************************
+// *****************************************************************************
+
+// Number of array elements
+#define NumberOf(x) (sizeof(x)/sizeof((x)[0]))
+
+// Break macro - useful for debugging
+#define Break() asm volatile("bkpt #0")
+
+// *****************************************************************************
+// *** Overloaded operators ************************************************
+// *****************************************************************************
+void* operator new(size_t sz);
+void* operator new[](size_t sz);
+void operator delete(void* p);
+void operator delete[](void* p);
+void* operator new(size_t size, void* p);
+void* operator new[](size_t size, void* p);
+void operator delete(void*, void*);
+void operator delete[](void*, void*);
+
+#endif
diff --git a/Display/DisplayDrv.cpp b/Display/DisplayDrv.cpp
new file mode 100644
index 0000000..16c1eac
--- /dev/null
+++ b/Display/DisplayDrv.cpp
@@ -0,0 +1,573 @@
+//******************************************************************************
+// @file DisplayDrv.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Display Driver Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DisplayDrv.h"
+
+// *****************************************************************************
+// *** Get Instance ********************************************************
+// *****************************************************************************
+DisplayDrv& DisplayDrv::GetInstance(void)
+{
+ static DisplayDrv display_drv;
+ return display_drv;
+}
+
+// *****************************************************************************
+// *** Display Driver Setup ************************************************
+// *****************************************************************************
+Result DisplayDrv::Setup()
+{
+ // Init display driver
+ tft.Init();
+ // Set mode - mode can be set earlier than Display initialization
+ SetUpdateMode(update_mode);
+
+ // If deisplay and touchscreen share same SPI
+ if(tft_hspi == touch_hspi)
+ {
+ // Set prescaler for SPI
+ MODIFY_REG(tft_hspi->Instance->CR1, (uint32_t)SPI_CR1_BR_Msk, SPI_BAUDRATEPRESCALER_64);
+ // Init touchscreen driver
+ touch.Init();
+ // Restore prescaler for SPI
+ MODIFY_REG(tft_hspi->Instance->CR1, (uint32_t)SPI_CR1_BR_Msk, SPI_BAUDRATEPRESCALER_2);
+ }
+ else
+ {
+ // Init touchscreen driver
+ touch.Init();
+ }
+
+ // Set string parameters
+ fps_str.SetParams(str, width/3, height - 6, COLOR_MAGENTA, String::FONT_4x6);
+ // Show string if flag is set
+ if(DISPLAY_DEBUG_INFO)
+ {
+ // Max Z
+ fps_str.Show(0xFFFFFFFFU);
+ }
+
+ // Always ok
+ return Result::RESULT_OK;
+}
+
+// *****************************************************************************
+// *** Display Driver Loop *************************************************
+// *****************************************************************************
+Result DisplayDrv::Loop()
+{
+ // Variable for find FPS
+ uint32_t time_ms = HAL_GetTick();
+
+ // If semaphore doesn't exist or taken within 100 ms - draw screen
+ // Time need for update touchscreen state every 100 ms even display not
+ // updated
+ if(screen_update.Take(100U) == Result::RESULT_OK)
+ {
+ // Set window for all screen and pointer to first pixel
+ LockDisplay();
+ // Set address window for all screen
+ tft.SetAddrWindow(0, 0, width-1, height-1);
+ // For each line/row
+ for(int32_t i=0; i < height; i++)
+ {
+ // Clear half of buffer
+ memset(scr_buf[i%2], 0x00, sizeof(scr_buf[0]));
+ // Take semaphore before draw line
+ line_mutex.Lock();
+ // Set pointer to first element
+ VisObject* p_obj = object_list;
+ // Do for all objects
+ while(p_obj != nullptr)
+ {
+ // Draw object to buf
+ if(update_mode) p_obj->DrawInBufH(scr_buf[i%2], width, i);
+ else p_obj->DrawInBufW(scr_buf[i%2], width, i);
+ // Set pointer to next object in list
+ p_obj = p_obj->p_next;
+ }
+ // Give semaphore after changes
+ line_mutex.Release();
+ // Wait until previous transfer complete
+ while(tft.IsTransferComplete() == false) taskYIELD();
+ // Write stream to LCD
+ tft.SpiWriteStream((uint8_t*)scr_buf[i%2], width*tft.GetBytesPerPixel());
+ // DO NOT TRY "OPTIMIZE" CODE !!!
+ // Two "while" cycles used for generate next line when previous line
+ // transfer via SPI to display.
+ }
+ // Wait until last transfer complete
+ while(tft.IsTransferComplete() == false) taskYIELD();
+ // Pull up CS
+ tft.StopTransfer();
+ // Give semaphore after draw frame
+ UnlockDisplay();
+ // Calculate FPS if debug info is ON
+ if(DISPLAY_DEBUG_INFO)
+ {
+ // FPS in format XX.X
+ fps_x10 = (1000 * 10) / (HAL_GetTick() - time_ms);
+ }
+ }
+
+ bool tmp_is_touch = false;
+ int32_t tmp_tx = tx;
+ int32_t tmp_ty = ty;
+ // Try to take mutex. 1 ms should be enough.
+ if(touchscreen_mutex.Lock(1U) == Result::RESULT_OK)
+ {
+ // Set prescaler for SPI it display share save SPI with touchscreen
+ if(tft_hspi == touch_hspi)
+ {
+ MODIFY_REG(tft_hspi->Instance->CR1, (uint32_t)SPI_CR1_BR_Msk, SPI_BAUDRATEPRESCALER_64);
+ }
+ // Get touch coordinates
+ tmp_is_touch = touch.GetXY(tmp_tx, tmp_ty);
+ // Reset prescaler for SPI it display share save SPI with touchscreen
+ if(tft_hspi == touch_hspi)
+ {
+ // Restore prescaler for SPI
+ MODIFY_REG(tft_hspi->Instance->CR1, (uint32_t)SPI_CR1_BR_Msk, SPI_BAUDRATEPRESCALER_2);
+ }
+ // Give semaphore for drawing frame - we can enter in this "if" statement
+ // only if mutex taken
+ touchscreen_mutex.Release();
+ }
+ // If touch state changed (move)
+ if(is_touch && tmp_is_touch && ((tx != tmp_tx) || (ty != tmp_ty)) )
+ {
+ // Go thru VisObject list and call Active() function for active object
+ // Take semaphore before draw line
+ line_mutex.Lock();
+ // Set pointer to first element
+ VisObject* p_obj = object_list_last;
+ // If list not empty
+ if(p_obj != nullptr)
+ {
+ // Do for all objects
+ while(p_obj != nullptr)
+ {
+ // If we found active object
+ if(p_obj->active)
+ {
+ // And touch in this object area
+ if( (tx >= p_obj->GetStartX()) && (tx <= p_obj->GetEndX())
+ && (ty >= p_obj->GetStartY()) && (ty <= p_obj->GetEndY())
+ && (tmp_tx >= p_obj->GetStartX()) && (tmp_tx <= p_obj->GetEndX())
+ && (tmp_ty >= p_obj->GetStartY()) && (tmp_ty <= p_obj->GetEndY()) )
+ {
+ // Call Action() function for Move
+ p_obj->Action(VisObject::ACT_MOVE, tmp_tx, tmp_ty);
+ // No need check all other objects - only one object can be touched
+ break;
+ }
+ if( (tx >= p_obj->GetStartX()) && (tx <= p_obj->GetEndX())
+ && (ty >= p_obj->GetStartY()) && (ty <= p_obj->GetEndY())
+ && ( ((tmp_tx < p_obj->GetStartX()) || (tmp_tx > p_obj->GetEndX()))
+ || ((tmp_ty < p_obj->GetStartY()) || (tmp_ty > p_obj->GetEndY())) ) )
+ {
+ // Call Action() function for Move Out
+ p_obj->Action(VisObject::ACT_MOVEOUT, tmp_tx, tmp_ty);
+ }
+ if( (tmp_tx >= p_obj->GetStartX()) && (tmp_tx <= p_obj->GetEndX())
+ && (tmp_ty >= p_obj->GetStartY()) && (tmp_ty <= p_obj->GetEndY())
+ && ( ((tx < p_obj->GetStartX()) || (tx > p_obj->GetEndX()))
+ || ((ty < p_obj->GetStartY()) || (ty > p_obj->GetEndY())) ) )
+ {
+ // Call Action() function for Move In
+ p_obj->Action(VisObject::ACT_MOVEIN, tmp_tx, tmp_ty);
+ }
+ }
+ // Get previous object
+ p_obj = p_obj->p_prev;
+ }
+ }
+ // Give semaphore after changes
+ line_mutex.Release();
+ }
+ // If touch state changed (touch & release)
+ if(is_touch != tmp_is_touch)
+ {
+ // Go thru VisObject list and call Active() function for active object
+ // Take semaphore before draw line
+ line_mutex.Lock();
+ // Set pointer to first element
+ VisObject* p_obj = object_list_last;
+ // If list not empty
+ if(p_obj != nullptr)
+ {
+ // Do for all objects
+ while(p_obj != nullptr)
+ {
+ // If we found active object
+ if(p_obj->active)
+ {
+ // And touch in this object area
+ if( (tmp_tx >= p_obj->GetStartX()) && (tmp_tx <= p_obj->GetEndX())
+ && (tmp_ty >= p_obj->GetStartY()) && (tmp_ty <= p_obj->GetEndY()) )
+ {
+ // Call Action() function
+ p_obj->Action(tmp_is_touch ? VisObject::ACT_TOUCH : VisObject::ACT_UNTOUCH,
+ tmp_tx, tmp_ty);
+ // No need check all other objects - only one object can be touched
+ break;
+ }
+ }
+ // Get previous object
+ p_obj = p_obj->p_prev;
+ }
+ }
+ // Give semaphore after changes
+ line_mutex.Release();
+ }
+ // Save new touch state
+ is_touch = tmp_is_touch;
+ tx = tmp_tx;
+ ty = tmp_ty;
+
+ // FIX ME: debug code. Should be removed.
+ if(DISPLAY_DEBUG_INFO)
+ {
+ if(is_touch) sprintf(str, "X: %4ld, Y: %4ld", tx, ty);
+ else sprintf(str, "FPS: %2lu.%1lu, time: %lu", fps_x10/10, fps_x10%10, RtosTick::GetTimeMs()/1000UL);
+ fps_str.SetString(str);
+ }
+
+ // Always run
+ return Result::RESULT_OK;
+}
+
+// *****************************************************************************
+// *** Add Visual Object to object list ************************************
+// *****************************************************************************
+Result DisplayDrv::AddVisObjectToList(VisObject* obj, uint32_t z)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ if((obj != nullptr) && (obj->p_prev == nullptr) && (obj->p_next == nullptr) && (obj != object_list))
+ {
+ // Take semaphore before add to list
+ line_mutex.Lock();
+ // Set object Z
+ obj->z = z;
+ // Set prev pointer to nullptr
+ obj->p_prev = nullptr;
+ // Set next pointer to nullptr
+ obj->p_next = nullptr;
+ // If object list empty
+ if(object_list == nullptr)
+ {
+ // Add object to list
+ object_list = obj;
+ // Set pointer to last object in the list
+ object_list_last = obj;
+ }
+ else if(object_list->z > z)
+ {
+ // Set next element to current head element
+ obj->p_next = object_list;
+ // Set prev element to next after head element
+ object_list->p_prev = obj;
+ // Set new head for list
+ object_list = obj;
+ }
+ else
+ {
+ // Set temporary pointer
+ VisObject* p_last = object_list;
+ // Find last element
+ while((p_last->p_next != nullptr) && (p_last->p_next->z < z)) p_last = p_last->p_next;
+ // If it not last element
+ if(p_last->p_next != nullptr)
+ {
+ // Set next pointer in object
+ obj->p_next = p_last->p_next;
+ // Set prev pointer in object
+ obj->p_next->p_prev = obj;
+ }
+ else
+ {
+ // Set pointer to last object in the list
+ object_list_last = obj;
+ }
+ // Set next pointer in prev element
+ p_last->p_next = obj;
+ // Set prev pointer to new object in list
+ obj->p_prev = p_last;
+ }
+ // Give semaphore after changes
+ line_mutex.Release();
+ // Set return status
+ result = Result::RESULT_OK;
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Delete Visual Object from object list *******************************
+// *****************************************************************************
+Result DisplayDrv::DelVisObjectFromList(VisObject* obj)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ if((obj != nullptr) && ((obj->p_prev != nullptr) || (obj->p_next != nullptr) || (obj == object_list)) )
+ {
+ // Take semaphore before delete from list
+ line_mutex.Lock();
+ // Remove element from head
+ if(obj == object_list)
+ {
+ // Set pointer to next object or clear pointer if no more elements
+ object_list = obj->p_next;
+ // Clear previous element in first object
+ object_list->p_prev = nullptr;
+ }
+ else if(obj == object_list_last)
+ {
+ // Set next pointer in previous object to nullptr
+ obj->p_prev->p_next = nullptr;
+ // Set pointer to previous object
+ object_list_last = obj->p_prev;
+ }
+ else
+ {
+ // Remove element from head
+ if(obj->p_prev == nullptr) object_list = obj->p_next;
+ // Remove element from middle
+ else if(obj->p_next != nullptr)
+ {
+ obj->p_prev->p_next = obj->p_next;
+ obj->p_next->p_prev = obj->p_prev;
+ }
+ // remove element from tail
+ else obj->p_prev->p_next = nullptr;
+ }
+ // Clear pointers in object
+ obj->p_prev = nullptr;
+ obj->p_next = nullptr;
+ // Give semaphore after changes
+ line_mutex.Release();
+ // Set return status
+ result = Result::RESULT_OK;
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Lock display ********************************************************
+// *****************************************************************************
+Result DisplayDrv::LockDisplay(uint32_t wait_ms)
+{
+ // Take semaphore for protect draw frame
+ Result result = frame_mutex.Lock(wait_ms);
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** Unlock display ******************************************************
+// *****************************************************************************
+Result DisplayDrv::UnlockDisplay(void)
+{
+ // Give semaphore for drawing frame
+ Result result = frame_mutex.Release();
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** Lock display line ***************************************************
+// *****************************************************************************
+Result DisplayDrv::LockDisplayLine(uint32_t wait_ms)
+{
+ // Take semaphore for protect draw line
+ Result result = line_mutex.Lock(wait_ms);
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** Unlock display line *************************************************
+// *****************************************************************************
+Result DisplayDrv::UnlockDisplayLine(void)
+{
+ // Give semaphore for drawing frame
+ Result result = line_mutex.Release();
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** Update display ******************************************************
+// *****************************************************************************
+Result DisplayDrv::UpdateDisplay(void)
+{
+ // Give semaphore for update screen
+ Result result = screen_update.Give();
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** Set Update Mode *****************************************************
+// *****************************************************************************
+void DisplayDrv::SetUpdateMode(bool is_vertical)
+{
+ // Lock display
+ LockDisplay();
+ // Wait while transfer complete before change settings
+ while(tft.IsTransferComplete() == false);
+ // Change Update mode
+ if(is_vertical)
+ {
+ tft.SetRotation(2U);
+ }
+ else
+ {
+ tft.SetRotation(3U);
+ }
+ // Set width and height variables for selected screen update mode
+ width = tft.GetWidth();
+ height = tft.GetHeight();
+ // Save Update mode
+ update_mode = is_vertical;
+ // Unlock display
+ UnlockDisplay();
+}
+
+// *****************************************************************************
+// *** Get Touch X and Y coordinate ****************************************
+// *****************************************************************************
+bool DisplayDrv::GetTouchXY(int32_t& x, int32_t& y)
+{
+ // Result variable
+ bool result = false;
+
+ // Try to take mutex. 1 ms should be enough.
+ if(touchscreen_mutex.Lock(1U) == Result::RESULT_OK)
+ {
+ // If display driver gets touch coordinates and touch still present
+ if(is_touch && touch.IsTouch())
+ {
+ // Return last values
+ x = tx;
+ y = ty;
+ // Set result
+ result = true;
+ }
+ else
+ {
+ // If no touch - clear flag for prevent return wrong coordinates if
+ // display will touched without reads new coordinates
+ is_touch = false;
+ }
+ // Give semaphore for drawing frame - we can enter in this "if" statement
+ // only if mutex taken
+ touchscreen_mutex.Release();
+ }
+ // Return result
+ return result;
+}
+
+// *************************************************************************
+// *** Check touch *****************************************************
+// *************************************************************************
+bool DisplayDrv::IsTouch()
+{
+ return touch.IsTouch();
+}
+
+// *****************************************************************************
+// *** Calibrate Touchscreen ***********************************************
+// *****************************************************************************
+void DisplayDrv::TouchCalibrate()
+{
+ // Box for calibration
+ Box background(0, 0, width, height, COLOR_BLACK, true);
+ Box box(0, 0, 2, 2, COLOR_WHITE, true);
+ int32_t tx;
+ int32_t ty;
+ int32_t x1, x2;
+ int32_t y1, y2;
+
+ // Reset calibration
+ touch.SetCalibrationConsts(XPT2046::COEF, XPT2046::COEF, 0, 0);
+
+ // Show background box
+ background.Show(0xFFFFFFFFU-1U);
+ // Show box
+ box.Show(0xFFFFFFFFU);
+
+ // Move box to position
+ box.Move(10-1, 10-1);
+ // Wait press for get initial coordinates
+ while(!GetTouchXY(x1, y1))
+ {
+ // Update Display
+ UpdateDisplay();
+ // Delay
+ RtosTick::DelayMs(100U);
+ }
+ // Wait unpress and measure coordinates continuously for averaging
+ while(GetTouchXY(tx, ty))
+ {
+ x1 = (x1 + tx) / 2;
+ y1 = (y1 + ty) / 2;
+ // Update Display - for update touch coordinates
+ UpdateDisplay();
+ // Delay
+ RtosTick::DelayMs(100U);
+ }
+
+ // Move box to position
+ box.Move(width - 10 - 1, height - 10 - 1);
+ // Wait press for get initial coordinates
+ while(!GetTouchXY(x2, y2))
+ {
+ // Update Display
+ UpdateDisplay();
+ // Delay
+ RtosTick::DelayMs(100U);
+ }
+ // Wait unpress and measure coordinates continuously for averaging
+ while(GetTouchXY(tx, ty))
+ {
+ x2 = (x2 + tx) / 2;
+ y2 = (y2 + ty) / 2;
+ // Update Display
+ UpdateDisplay();
+ // Delay
+ RtosTick::DelayMs(100U);
+ }
+
+ // Calc coefs
+ int32_t kx = ((x2 - x1) * XPT2046::COEF) / (width - 2*10);
+ int32_t ky = ((y2 - y1) * XPT2046::COEF) / (height - 2*10);
+ int32_t bx = 10 - (x1 * XPT2046::COEF) / kx;
+ int32_t by = 10 - (y1 * XPT2046::COEF) / ky;
+
+ // Save calibration
+ touch.SetCalibrationConsts(kx, ky, bx, by);
+
+ // Hide box
+ box.Hide();
+}
diff --git a/Display/DisplayDrv.h b/Display/DisplayDrv.h
new file mode 100644
index 0000000..aafa814
--- /dev/null
+++ b/Display/DisplayDrv.h
@@ -0,0 +1,202 @@
+//******************************************************************************
+// @file DisplayDrv.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Display Driver Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+//******************************************************************************
+
+#ifndef DisplayDrv_h
+#define DisplayDrv_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "DevCfg.h"
+#include "AppTask.h"
+#include "RtosMutex.h"
+#include "RtosSemaphore.h"
+
+#include "ILI9341.h"
+#include "XPT2046.h"
+#include "VisObject.h"
+#include "Primitives.h"
+#include "Strings.h"
+#include "Image.h"
+#include "TiledMap.h"
+
+// *****************************************************************************
+// *** Display Driver Class ************************************************
+// *****************************************************************************
+class DisplayDrv : public AppTask
+{
+ public:
+ // *************************************************************************
+ // *** Get Instance ****************************************************
+ // *************************************************************************
+ static DisplayDrv& GetInstance(void);
+
+ // *************************************************************************
+ // *** Display Driver Setup ********************************************
+ // *************************************************************************
+ virtual Result Setup();
+
+ // *************************************************************************
+ // *** Display Driver Loop *********************************************
+ // *************************************************************************
+ virtual Result Loop();
+
+ // *************************************************************************
+ // *** Add Visual Object to object list ********************************
+ // *************************************************************************
+ Result AddVisObjectToList(VisObject* obj, uint32_t z);
+
+ // *************************************************************************
+ // *** Delete Visual Object from object list ***************************
+ // *************************************************************************
+ Result DelVisObjectFromList(VisObject* obj);
+
+ // *************************************************************************
+ // *** Lock display ****************************************************
+ // *************************************************************************
+ Result LockDisplay(uint32_t wait_ms = portMAX_DELAY);
+
+ // *************************************************************************
+ // *** Unlock display **************************************************
+ // *************************************************************************
+ Result UnlockDisplay(void);
+
+ // *************************************************************************
+ // *** Lock display line ***********************************************
+ // *************************************************************************
+ Result LockDisplayLine(uint32_t wait_ms = portMAX_DELAY);
+
+ // *************************************************************************
+ // *** Unlock display line *********************************************
+ // *************************************************************************
+ Result UnlockDisplayLine(void);
+
+ // *************************************************************************
+ // *** Update display **************************************************
+ // *************************************************************************
+ Result UpdateDisplay(void);
+
+ // *************************************************************************
+ // *** Set Update Mode *************************************************
+ // *************************************************************************
+ void SetUpdateMode(bool is_vertical = false);
+
+ // *************************************************************************
+ // *** GetScreenW ******************************************************
+ // *************************************************************************
+ inline int32_t GetScreenW(void) {return width;}
+
+ // *************************************************************************
+ // *** GetScreenH ******************************************************
+ // *************************************************************************
+ inline int32_t GetScreenH(void) {return height;}
+
+ // *************************************************************************
+ // *** Get Touch X and Y coordinate ************************************
+ // *************************************************************************
+ bool GetTouchXY(int32_t& x, int32_t& y);
+
+ // *************************************************************************
+ // *** Check touch *****************************************************
+ // *************************************************************************
+ bool IsTouch();
+
+ // *************************************************************************
+ // *** Calibrate Touchscreen *******************************************
+ // *************************************************************************
+ void TouchCalibrate();
+
+ private:
+ // Display FPS/touch coordinates
+ static const bool DISPLAY_DEBUG_INFO = true;
+
+ // Display driver object
+ ILI9341 tft = TFT_HSPI;
+ // Display SPI handle
+ SPI_HandleTypeDef* tft_hspi = TFT_HSPI;
+
+ // Touchscreen driver object
+ XPT2046 touch = TOUCH_HSPI;
+ // Touchscreen SPI handle
+ SPI_HandleTypeDef* touch_hspi = TOUCH_HSPI;
+
+ // Pointer to first object in list
+ VisObject* object_list = nullptr;
+ // Pointer to last object in list
+ VisObject* object_list_last = nullptr;
+
+ // Update mode: true - vertical, false = horizontal
+ bool update_mode = false;
+ // Variables for update screen mode
+ int32_t width = 0;
+ int32_t height = 0;
+ // Double Screen Line buffer
+ uint16_t scr_buf[2][ILI9341::GetMaxLine()];
+
+ // Touch coordinates and state
+ bool is_touch = false;
+ int32_t tx = 0;
+ int32_t ty = 0;
+
+ // FPS multiplied to 10
+ volatile uint32_t fps_x10 = 0U;
+ // Buffer for print FPS string
+ char str[32] = {" "};
+ // FPS string
+ String fps_str;
+
+ // Semaphore for update screen
+ RtosSemaphore screen_update;
+ // Mutex to synchronize when drawing lines
+ RtosMutex line_mutex;
+ // Mutex to synchronize when drawing frames
+ RtosMutex frame_mutex;
+ // Mutex for synchronize when reads touch coordinates
+ RtosMutex touchscreen_mutex;
+
+ // *************************************************************************
+ // ** Private constructor. Only GetInstance() allow to access this class. **
+ // *************************************************************************
+ DisplayDrv() : AppTask(DISPLAY_DRV_TASK_STACK_SIZE, DISPLAY_DRV_TASK_PRIORITY,
+ "DisplayDrv") {};
+};
+
+#endif
diff --git a/Display/Fonts.c b/Display/Fonts.c
new file mode 100644
index 0000000..06bf86b
--- /dev/null
+++ b/Display/Fonts.c
@@ -0,0 +1,1312 @@
+//******************************************************************************
+// @file Fonts.c
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Fonts data
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+const unsigned char font4x6[256][6] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 - ' '
+ {0x04, 0x0A, 0x0E, 0x0A, 0x04, 0x00}, // 0x01 - ''
+ {0x04, 0x0E, 0x0A, 0x0E, 0x04, 0x00}, // 0x02 - ''
+ {0x00, 0x0A, 0x0E, 0x0E, 0x04, 0x00}, // 0x03 - ''
+ {0x00, 0x04, 0x0E, 0x0E, 0x04, 0x00}, // 0x04 - ''
+ {0x04, 0x0E, 0x0E, 0x04, 0x0E, 0x00}, // 0x05 - ''
+ {0x04, 0x04, 0x0E, 0x04, 0x0E, 0x00}, // 0x06 - ''
+ {0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, // 0x07 - ''
+ {0x0F, 0x0F, 0x0B, 0x0F, 0x0F, 0x0F}, // 0x08 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 - ' '
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A - ' '
+ {0x00, 0x0C, 0x08, 0x06, 0x06, 0x00}, // 0x0B - ' '
+ {0x04, 0x0A, 0x04, 0x0E, 0x04, 0x00}, // 0x0C - ' '
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D - ' '
+ {0x04, 0x0C, 0x0A, 0x08, 0x04, 0x00}, // 0x0E - ''
+ {0x04, 0x0E, 0x0A, 0x0E, 0x04, 0x00}, // 0x0F - ''
+ {0x02, 0x06, 0x0E, 0x06, 0x02, 0x00}, // 0x10 - ''
+ {0x08, 0x0C, 0x0E, 0x0C, 0x08, 0x00}, // 0x11 - ''
+ {0x04, 0x0E, 0x04, 0x0E, 0x04, 0x00}, // 0x12 - ''
+ {0x0A, 0x0A, 0x0A, 0x00, 0x0A, 0x00}, // 0x13 - ''
+ {0x0E, 0x0B, 0x0B, 0x0A, 0x0A, 0x00}, // 0x14 - ''
+ {0x0C, 0x06, 0x0A, 0x0C, 0x06, 0x00}, // 0x15 - ''
+ {0x00, 0x00, 0x06, 0x06, 0x00, 0x00}, // 0x16 - ''
+ {0x04, 0x0E, 0x04, 0x0E, 0x04, 0x0E}, // 0x17 - ''
+ {0x04, 0x0E, 0x04, 0x04, 0x04, 0x00}, // 0x18 - ''
+ {0x04, 0x04, 0x04, 0x0E, 0x04, 0x00}, // 0x19 - ''
+ {0x00, 0x04, 0x0F, 0x04, 0x00, 0x00}, // 0x1A - ' '
+ {0x00, 0x02, 0x0F, 0x02, 0x00, 0x00}, // 0x1B - ''
+ {0x00, 0x00, 0x02, 0x0E, 0x00, 0x00}, // 0x1C - ''
+ {0x00, 0x0A, 0x0E, 0x0A, 0x00, 0x00}, // 0x1D - ''
+ {0x00, 0x04, 0x0E, 0x0E, 0x00, 0x00}, // 0x1E - ''
+ {0x00, 0x0E, 0x0E, 0x04, 0x00, 0x00}, // 0x1F - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 - ' '
+ {0x04, 0x04, 0x04, 0x00, 0x04, 0x00}, // 0x21 - '!'
+ {0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00}, // 0x22 - '"'
+ {0x0A, 0x0E, 0x0A, 0x0E, 0x0A, 0x00}, // 0x23 - '#'
+ {0x04, 0x0C, 0x06, 0x0C, 0x06, 0x04}, // 0x24 - '$'
+ {0x02, 0x08, 0x04, 0x02, 0x08, 0x00}, // 0x25 - '%'
+ {0x04, 0x0A, 0x0C, 0x0A, 0x0E, 0x00}, // 0x26 - '&'
+ {0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, // 0x27 - '''
+ {0x04, 0x02, 0x02, 0x02, 0x04, 0x00}, // 0x28 - '('
+ {0x02, 0x04, 0x04, 0x04, 0x02, 0x00}, // 0x29 - ')'
+ {0x0A, 0x04, 0x0E, 0x04, 0x0A, 0x00}, // 0x2A - '*'
+ {0x00, 0x04, 0x0E, 0x04, 0x00, 0x00}, // 0x2B - '+'
+ {0x00, 0x00, 0x00, 0x00, 0x06, 0x02}, // 0x2C - ','
+ {0x00, 0x00, 0x0E, 0x00, 0x00, 0x00}, // 0x2D - '-'
+ {0x00, 0x00, 0x00, 0x00, 0x04, 0x00}, // 0x2E - '.'
+ {0x08, 0x08, 0x04, 0x02, 0x02, 0x00}, // 0x2F - '/'
+ {0x0C, 0x0A, 0x0A, 0x0A, 0x06, 0x00}, // 0x30 - '0'
+ {0x04, 0x06, 0x04, 0x04, 0x0E, 0x00}, // 0x31 - '1'
+ {0x06, 0x08, 0x04, 0x02, 0x0E, 0x00}, // 0x32 - '2'
+ {0x06, 0x08, 0x04, 0x08, 0x06, 0x00}, // 0x33 - '3'
+ {0x08, 0x0A, 0x0E, 0x08, 0x08, 0x00}, // 0x34 - '4'
+ {0x0E, 0x02, 0x06, 0x08, 0x06, 0x00}, // 0x35 - '5'
+ {0x04, 0x02, 0x06, 0x0A, 0x04, 0x00}, // 0x36 - '6'
+ {0x0E, 0x08, 0x0C, 0x04, 0x04, 0x00}, // 0x37 - '7'
+ {0x04, 0x0A, 0x04, 0x0A, 0x04, 0x00}, // 0x38 - '8'
+ {0x04, 0x0A, 0x0C, 0x08, 0x04, 0x00}, // 0x39 - '9'
+ {0x00, 0x00, 0x04, 0x00, 0x04, 0x00}, // 0x3A - ':'
+ {0x00, 0x00, 0x04, 0x00, 0x06, 0x02}, // 0x3B - ';'
+ {0x08, 0x04, 0x02, 0x04, 0x08, 0x00}, // 0x3C - '<'
+ {0x00, 0x00, 0x0E, 0x00, 0x0E, 0x00}, // 0x3D - '='
+ {0x02, 0x04, 0x08, 0x04, 0x02, 0x00}, // 0x3E - '>'
+ {0x06, 0x08, 0x04, 0x00, 0x04, 0x00}, // 0x3F - '?'
+ {0x0E, 0x0A, 0x0A, 0x02, 0x0E, 0x00}, // 0x40 - '@'
+ {0x04, 0x0A, 0x0E, 0x0A, 0x0A, 0x00}, // 0x41 - 'A'
+ {0x06, 0x0A, 0x06, 0x0A, 0x06, 0x00}, // 0x42 - 'B'
+ {0x0C, 0x02, 0x02, 0x02, 0x0C, 0x00}, // 0x43 - 'C'
+ {0x06, 0x0A, 0x0A, 0x0A, 0x06, 0x00}, // 0x44 - 'D'
+ {0x0E, 0x02, 0x06, 0x02, 0x0E, 0x00}, // 0x45 - 'E'
+ {0x0E, 0x02, 0x06, 0x02, 0x02, 0x00}, // 0x46 - 'F'
+ {0x0C, 0x02, 0x0A, 0x0A, 0x0C, 0x00}, // 0x47 - 'G'
+ {0x0A, 0x0A, 0x0E, 0x0A, 0x0A, 0x00}, // 0x48 - 'H'
+ {0x0E, 0x04, 0x04, 0x04, 0x0E, 0x00}, // 0x49 - 'I'
+ {0x08, 0x08, 0x08, 0x0A, 0x04, 0x00}, // 0x4A - 'J'
+ {0x0A, 0x0A, 0x06, 0x0A, 0x0A, 0x00}, // 0x4B - 'K'
+ {0x02, 0x02, 0x02, 0x02, 0x0E, 0x00}, // 0x4C - 'L'
+ {0x0A, 0x0E, 0x0E, 0x0A, 0x0A, 0x00}, // 0x4D - 'M'
+ {0x0A, 0x0E, 0x0A, 0x0A, 0x0A, 0x00}, // 0x4E - 'N'
+ {0x04, 0x0A, 0x0A, 0x0A, 0x04, 0x00}, // 0x4F - 'O'
+ {0x06, 0x0A, 0x06, 0x02, 0x02, 0x00}, // 0x50 - 'P'
+ {0x04, 0x0A, 0x0A, 0x0E, 0x0C, 0x00}, // 0x51 - 'Q'
+ {0x06, 0x0A, 0x06, 0x0A, 0x0A, 0x00}, // 0x52 - 'R'
+ {0x0C, 0x02, 0x0E, 0x08, 0x06, 0x00}, // 0x53 - 'S'
+ {0x0E, 0x04, 0x04, 0x04, 0x04, 0x00}, // 0x54 - 'T'
+ {0x0A, 0x0A, 0x0A, 0x0A, 0x0E, 0x00}, // 0x55 - 'U'
+ {0x0A, 0x0A, 0x0A, 0x0A, 0x04, 0x00}, // 0x56 - 'V'
+ {0x0A, 0x0A, 0x0E, 0x0E, 0x0A, 0x00}, // 0x57 - 'W'
+ {0x0A, 0x0A, 0x04, 0x0A, 0x0A, 0x00}, // 0x58 - 'X'
+ {0x0A, 0x0A, 0x04, 0x04, 0x04, 0x00}, // 0x59 - 'Y'
+ {0x0E, 0x08, 0x04, 0x02, 0x0E, 0x00}, // 0x5A - 'Z'
+ {0x06, 0x02, 0x02, 0x02, 0x06, 0x00}, // 0x5B - '['
+ {0x02, 0x02, 0x04, 0x08, 0x08, 0x00}, // 0x5C - '\'
+ {0x06, 0x04, 0x04, 0x04, 0x06, 0x00}, // 0x5D - ']'
+ {0x04, 0x0A, 0x00, 0x00, 0x00, 0x00}, // 0x5E - '^'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x0F}, // 0x5F - '_'
+ {0x06, 0x04, 0x00, 0x00, 0x00, 0x00}, // 0x60 - '`'
+ {0x00, 0x00, 0x0C, 0x0A, 0x0E, 0x00}, // 0x61 - 'a'
+ {0x02, 0x02, 0x06, 0x0A, 0x06, 0x00}, // 0x62 - 'b'
+ {0x00, 0x00, 0x0C, 0x02, 0x0C, 0x00}, // 0x63 - 'c'
+ {0x08, 0x08, 0x0C, 0x0A, 0x0C, 0x00}, // 0x64 - 'd'
+ {0x00, 0x00, 0x0E, 0x06, 0x0C, 0x00}, // 0x65 - 'e'
+ {0x08, 0x04, 0x0E, 0x04, 0x04, 0x00}, // 0x66 - 'f'
+ {0x00, 0x00, 0x0E, 0x0A, 0x08, 0x0E}, // 0x67 - 'g'
+ {0x02, 0x02, 0x06, 0x0A, 0x0A, 0x00}, // 0x68 - 'h'
+ {0x04, 0x00, 0x04, 0x04, 0x04, 0x00}, // 0x69 - 'i'
+ {0x04, 0x00, 0x04, 0x04, 0x04, 0x06}, // 0x6A - 'j'
+ {0x02, 0x02, 0x0A, 0x06, 0x0A, 0x00}, // 0x6B - 'k'
+ {0x04, 0x04, 0x04, 0x04, 0x04, 0x00}, // 0x6C - 'l'
+ {0x00, 0x00, 0x0E, 0x0E, 0x0A, 0x00}, // 0x6D - 'm'
+ {0x00, 0x00, 0x06, 0x0A, 0x0A, 0x00}, // 0x6E - 'n'
+ {0x00, 0x00, 0x04, 0x0A, 0x04, 0x00}, // 0x6F - 'o'
+ {0x00, 0x00, 0x06, 0x0A, 0x06, 0x02}, // 0x70 - 'p'
+ {0x00, 0x00, 0x0C, 0x0A, 0x0C, 0x08}, // 0x71 - 'q'
+ {0x00, 0x00, 0x06, 0x02, 0x02, 0x00}, // 0x72 - 'r'
+ {0x00, 0x00, 0x0C, 0x04, 0x06, 0x00}, // 0x73 - 's'
+ {0x00, 0x04, 0x0E, 0x04, 0x0C, 0x00}, // 0x74 - 't'
+ {0x00, 0x00, 0x0A, 0x0A, 0x0E, 0x00}, // 0x75 - 'u'
+ {0x00, 0x00, 0x0A, 0x0A, 0x04, 0x00}, // 0x76 - 'v'
+ {0x00, 0x00, 0x0A, 0x0E, 0x0E, 0x00}, // 0x77 - 'w'
+ {0x00, 0x00, 0x0A, 0x04, 0x0A, 0x00}, // 0x78 - 'x'
+ {0x00, 0x00, 0x0A, 0x0A, 0x04, 0x02}, // 0x79 - 'y'
+ {0x00, 0x00, 0x06, 0x04, 0x0C, 0x00}, // 0x7A - 'z'
+ {0x0C, 0x04, 0x06, 0x04, 0x0C, 0x00}, // 0x7B - '{'
+ {0x04, 0x04, 0x04, 0x04, 0x04, 0x00}, // 0x7C - '|'
+ {0x06, 0x04, 0x0C, 0x04, 0x06, 0x00}, // 0x7D - '}'
+ {0x0A, 0x05, 0x00, 0x00, 0x00, 0x00}, // 0x7E - '~'
+ {0x00, 0x04, 0x0A, 0x0E, 0x00, 0x00}, // 0x7F - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x80 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x81 - '�'
+ {0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, // 0x82 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x83 - '�'
+ {0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00}, // 0x84 - '�'
+ {0x00, 0x00, 0x04, 0x00, 0x04, 0x00}, // 0x85 - '�'
+ {0x04, 0x04, 0x0F, 0x04, 0x04, 0x04}, // 0x86 - '�'
+ {0x04, 0x0F, 0x00, 0x0F, 0x04, 0x04}, // 0x87 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88 - '�'
+ {0x02, 0x08, 0x04, 0x02, 0x08, 0x00}, // 0x89 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A - '�'
+ {0x08, 0x04, 0x02, 0x04, 0x08, 0x00}, // 0x8B - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 - '�'
+ {0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, // 0x91 - '�'
+ {0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, // 0x92 - '�'
+ {0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00}, // 0x93 - '�'
+ {0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00}, // 0x94 - '�'
+ {0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, // 0x95 - '�'
+ {0x00, 0x00, 0x0E, 0x00, 0x00, 0x00}, // 0x96 - '�'
+ {0x00, 0x00, 0x0E, 0x00, 0x00, 0x00}, // 0x97 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 - '�'
+ {0x0E, 0x04, 0x04, 0x04, 0x04, 0x00}, // 0x99 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A - '�'
+ {0x02, 0x04, 0x08, 0x04, 0x02, 0x00}, // 0x9B - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 - '�'
+ {0x07, 0x05, 0x07, 0x04, 0x03, 0x00}, // 0xA1 - '�'
+ {0x00, 0x02, 0x05, 0x05, 0x02, 0x01}, // 0xA2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 - '�'
+ {0x00, 0x07, 0x05, 0x05, 0x07, 0x00}, // 0xA4 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA5 - '�'
+ {0x04, 0x04, 0x04, 0x04, 0x04, 0x04}, // 0xA6 - '�'
+ {0x0C, 0x06, 0x0A, 0x0C, 0x06, 0x00}, // 0xA7 - '�'
+ {0x07, 0x01, 0x03, 0x01, 0x07, 0x00}, // 0xA8 - '�'
+ {0x00, 0x00, 0x0C, 0x02, 0x0C, 0x00}, // 0xA9 - '�'
+ {0x06, 0x01, 0x07, 0x01, 0x06, 0x00}, // 0xAA - '�'
+ {0x08, 0x04, 0x02, 0x04, 0x08, 0x00}, // 0xAB - '�'
+ {0x00, 0x00, 0x07, 0x04, 0x04, 0x04}, // 0xAC - '�'
+ {0x00, 0x00, 0x0E, 0x00, 0x00, 0x00}, // 0xAD - '�'
+ {0x06, 0x0A, 0x06, 0x0A, 0x0A, 0x00}, // 0xAE - '�'
+ {0x05, 0x02, 0x02, 0x02, 0x02, 0x00}, // 0xAF - '�'
+ {0x04, 0x0A, 0x04, 0x00, 0x00, 0x00}, // 0xB0 - '�'
+ {0x00, 0x04, 0x0E, 0x04, 0x00, 0x00}, // 0xB1 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 - '�'
+ {0x00, 0x00, 0x05, 0x07, 0x04, 0x00}, // 0xB5 - '�'
+ {0x0E, 0x0B, 0x0B, 0x0A, 0x0A, 0x00}, // 0xB6 - '�'
+ {0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, // 0xB7 - '�'
+ {0x05, 0x00, 0x07, 0x03, 0x06, 0x00}, // 0xB8 - '�'
+ {0x05, 0x07, 0x07, 0x07, 0x05, 0x00}, // 0xB9 - '�'
+ {0x00, 0x00, 0x06, 0x03, 0x06, 0x00}, // 0xBA - '�'
+ {0x02, 0x04, 0x08, 0x04, 0x02, 0x00}, // 0xBB - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE - '�'
+ {0x00, 0x00, 0x05, 0x02, 0x02, 0x00}, // 0xBF - '�'
+ {0x02, 0x05, 0x07, 0x05, 0x05, 0x00}, // 0xC0 - '�'
+ {0x07, 0x01, 0x03, 0x05, 0x03, 0x00}, // 0xC1 - '�'
+ {0x03, 0x05, 0x03, 0x05, 0x03, 0x00}, // 0xC2 - '�'
+ {0x07, 0x01, 0x01, 0x01, 0x01, 0x00}, // 0xC3 - '�'
+ {0x02, 0x02, 0x02, 0x07, 0x05, 0x00}, // 0xC4 - '�'
+ {0x07, 0x01, 0x03, 0x01, 0x07, 0x00}, // 0xC5 - '�'
+ {0x05, 0x07, 0x02, 0x07, 0x05, 0x00}, // 0xC6 - '�'
+ {0x07, 0x04, 0x06, 0x04, 0x07, 0x00}, // 0xC7 - '�'
+ {0x05, 0x05, 0x07, 0x07, 0x05, 0x00}, // 0xC8 - '�'
+ {0x07, 0x05, 0x07, 0x07, 0x05, 0x00}, // 0xC9 - '�'
+ {0x05, 0x03, 0x03, 0x05, 0x05, 0x00}, // 0xCA - '�'
+ {0x06, 0x05, 0x05, 0x05, 0x05, 0x00}, // 0xCB - '�'
+ {0x05, 0x07, 0x05, 0x05, 0x05, 0x00}, // 0xCC - '�'
+ {0x05, 0x05, 0x07, 0x05, 0x05, 0x00}, // 0xCD - '�'
+ {0x02, 0x05, 0x05, 0x05, 0x02, 0x00}, // 0xCE - '�'
+ {0x07, 0x05, 0x05, 0x05, 0x05, 0x00}, // 0xCF - '�'
+ {0x03, 0x05, 0x03, 0x01, 0x01, 0x00}, // 0xD0 - '�'
+ {0x06, 0x01, 0x01, 0x01, 0x06, 0x00}, // 0xD1 - '�'
+ {0x07, 0x02, 0x02, 0x02, 0x02, 0x00}, // 0xD2 - '�'
+ {0x05, 0x05, 0x07, 0x04, 0x03, 0x00}, // 0xD3 - '�'
+ {0x02, 0x07, 0x05, 0x07, 0x02, 0x00}, // 0xD4 - '�'
+ {0x05, 0x05, 0x02, 0x05, 0x05, 0x00}, // 0xD5 - '�'
+ {0x05, 0x05, 0x05, 0x05, 0x0F, 0x08}, // 0xD6 - '�'
+ {0x05, 0x05, 0x07, 0x04, 0x04, 0x00}, // 0xD7 - '�'
+ {0x05, 0x05, 0x07, 0x07, 0x07, 0x00}, // 0xD8 - '�'
+ {0x05, 0x05, 0x07, 0x07, 0x0F, 0x08}, // 0xD9 - '�'
+ {0x03, 0x02, 0x06, 0x06, 0x06, 0x00}, // 0xDA - '�'
+ {0x05, 0x05, 0x07, 0x05, 0x07, 0x00}, // 0xDB - '�'
+ {0x01, 0x01, 0x03, 0x05, 0x03, 0x00}, // 0xDC - '�'
+ {0x03, 0x04, 0x06, 0x04, 0x03, 0x00}, // 0xDD - '�'
+ {0x05, 0x0F, 0x0B, 0x0F, 0x05, 0x00}, // 0xDE - '�'
+ {0x06, 0x05, 0x06, 0x05, 0x05, 0x00}, // 0xDF - '�'
+ {0x00, 0x00, 0x06, 0x05, 0x06, 0x00}, // 0xE0 - '�'
+ {0x00, 0x00, 0x07, 0x03, 0x07, 0x00}, // 0xE1 - '�'
+ {0x00, 0x00, 0x03, 0x07, 0x07, 0x00}, // 0xE2 - '�'
+ {0x00, 0x00, 0x07, 0x01, 0x01, 0x00}, // 0xE3 - '�'
+ {0x00, 0x00, 0x02, 0x07, 0x05, 0x00}, // 0xE4 - '�'
+ {0x00, 0x00, 0x07, 0x03, 0x06, 0x00}, // 0xE5 - '�'
+ {0x00, 0x00, 0x07, 0x02, 0x07, 0x00}, // 0xE6 - '�'
+ {0x00, 0x00, 0x07, 0x06, 0x07, 0x00}, // 0xE7 - '�'
+ {0x00, 0x00, 0x05, 0x07, 0x05, 0x00}, // 0xE8 - '�'
+ {0x02, 0x00, 0x05, 0x07, 0x05, 0x00}, // 0xE9 - '�'
+ {0x00, 0x00, 0x05, 0x03, 0x05, 0x00}, // 0xEA - '�'
+ {0x00, 0x00, 0x06, 0x05, 0x05, 0x00}, // 0xEB - '�'
+ {0x00, 0x00, 0x05, 0x07, 0x07, 0x00}, // 0xEC - '�'
+ {0x00, 0x00, 0x05, 0x07, 0x05, 0x00}, // 0xED - '�'
+ {0x00, 0x00, 0x02, 0x05, 0x02, 0x00}, // 0xEE - '�'
+ {0x00, 0x00, 0x07, 0x05, 0x05, 0x00}, // 0xEF - '�'
+ {0x00, 0x00, 0x03, 0x05, 0x03, 0x01}, // 0xF0 - '�'
+ {0x00, 0x00, 0x06, 0x01, 0x06, 0x00}, // 0xF1 - '�'
+ {0x00, 0x00, 0x07, 0x02, 0x02, 0x00}, // 0xF2 - '�'
+ {0x00, 0x00, 0x05, 0x05, 0x02, 0x01}, // 0xF3 - '�'
+ {0x00, 0x00, 0x07, 0x05, 0x07, 0x02}, // 0xF4 - '�'
+ {0x00, 0x00, 0x05, 0x02, 0x05, 0x00}, // 0xF5 - '�'
+ {0x00, 0x00, 0x05, 0x05, 0x0F, 0x08}, // 0xF6 - '�'
+ {0x00, 0x00, 0x05, 0x07, 0x04, 0x00}, // 0xF7 - '�'
+ {0x00, 0x00, 0x05, 0x07, 0x07, 0x00}, // 0xF8 - '�'
+ {0x00, 0x00, 0x05, 0x07, 0x0F, 0x08}, // 0xF9 - '�'
+ {0x00, 0x00, 0x03, 0x06, 0x06, 0x00}, // 0xFA - '�'
+ {0x00, 0x00, 0x05, 0x07, 0x07, 0x00}, // 0xFB - '�'
+ {0x00, 0x00, 0x01, 0x07, 0x07, 0x00}, // 0xFC - '�'
+ {0x00, 0x00, 0x03, 0x06, 0x03, 0x00}, // 0xFD - '�'
+ {0x00, 0x00, 0x05, 0x0F, 0x05, 0x00}, // 0xFE - '�'
+ {0x00, 0x00, 0x07, 0x06, 0x05, 0x00} // 0xFF - '�'
+};
+
+const unsigned char font6x8[256][8] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 - ' '
+ {0x1C, 0x22, 0x36, 0x22, 0x2A, 0x22, 0x1C, 0x00}, // 0x01 - ''
+ {0x1C, 0x3E, 0x2A, 0x3E, 0x22, 0x3E, 0x1C, 0x00}, // 0x02 - ''
+ {0x00, 0x14, 0x3E, 0x3E, 0x3E, 0x1C, 0x08, 0x00}, // 0x03 - ''
+ {0x00, 0x08, 0x1C, 0x3E, 0x3E, 0x1C, 0x08, 0x00}, // 0x04 - ''
+ {0x08, 0x1C, 0x1C, 0x08, 0x3E, 0x3E, 0x08, 0x00}, // 0x05 - ''
+ {0x00, 0x08, 0x1C, 0x3E, 0x3E, 0x08, 0x1C, 0x00}, // 0x06 - ''
+ {0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00}, // 0x07 - ''
+ {0x3F, 0x3F, 0x3F, 0x33, 0x33, 0x3F, 0x3F, 0x3F}, // 0x08 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 - ' '
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A - ' '
+ {0x00, 0x38, 0x30, 0x2C, 0x12, 0x12, 0x0C, 0x00}, // 0x0B - ' '
+ {0x1C, 0x22, 0x22, 0x1C, 0x08, 0x1C, 0x08, 0x00}, // 0x0C - ' '
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D - ' '
+ {0x30, 0x2C, 0x34, 0x2C, 0x34, 0x36, 0x06, 0x00}, // 0x0E - ''
+ {0x00, 0x2A, 0x1C, 0x36, 0x1C, 0x2A, 0x00, 0x00}, // 0x0F - ''
+ {0x04, 0x0C, 0x1C, 0x3C, 0x1C, 0x0C, 0x04, 0x00}, // 0x10 - ''
+ {0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00}, // 0x11 - ''
+ {0x08, 0x1C, 0x3E, 0x08, 0x3E, 0x1C, 0x08, 0x00}, // 0x12 - ''
+ {0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x14, 0x00}, // 0x13 - ''
+ {0x3C, 0x2A, 0x2A, 0x2C, 0x28, 0x28, 0x28, 0x00}, // 0x14 - ''
+ {0x1C, 0x22, 0x0C, 0x14, 0x18, 0x22, 0x1C, 0x00}, // 0x15 - ''
+ {0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00}, // 0x16 - ''
+ {0x08, 0x1C, 0x3E, 0x08, 0x3E, 0x1C, 0x08, 0x1C}, // 0x17 - ''
+ {0x08, 0x1C, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x00}, // 0x18 - ''
+ {0x08, 0x08, 0x08, 0x08, 0x3E, 0x1C, 0x08, 0x00}, // 0x19 - ''
+ {0x00, 0x08, 0x18, 0x3E, 0x18, 0x08, 0x00, 0x00}, // 0x1A - ' '
+ {0x00, 0x08, 0x0C, 0x3E, 0x0C, 0x08, 0x00, 0x00}, // 0x1B - ''
+ {0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x3E, 0x00}, // 0x1C - ''
+ {0x00, 0x14, 0x14, 0x3E, 0x14, 0x14, 0x00, 0x00}, // 0x1D - ''
+ {0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x3E, 0x00, 0x00}, // 0x1E - ''
+ {0x3E, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x00, 0x00}, // 0x1F - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 - ' '
+ {0x08, 0x1C, 0x1C, 0x08, 0x08, 0x00, 0x08, 0x00}, // 0x21 - '!'
+ {0x36, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x22 - '"'
+ {0x00, 0x14, 0x3E, 0x14, 0x14, 0x3E, 0x14, 0x00}, // 0x23 - '#'
+ {0x04, 0x1C, 0x02, 0x0C, 0x10, 0x0E, 0x08, 0x00}, // 0x24 - '$'
+ {0x26, 0x26, 0x10, 0x08, 0x04, 0x32, 0x32, 0x00}, // 0x25 - '%'
+ {0x04, 0x0A, 0x0A, 0x04, 0x2A, 0x12, 0x2C, 0x00}, // 0x26 - '&'
+ {0x0C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x27 - '''
+ {0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x00}, // 0x28 - '('
+ {0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x00}, // 0x29 - ')'
+ {0x00, 0x14, 0x1C, 0x3E, 0x1C, 0x14, 0x00, 0x00}, // 0x2A - '*'
+ {0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00}, // 0x2B - '+'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x04}, // 0x2C - ','
+ {0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00}, // 0x2D - '-'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // 0x2E - '.'
+ {0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00}, // 0x2F - '/'
+ {0x1C, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x1C, 0x00}, // 0x30 - '0'
+ {0x08, 0x0C, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00}, // 0x31 - '1'
+ {0x1C, 0x22, 0x20, 0x18, 0x04, 0x02, 0x3E, 0x00}, // 0x32 - '2'
+ {0x1C, 0x22, 0x20, 0x1C, 0x20, 0x22, 0x1C, 0x00}, // 0x33 - '3'
+ {0x10, 0x18, 0x14, 0x12, 0x3E, 0x10, 0x10, 0x00}, // 0x34 - '4'
+ {0x3E, 0x02, 0x02, 0x1E, 0x20, 0x22, 0x1C, 0x00}, // 0x35 - '5'
+ {0x18, 0x04, 0x02, 0x1E, 0x22, 0x22, 0x1C, 0x00}, // 0x36 - '6'
+ {0x3E, 0x20, 0x10, 0x08, 0x04, 0x04, 0x04, 0x00}, // 0x37 - '7'
+ {0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00}, // 0x38 - '8'
+ {0x1C, 0x22, 0x22, 0x3C, 0x20, 0x10, 0x0C, 0x00}, // 0x39 - '9'
+ {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00}, // 0x3A - ':'
+ {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x04}, // 0x3B - ';'
+ {0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00}, // 0x3C - '<'
+ {0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00}, // 0x3D - '='
+ {0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00}, // 0x3E - '>'
+ {0x1C, 0x22, 0x20, 0x18, 0x08, 0x00, 0x08, 0x00}, // 0x3F - '?'
+ {0x1C, 0x22, 0x3A, 0x2A, 0x3A, 0x02, 0x1C, 0x00}, // 0x40 - '@'
+ {0x1C, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00}, // 0x41 - 'A'
+ {0x1E, 0x22, 0x22, 0x1E, 0x22, 0x22, 0x1E, 0x00}, // 0x42 - 'B'
+ {0x1C, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00}, // 0x43 - 'C'
+ {0x1E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x00}, // 0x44 - 'D'
+ {0x3E, 0x02, 0x02, 0x1E, 0x02, 0x02, 0x3E, 0x00}, // 0x45 - 'E'
+ {0x3E, 0x02, 0x02, 0x1E, 0x02, 0x02, 0x02, 0x00}, // 0x46 - 'F'
+ {0x1C, 0x22, 0x02, 0x3A, 0x22, 0x22, 0x3C, 0x00}, // 0x47 - 'G'
+ {0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00}, // 0x48 - 'H'
+ {0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00}, // 0x49 - 'I'
+ {0x20, 0x20, 0x20, 0x20, 0x22, 0x22, 0x1C, 0x00}, // 0x4A - 'J'
+ {0x22, 0x12, 0x0A, 0x06, 0x0A, 0x12, 0x22, 0x00}, // 0x4B - 'K'
+ {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3E, 0x00}, // 0x4C - 'L'
+ {0x22, 0x36, 0x2A, 0x22, 0x22, 0x22, 0x22, 0x00}, // 0x4D - 'M'
+ {0x22, 0x26, 0x2A, 0x32, 0x22, 0x22, 0x22, 0x00}, // 0x4E - 'N'
+ {0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00}, // 0x4F - 'O'
+ {0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x02, 0x00}, // 0x50 - 'P'
+ {0x1C, 0x22, 0x22, 0x22, 0x2A, 0x12, 0x2C, 0x00}, // 0x51 - 'Q'
+ {0x1E, 0x22, 0x22, 0x1E, 0x12, 0x22, 0x22, 0x00}, // 0x52 - 'R'
+ {0x1C, 0x22, 0x02, 0x1C, 0x20, 0x22, 0x1C, 0x00}, // 0x53 - 'S'
+ {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}, // 0x54 - 'T'
+ {0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00}, // 0x55 - 'U'
+ {0x22, 0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00}, // 0x56 - 'V'
+ {0x22, 0x22, 0x2A, 0x2A, 0x2A, 0x2A, 0x14, 0x00}, // 0x57 - 'W'
+ {0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00}, // 0x58 - 'X'
+ {0x22, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x00}, // 0x59 - 'Y'
+ {0x1E, 0x10, 0x08, 0x04, 0x02, 0x02, 0x1E, 0x00}, // 0x5A - 'Z'
+ {0x1C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1C, 0x00}, // 0x5B - '['
+ {0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00}, // 0x5C - '\'
+ {0x1C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00}, // 0x5D - ']'
+ {0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5E - '^'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00}, // 0x5F - '_'
+ {0x0C, 0x0C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x60 - '`'
+ {0x00, 0x00, 0x1C, 0x20, 0x3C, 0x22, 0x3C, 0x00}, // 0x61 - 'a'
+ {0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00}, // 0x62 - 'b'
+ {0x00, 0x00, 0x1C, 0x22, 0x02, 0x22, 0x1C, 0x00}, // 0x63 - 'c'
+ {0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00}, // 0x64 - 'd'
+ {0x00, 0x00, 0x1C, 0x22, 0x1E, 0x02, 0x1C, 0x00}, // 0x65 - 'e'
+ {0x18, 0x04, 0x04, 0x1E, 0x04, 0x04, 0x04, 0x00}, // 0x66 - 'f'
+ {0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x1C}, // 0x67 - 'g'
+ {0x02, 0x02, 0x0E, 0x12, 0x12, 0x12, 0x12, 0x00}, // 0x68 - 'h'
+ {0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00}, // 0x69 - 'i'
+ {0x10, 0x00, 0x18, 0x10, 0x10, 0x10, 0x12, 0x0C}, // 0x6A - 'j'
+ {0x02, 0x02, 0x12, 0x0A, 0x06, 0x0A, 0x12, 0x00}, // 0x6B - 'k'
+ {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00}, // 0x6C - 'l'
+ {0x00, 0x00, 0x16, 0x2A, 0x2A, 0x22, 0x22, 0x00}, // 0x6D - 'm'
+ {0x00, 0x00, 0x0E, 0x12, 0x12, 0x12, 0x12, 0x00}, // 0x6E - 'n'
+ {0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00}, // 0x6F - 'o'
+ {0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02}, // 0x70 - 'p'
+ {0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20}, // 0x71 - 'q'
+ {0x00, 0x00, 0x1A, 0x24, 0x04, 0x04, 0x0E, 0x00}, // 0x72 - 'r'
+ {0x00, 0x00, 0x1C, 0x02, 0x1C, 0x20, 0x1C, 0x00}, // 0x73 - 's'
+ {0x00, 0x04, 0x1E, 0x04, 0x04, 0x14, 0x08, 0x00}, // 0x74 - 't'
+ {0x00, 0x00, 0x12, 0x12, 0x12, 0x1A, 0x14, 0x00}, // 0x75 - 'u'
+ {0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00}, // 0x76 - 'v'
+ {0x00, 0x00, 0x22, 0x22, 0x2A, 0x3E, 0x14, 0x00}, // 0x77 - 'w'
+ {0x00, 0x00, 0x12, 0x12, 0x0C, 0x12, 0x12, 0x00}, // 0x78 - 'x'
+ {0x00, 0x00, 0x12, 0x12, 0x12, 0x1C, 0x08, 0x06}, // 0x79 - 'y'
+ {0x00, 0x00, 0x1E, 0x10, 0x0C, 0x02, 0x1E, 0x00}, // 0x7A - 'z'
+ {0x18, 0x04, 0x04, 0x06, 0x04, 0x04, 0x18, 0x00}, // 0x7B - '{'
+ {0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00}, // 0x7C - '|'
+ {0x0C, 0x10, 0x10, 0x30, 0x10, 0x10, 0x0C, 0x00}, // 0x7D - '}'
+ {0x14, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7E - '~'
+ {0x08, 0x1C, 0x36, 0x22, 0x22, 0x3E, 0x00, 0x00}, // 0x7F - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x80 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x81 - '�'
+ {0x0C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x82 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x83 - '�'
+ {0x36, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x84 - '�'
+ {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00}, // 0x85 - '�'
+ {0x08, 0x08, 0x08, 0x3F, 0x08, 0x08, 0x08, 0x08}, // 0x86 - '�'
+ {0x08, 0x3F, 0x08, 0x3F, 0x08, 0x08, 0x08, 0x08}, // 0x87 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88 - '�'
+ {0x26, 0x26, 0x10, 0x08, 0x04, 0x32, 0x32, 0x00}, // 0x89 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A - '�'
+ {0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00}, // 0x8B - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 - '�'
+ {0x0C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91 - '�'
+ {0x0C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x92 - '�'
+ {0x36, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x93 - '�'
+ {0x36, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94 - '�'
+ {0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00}, // 0x95 - '�'
+ {0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00}, // 0x96 - '�'
+ {0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00}, // 0x97 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 - '�'
+ {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}, // 0x99 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A - '�'
+ {0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00}, // 0x9B - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 - '�'
+ {0x2A, 0x2A, 0x22, 0x3C, 0x20, 0x22, 0x1C, 0x00}, // 0xA1 - '�'
+ {0x0C, 0x00, 0x12, 0x12, 0x12, 0x1C, 0x08, 0x06}, // 0xA2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 - '�'
+ {0x00, 0x33, 0x1E, 0x33, 0x1E, 0x33, 0x00, 0x00}, // 0xA4 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA5 - '�'
+ {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, // 0xA6 - '�'
+ {0x1C, 0x22, 0x0C, 0x14, 0x18, 0x22, 0x1C, 0x00}, // 0xA7 - '�'
+ {0x14, 0x3E, 0x02, 0x1E, 0x02, 0x02, 0x3E, 0x00}, // 0xA8 - '�'
+ {0x00, 0x00, 0x1C, 0x22, 0x02, 0x22, 0x1C, 0x00}, // 0xA9 - '�'
+ {0x1C, 0x22, 0x02, 0x0E, 0x02, 0x22, 0x1C, 0x00}, // 0xAA - '�'
+ {0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00}, // 0xAB - '�'
+ {0x00, 0x00, 0x00, 0x0F, 0x08, 0x08, 0x08, 0x08}, // 0xAC - '�'
+ {0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00}, // 0xAD - '�'
+ {0x1E, 0x22, 0x22, 0x1E, 0x12, 0x22, 0x22, 0x00}, // 0xAE - '�'
+ {0x22, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00}, // 0xAF - '�'
+ {0x0C, 0x12, 0x12, 0x0C, 0x00, 0x00, 0x00, 0x00}, // 0xB0 - '�'
+ {0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00}, // 0xB1 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 - '�'
+ {0x00, 0x00, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x00}, // 0xB5 - '�'
+ {0x3C, 0x2A, 0x2A, 0x2C, 0x28, 0x28, 0x28, 0x00}, // 0xB6 - '�'
+ {0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}, // 0xB7 - '�'
+ {0x14, 0x00, 0x1C, 0x22, 0x1E, 0x02, 0x1C, 0x00}, // 0xB8 - '�'
+ {0x39, 0x3B, 0x0B, 0x0D, 0x3D, 0x09, 0x09, 0x00}, // 0xB9 - '�'
+ {0x00, 0x00, 0x1C, 0x22, 0x0E, 0x22, 0x1C, 0x00}, // 0xBA - '�'
+ {0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00}, // 0xBB - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE - '�'
+ {0x14, 0x00, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00}, // 0xBF - '�'
+ {0x1C, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00}, // 0xC0 - '�'
+ {0x3E, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x1E, 0x00}, // 0xC1 - '�'
+ {0x1E, 0x22, 0x22, 0x1E, 0x22, 0x22, 0x1E, 0x00}, // 0xC2 - '�'
+ {0x3E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00}, // 0xC3 - '�'
+ {0x1C, 0x12, 0x12, 0x12, 0x12, 0x3F, 0x21, 0x00}, // 0xC4 - '�'
+ {0x3E, 0x02, 0x02, 0x1E, 0x02, 0x02, 0x3E, 0x00}, // 0xC5 - '�'
+ {0x2A, 0x2A, 0x2A, 0x1C, 0x2A, 0x2A, 0x2A, 0x00}, // 0xC6 - '�'
+ {0x0E, 0x11, 0x10, 0x0E, 0x10, 0x11, 0x0E, 0x00}, // 0xC7 - '�'
+ {0x22, 0x22, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x00}, // 0xC8 - '�'
+ {0x2A, 0x2A, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x00}, // 0xC9 - '�'
+ {0x22, 0x12, 0x0A, 0x06, 0x0A, 0x12, 0x22, 0x00}, // 0xCA - '�'
+ {0x38, 0x24, 0x24, 0x24, 0x24, 0x24, 0x26, 0x00}, // 0xCB - '�'
+ {0x22, 0x36, 0x2A, 0x22, 0x22, 0x22, 0x22, 0x00}, // 0xCC - '�'
+ {0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00}, // 0xCD - '�'
+ {0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00}, // 0xCE - '�'
+ {0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00}, // 0xCF - '�'
+ {0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x02, 0x00}, // 0xD0 - '�'
+ {0x1C, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00}, // 0xD1 - '�'
+ {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}, // 0xD2 - '�'
+ {0x22, 0x22, 0x22, 0x3C, 0x20, 0x22, 0x1C, 0x00}, // 0xD3 - '�'
+ {0x1C, 0x2A, 0x2A, 0x2A, 0x1C, 0x08, 0x08, 0x00}, // 0xD4 - '�'
+ {0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00}, // 0xD5 - '�'
+ {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3E, 0x20}, // 0xD6 - '�'
+ {0x22, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00}, // 0xD7 - '�'
+ {0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x3E, 0x00}, // 0xD8 - '�'
+ {0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x3E, 0x20}, // 0xD9 - '�'
+ {0x07, 0x05, 0x04, 0x1C, 0x24, 0x24, 0x1C, 0x00}, // 0xDA - '�'
+ {0x22, 0x22, 0x22, 0x2E, 0x32, 0x32, 0x2E, 0x00}, // 0xDB - '�'
+ {0x02, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x1E, 0x00}, // 0xDC - '�'
+ {0x1C, 0x22, 0x20, 0x38, 0x20, 0x22, 0x1C, 0x00}, // 0xDD - '�'
+ {0x12, 0x2A, 0x2A, 0x2E, 0x2A, 0x2A, 0x12, 0x00}, // 0xDE - '�'
+ {0x3C, 0x22, 0x22, 0x3C, 0x24, 0x22, 0x22, 0x00}, // 0xDF - '�'
+ {0x00, 0x00, 0x1C, 0x20, 0x3C, 0x22, 0x3C, 0x00}, // 0xE0 - '�'
+ {0x20, 0x1C, 0x02, 0x1E, 0x22, 0x22, 0x1C, 0x00}, // 0xE1 - '�'
+ {0x00, 0x00, 0x1E, 0x22, 0x1E, 0x22, 0x1E, 0x00}, // 0xE2 - '�'
+ {0x00, 0x00, 0x1E, 0x12, 0x02, 0x02, 0x02, 0x00}, // 0xE3 - '�'
+ {0x00, 0x00, 0x1C, 0x12, 0x12, 0x3F, 0x21, 0x00}, // 0xE4 - '�'
+ {0x00, 0x00, 0x1C, 0x22, 0x1E, 0x02, 0x1C, 0x00}, // 0xE5 - '�'
+ {0x00, 0x00, 0x2A, 0x2A, 0x1C, 0x2A, 0x2A, 0x00}, // 0xE6 - '�'
+ {0x00, 0x00, 0x1C, 0x22, 0x18, 0x22, 0x1C, 0x00}, // 0xE7 - '�'
+ {0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x00}, // 0xE8 - '�'
+ {0x00, 0x18, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x00}, // 0xE9 - '�'
+ {0x00, 0x00, 0x12, 0x0A, 0x06, 0x0A, 0x12, 0x00}, // 0xEA - '�'
+ {0x00, 0x00, 0x1C, 0x12, 0x12, 0x12, 0x11, 0x00}, // 0xEB - '�'
+ {0x00, 0x00, 0x22, 0x36, 0x2A, 0x22, 0x22, 0x00}, // 0xEC - '�'
+ {0x00, 0x00, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00}, // 0xED - '�'
+ {0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00}, // 0xEE - '�'
+ {0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x00}, // 0xEF - '�'
+ {0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02}, // 0xF0 - '�'
+ {0x00, 0x00, 0x1C, 0x22, 0x02, 0x22, 0x1C, 0x00}, // 0xF1 - '�'
+ {0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x00}, // 0xF2 - '�'
+ {0x00, 0x00, 0x12, 0x12, 0x12, 0x1C, 0x08, 0x06}, // 0xF3 - '�'
+ {0x00, 0x00, 0x1C, 0x2A, 0x2A, 0x1C, 0x08, 0x00}, // 0xF4 - '�'
+ {0x00, 0x00, 0x12, 0x12, 0x0C, 0x12, 0x12, 0x00}, // 0xF5 - '�'
+ {0x00, 0x00, 0x12, 0x12, 0x12, 0x12, 0x3E, 0x20}, // 0xF6 - '�'
+ {0x00, 0x00, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x00}, // 0xF7 - '�'
+ {0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x3E, 0x00}, // 0xF8 - '�'
+ {0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x2A, 0x3E, 0x20}, // 0xF9 - '�'
+ {0x00, 0x00, 0x07, 0x05, 0x1C, 0x24, 0x1C, 0x00}, // 0xFA - '�'
+ {0x00, 0x00, 0x22, 0x22, 0x2E, 0x32, 0x2E, 0x00}, // 0xFB - '�'
+ {0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x1E, 0x00}, // 0xFC - '�'
+ {0x00, 0x00, 0x1C, 0x22, 0x38, 0x22, 0x1C, 0x00}, // 0xFD - '�'
+ {0x00, 0x00, 0x12, 0x2A, 0x2E, 0x2A, 0x12, 0x00}, // 0xFE - '�'
+ {0x00, 0x00, 0x3C, 0x22, 0x3C, 0x24, 0x22, 0x00} // 0xFF - '�'
+};
+
+const unsigned char font8x8[256][8] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 - ' '
+ {0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E}, // 0x01 - ''
+ {0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E}, // 0x02 - ''
+ {0x36, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00}, // 0x03 - ''
+ {0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00}, // 0x04 - ''
+ {0x1C, 0x3E, 0x1C, 0x7F, 0x7F, 0x6B, 0x08, 0x1C}, // 0x05 - ''
+ {0x08, 0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x08, 0x1C}, // 0x06 - ''
+ {0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00}, // 0x07 - ''
+ {0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF}, // 0x08 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 - ' '
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A - ' '
+ {0xF0, 0xE0, 0xF0, 0xBE, 0x33, 0x33, 0x33, 0x1E}, // 0x0B - ' '
+ {0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18}, // 0x0C - ' '
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D - ' '
+ {0xFE, 0xC6, 0xFE, 0xC6, 0xC6, 0xE6, 0x67, 0x03}, // 0x0E - ''
+ {0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99}, // 0x0F - ''
+ {0x01, 0x07, 0x1F, 0x7F, 0x1F, 0x07, 0x01, 0x00}, // 0x10 - ''
+ {0x40, 0x70, 0x7C, 0x7F, 0x7C, 0x70, 0x40, 0x00}, // 0x11 - ''
+ {0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18}, // 0x12 - ''
+ {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00}, // 0x13 - ''
+ {0xFE, 0xDB, 0xDB, 0xDE, 0xD8, 0xD8, 0xD8, 0x00}, // 0x14 - ''
+ {0x7E, 0xC3, 0x1E, 0x33, 0x33, 0x1E, 0x31, 0x1F}, // 0x15 - ''
+ {0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00}, // 0x16 - ''
+ {0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF}, // 0x17 - ''
+ {0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00}, // 0x18 - ''
+ {0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00}, // 0x19 - ''
+ {0x00, 0x18, 0x30, 0x7F, 0x30, 0x18, 0x00, 0x00}, // 0x1A - ' '
+ {0x00, 0x0C, 0x06, 0x7F, 0x06, 0x0C, 0x00, 0x00}, // 0x1B - ''
+ {0x00, 0x00, 0x03, 0x03, 0x03, 0x7F, 0x00, 0x00}, // 0x1C - ''
+ {0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00}, // 0x1D - ''
+ {0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00}, // 0x1E - ''
+ {0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00}, // 0x1F - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 - ' '
+ {0x0C, 0x1E, 0x1E, 0x0C, 0x0C, 0x00, 0x0C, 0x00}, // 0x21 - '!'
+ {0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x22 - '"'
+ {0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // 0x23 - '#'
+ {0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // 0x24 - '$'
+ {0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // 0x25 - '%'
+ {0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // 0x26 - '&'
+ {0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x27 - '''
+ {0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // 0x28 - '('
+ {0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // 0x29 - ')'
+ {0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // 0x2A - '*'
+ {0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // 0x2B - '+'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0C, 0x06}, // 0x2C - ','
+ {0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // 0x2D - '-'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // 0x2E - '.'
+ {0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // 0x2F - '/'
+ {0x1E, 0x33, 0x3B, 0x3F, 0x37, 0x33, 0x1E, 0x00}, // 0x30 - '0'
+ {0x0C, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // 0x31 - '1'
+ {0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // 0x32 - '2'
+ {0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // 0x33 - '3'
+ {0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x30, 0x00}, // 0x34 - '4'
+ {0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // 0x35 - '5'
+ {0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // 0x36 - '6'
+ {0x3F, 0x33, 0x30, 0x18, 0x0C, 0x06, 0x06, 0x00}, // 0x37 - '7'
+ {0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // 0x38 - '8'
+ {0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // 0x39 - '9'
+ {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00}, // 0x3A - ':'
+ {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0E, 0x0C, 0x06}, // 0x3B - ';'
+ {0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // 0x3C - '<'
+ {0x00, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x00, 0x00}, // 0x3D - '='
+ {0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // 0x3E - '>'
+ {0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // 0x3F - '?'
+ {0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // 0x40 - '@'
+ {0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // 0x41 - 'A'
+ {0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // 0x42 - 'B'
+ {0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // 0x43 - 'C'
+ {0x3F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x3F, 0x00}, // 0x44 - 'D'
+ {0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // 0x45 - 'E'
+ {0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // 0x46 - 'F'
+ {0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // 0x47 - 'G'
+ {0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // 0x48 - 'H'
+ {0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0x49 - 'I'
+ {0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // 0x4A - 'J'
+ {0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // 0x4B - 'K'
+ {0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // 0x4C - 'L'
+ {0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00}, // 0x4D - 'M'
+ {0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // 0x4E - 'N'
+ {0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // 0x4F - 'O'
+ {0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // 0x50 - 'P'
+ {0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // 0x51 - 'Q'
+ {0x3F, 0x66, 0x66, 0x3E, 0x1E, 0x36, 0x67, 0x00}, // 0x52 - 'R'
+ {0x1E, 0x33, 0x07, 0x1C, 0x38, 0x33, 0x1E, 0x00}, // 0x53 - 'S'
+ {0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0x54 - 'T'
+ {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // 0x55 - 'U'
+ {0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // 0x56 - 'V'
+ {0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // 0x57 - 'W'
+ {0x63, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x63, 0x00}, // 0x58 - 'X'
+ {0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // 0x59 - 'Y'
+ {0x7F, 0x33, 0x19, 0x0C, 0x46, 0x63, 0x7F, 0x00}, // 0x5A - 'Z'
+ {0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // 0x5B - '['
+ {0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // 0x5C - '\'
+ {0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // 0x5D - ']'
+ {0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // 0x5E - '^'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00}, // 0x5F - '_'
+ {0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x60 - '`'
+ {0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // 0x61 - 'a'
+ {0x07, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3D, 0x00}, // 0x62 - 'b'
+ {0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // 0x63 - 'c'
+ {0x38, 0x30, 0x30, 0x3E, 0x33, 0x33, 0x6E, 0x00}, // 0x64 - 'd'
+ {0x00, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // 0x65 - 'e'
+ {0x1C, 0x36, 0x06, 0x0F, 0x06, 0x06, 0x0F, 0x00}, // 0x66 - 'f'
+ {0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // 0x67 - 'g'
+ {0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // 0x68 - 'h'
+ {0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0x69 - 'i'
+ {0x18, 0x00, 0x1E, 0x18, 0x18, 0x18, 0x1B, 0x0E}, // 0x6A - 'j'
+ {0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // 0x6B - 'k'
+ {0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0x6C - 'l'
+ {0x00, 0x00, 0x37, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // 0x6D - 'm'
+ {0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // 0x6E - 'n'
+ {0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // 0x6F - 'o'
+ {0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // 0x70 - 'p'
+ {0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // 0x71 - 'q'
+ {0x00, 0x00, 0x1B, 0x36, 0x36, 0x06, 0x0F, 0x00}, // 0x72 - 'r'
+ {0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // 0x73 - 's'
+ {0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // 0x74 - 't'
+ {0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // 0x75 - 'u'
+ {0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // 0x76 - 'v'
+ {0x00, 0x00, 0x63, 0x63, 0x6B, 0x7F, 0x36, 0x00}, // 0x77 - 'w'
+ {0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // 0x78 - 'x'
+ {0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // 0x79 - 'y'
+ {0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // 0x7A - 'z'
+ {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF}, // 0x7B - '{'
+ {0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0xBD, 0x81, 0xFF}, // 0x7C - '|'
+ {0xFF, 0x20, 0x70, 0x7C, 0xFE, 0xFE, 0x7C, 0x00}, // 0x7D - '}'
+ {0x07, 0x00, 0x00, 0x40, 0xFF, 0x40, 0x00, 0x00}, // 0x7E - '~'
+ {0x00, 0xE1, 0xFD, 0xFF, 0xFD, 0x31, 0x10, 0x00}, // 0x7F - ''
+ {0x00, 0xC1, 0xE3, 0xFF, 0x3F, 0x00, 0x00, 0x00}, // 0x80 - '�'
+ {0xF0, 0x08, 0x04, 0x02, 0xE1, 0xC1, 0xE1, 0xC1}, // 0x81 - '�'
+ {0x0F, 0x10, 0x21, 0x71, 0x9F, 0x8F, 0x8F, 0x87}, // 0x82 - '�'
+ {0xC1, 0xE1, 0xFD, 0xF1, 0xDA, 0x0C, 0x08, 0xF0}, // 0x83 - '�'
+ {0x87, 0x8F, 0x8F, 0x8F, 0x4F, 0x20, 0x10, 0x0F}, // 0x84 - '�'
+ {0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00}, // 0x85 - '�'
+ {0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18}, // 0x86 - '�'
+ {0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18}, // 0x87 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88 - '�'
+ {0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // 0x89 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A - '�'
+ {0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // 0x8B - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 - '�'
+ {0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91 - '�'
+ {0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x92 - '�'
+ {0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x93 - '�'
+ {0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94 - '�'
+ {0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00}, // 0x95 - '�'
+ {0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // 0x96 - '�'
+ {0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // 0x97 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 - '�'
+ {0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0x99 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A - '�'
+ {0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // 0x9B - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 - '�'
+ {0x08, 0x63, 0x63, 0x7E, 0x60, 0x63, 0x3E, 0x00}, // 0xA1 - '�'
+ {0x6B, 0x6B, 0x63, 0x63, 0x63, 0x7E, 0x60, 0x3E}, // 0xA2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 - '�'
+ {0x00, 0x63, 0x3E, 0x63, 0x63, 0x3E, 0x63, 0x00}, // 0xA4 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA5 - '�'
+ {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, // 0xA6 - '�'
+ {0x7E, 0xC3, 0x1E, 0x33, 0x33, 0x1E, 0x31, 0x1F}, // 0xA7 - '�'
+ {0x36, 0x7F, 0x46, 0x1E, 0x06, 0x46, 0x7F, 0x00}, // 0xA8 - '�'
+ {0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // 0xA9 - '�'
+ {0x3C, 0x66, 0x03, 0x1F, 0x03, 0x66, 0x3C, 0x00}, // 0xAA - '�'
+ {0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // 0xAB - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18}, // 0xAC - '�'
+ {0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // 0xAD - '�'
+ {0x3F, 0x66, 0x66, 0x3E, 0x1E, 0x36, 0x67, 0x00}, // 0xAE - '�'
+ {0x33, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0xAF - '�'
+ {0x1C, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, // 0xB0 - '�'
+ {0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // 0xB1 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 - '�'
+ {0x00, 0x00, 0x63, 0x63, 0x7E, 0x60, 0x60, 0x00}, // 0xB5 - '�'
+ {0xFE, 0xDB, 0xDB, 0xDE, 0xD8, 0xD8, 0xD8, 0x00}, // 0xB6 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00}, // 0xB7 - '�'
+ {0x33, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // 0xB8 - '�'
+ {0x71, 0x33, 0x37, 0x7F, 0x3B, 0x33, 0x33, 0x00}, // 0xB9 - '�'
+ {0x00, 0x00, 0x3E, 0x63, 0x0F, 0x63, 0x3E, 0x00}, // 0xBA - '�'
+ {0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // 0xBB - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE - '�'
+ {0x33, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0xBF - '�'
+ {0x7C, 0x66, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00}, // 0xC0 - '�'
+ {0x7F, 0x66, 0x06, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // 0xC1 - '�'
+ {0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // 0xC2 - '�'
+ {0x7F, 0x66, 0x06, 0x06, 0x06, 0x06, 0x0F, 0x00}, // 0xC3 - '�'
+ {0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0xFF, 0xC3}, // 0xC4 - '�'
+ {0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // 0xC5 - '�'
+ {0x6B, 0x6B, 0x3E, 0x1C, 0x3E, 0x6B, 0x6B, 0x00}, // 0xC6 - '�'
+ {0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // 0xC7 - '�'
+ {0x63, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x63, 0x00}, // 0xC8 - '�'
+ {0x6B, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x63, 0x00}, // 0xC9 - '�'
+ {0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // 0xCA - '�'
+ {0x78, 0x6E, 0x66, 0x66, 0x66, 0x66, 0x63, 0x00}, // 0xCB - '�'
+ {0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00}, // 0xCC - '�'
+ {0x63, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x00}, // 0xCD - '�'
+ {0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // 0xCE - '�'
+ {0x7F, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00}, // 0xCF - '�'
+ {0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // 0xD0 - '�'
+ {0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // 0xD1 - '�'
+ {0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // 0xD2 - '�'
+ {0x63, 0x63, 0x63, 0x7E, 0x60, 0x63, 0x3E, 0x00}, // 0xD3 - '�'
+ {0x3E, 0x6B, 0x6B, 0x6B, 0x3E, 0x08, 0x1C, 0x00}, // 0xD4 - '�'
+ {0x63, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x63, 0x00}, // 0xD5 - '�'
+ {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x7F, 0x60}, // 0xD6 - '�'
+ {0x63, 0x63, 0x63, 0x7E, 0x60, 0x60, 0x60, 0x00}, // 0xD7 - '�'
+ {0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x00}, // 0xD8 - '�'
+ {0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0xFF, 0xC0}, // 0xD9 - '�'
+ {0x0F, 0x0F, 0x0D, 0x3C, 0x6C, 0x6C, 0x3C, 0x00}, // 0xDA - '�'
+ {0x63, 0x63, 0x63, 0x6F, 0x7B, 0x7B, 0x6F, 0x00}, // 0xDB - '�'
+ {0x0F, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00}, // 0xDC - '�'
+ {0x1E, 0x33, 0x60, 0x7C, 0x60, 0x33, 0x1E, 0x00}, // 0xDD - '�'
+ {0x3B, 0x6B, 0x6B, 0x6F, 0x6B, 0x6B, 0x3B, 0x00}, // 0xDE - '�'
+ {0x7E, 0x63, 0x63, 0x7E, 0x7C, 0x66, 0x63, 0x00}, // 0xDF - '�'
+ {0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // 0xE0 - '�'
+ {0x60, 0x3E, 0x03, 0x3E, 0x63, 0x63, 0x3E, 0x00}, // 0xE1 - '�'
+ {0x00, 0x00, 0x3F, 0x66, 0x3E, 0x66, 0x3F, 0x00}, // 0xE2 - '�'
+ {0x00, 0x00, 0x7F, 0x66, 0x06, 0x06, 0x0F, 0x00}, // 0xE3 - '�'
+ {0x00, 0x00, 0x3C, 0x36, 0x36, 0x36, 0x7F, 0x63}, // 0xE4 - '�'
+ {0x00, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // 0xE5 - '�'
+ {0x00, 0x00, 0x6B, 0x3E, 0x1C, 0x3E, 0x6B, 0x00}, // 0xE6 - '�'
+ {0x00, 0x00, 0x3E, 0x63, 0x38, 0x63, 0x3E, 0x00}, // 0xE7 - '�'
+ {0x00, 0x00, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x00}, // 0xE8 - '�'
+ {0x08, 0x63, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x00}, // 0xE9 - '�'
+ {0x00, 0x00, 0x67, 0x36, 0x1E, 0x36, 0x67, 0x00}, // 0xEA - '�'
+ {0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x67, 0x00}, // 0xEB - '�'
+ {0x00, 0x00, 0x63, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // 0xEC - '�'
+ {0x00, 0x00, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00}, // 0xED - '�'
+ {0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // 0xEE - '�'
+ {0x00, 0x00, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x00}, // 0xEF - '�'
+ {0x00, 0x00, 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // 0xF0 - '�'
+ {0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // 0xF1 - '�'
+ {0x00, 0x00, 0x7E, 0x5A, 0x18, 0x18, 0x3C, 0x00}, // 0xF2 - '�'
+ {0x00, 0x00, 0x63, 0x63, 0x63, 0x7E, 0x60, 0x3E}, // 0xF3 - '�'
+ {0x00, 0x00, 0x3E, 0x6B, 0x6B, 0x3E, 0x08, 0x1C}, // 0xF4 - '�'
+ {0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // 0xF5 - '�'
+ {0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x7F, 0x60}, // 0xF6 - '�'
+ {0x00, 0x00, 0x63, 0x63, 0x7E, 0x60, 0x60, 0x00}, // 0xF7 - '�'
+ {0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x00}, // 0xF8 - '�'
+ {0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0xFF, 0xC0}, // 0xF9 - '�'
+ {0x00, 0x00, 0x0F, 0x0D, 0x3C, 0x6C, 0x3C, 0x00}, // 0xFA - '�'
+ {0x00, 0x00, 0x63, 0x63, 0x6F, 0x7B, 0x6F, 0x00}, // 0xFB - '�'
+ {0x00, 0x00, 0x0F, 0x06, 0x3E, 0x66, 0x3E, 0x00}, // 0xFC - '�'
+ {0x00, 0x00, 0x3E, 0x63, 0x78, 0x63, 0x3E, 0x00}, // 0xFD - '�'
+ {0x00, 0x00, 0x3B, 0x6B, 0x6F, 0x6B, 0x3B, 0x00}, // 0xFE - '�'
+ {0x00, 0x00, 0x7E, 0x63, 0x7E, 0x66, 0x63, 0x00} // 0xFF - '�'
+};
+
+const unsigned char font8x12[256][12] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 - ' '
+ {0x00, 0x7E, 0xC3, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0xC3, 0x7E, 0x00, 0x00}, // 0x01 - ''
+ {0x00, 0x7E, 0xFF, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x00, 0x00}, // 0x02 - ''
+ {0x00, 0x00, 0x22, 0x77, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x00}, // 0x03 - ''
+ {0x00, 0x08, 0x1C, 0x3E, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00}, // 0x04 - ''
+ {0x00, 0x18, 0x3C, 0x3C, 0xFF, 0xE7, 0xE7, 0x18, 0x18, 0x7E, 0x00, 0x00}, // 0x05 - ''
+ {0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x7E, 0x00, 0x00}, // 0x06 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00}, // 0x07 - ''
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x81, 0x81, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF}, // 0x08 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 - ' '
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A - ' '
+ {0x00, 0x7C, 0x70, 0x5C, 0x4E, 0x1F, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x0B - ' '
+ {0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00}, // 0x0C - ' '
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D - ' '
+ {0x00, 0xFE, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xE6, 0xE7, 0x67, 0x03, 0x00}, // 0x0E - ''
+ {0x00, 0x00, 0x18, 0xDB, 0x7E, 0xE7, 0xE7, 0x7E, 0xDB, 0x18, 0x00, 0x00}, // 0x0F - ''
+ {0x00, 0x01, 0x03, 0x07, 0x1F, 0x7F, 0x1F, 0x07, 0x03, 0x01, 0x00, 0x00}, // 0x10 - ''
+ {0x00, 0x40, 0x60, 0x70, 0x7C, 0x7F, 0x7C, 0x70, 0x60, 0x40, 0x00, 0x00}, // 0x11 - ''
+ {0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00}, // 0x12 - ''
+ {0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00}, // 0x13 - ''
+ {0x00, 0xFE, 0xDB, 0xDB, 0xDB, 0xDE, 0xD8, 0xD8, 0xD8, 0xD8, 0x00, 0x00}, // 0x14 - ''
+ {0x00, 0x7E, 0xC6, 0x0C, 0x3C, 0x66, 0x66, 0x3C, 0x30, 0x63, 0x7E, 0x00}, // 0x15 - ''
+ {0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00}, // 0x16 - ''
+ {0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00}, // 0x17 - ''
+ {0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00}, // 0x18 - ''
+ {0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00}, // 0x19 - ''
+ {0x00, 0x00, 0x00, 0x18, 0x30, 0x7F, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00}, // 0x1A - ' '
+ {0x00, 0x00, 0x00, 0x0C, 0x06, 0x7F, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00}, // 0x1B - ''
+ {0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x7F, 0x00, 0x00, 0x00, 0x00}, // 0x1C - ''
+ {0x00, 0x00, 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00}, // 0x1D - ''
+ {0x00, 0x00, 0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x3E, 0x7F, 0x7F, 0x00, 0x00}, // 0x1E - ''
+ {0x00, 0x00, 0x7F, 0x7F, 0x3E, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x00, 0x00}, // 0x1F - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 - ' '
+ {0x00, 0x0C, 0x1E, 0x1E, 0x1E, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00, 0x00}, // 0x21 - '!'
+ {0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x22 - '"'
+ {0x00, 0x36, 0x36, 0x7F, 0x36, 0x36, 0x36, 0x7F, 0x36, 0x36, 0x00, 0x00}, // 0x23 - '#'
+ {0x0C, 0x0C, 0x3E, 0x03, 0x03, 0x1E, 0x30, 0x30, 0x1F, 0x0C, 0x0C, 0x00}, // 0x24 - '$'
+ {0x00, 0x00, 0x00, 0x23, 0x33, 0x18, 0x0C, 0x06, 0x33, 0x31, 0x00, 0x00}, // 0x25 - '%'
+ {0x00, 0x0E, 0x1B, 0x1B, 0x0E, 0x5F, 0x7B, 0x33, 0x3B, 0x6E, 0x00, 0x00}, // 0x26 - '&'
+ {0x00, 0x0C, 0x0C, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x27 - '''
+ {0x00, 0x30, 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x00}, // 0x28 - '('
+ {0x00, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00}, // 0x29 - ')'
+ {0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00}, // 0x2A - '*'
+ {0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, // 0x2B - '+'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x06, 0x00}, // 0x2C - ','
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2D - '-'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00}, // 0x2E - '.'
+ {0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00}, // 0x2F - '/'
+ {0x00, 0x3E, 0x63, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x63, 0x3E, 0x00, 0x00}, // 0x30 - '0'
+ {0x00, 0x08, 0x0C, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00, 0x00}, // 0x31 - '1'
+ {0x00, 0x1E, 0x33, 0x33, 0x30, 0x18, 0x0C, 0x06, 0x33, 0x3F, 0x00, 0x00}, // 0x32 - '2'
+ {0x00, 0x1E, 0x33, 0x30, 0x30, 0x1C, 0x30, 0x30, 0x33, 0x1E, 0x00, 0x00}, // 0x33 - '3'
+ {0x00, 0x30, 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x30, 0x78, 0x00, 0x00}, // 0x34 - '4'
+ {0x00, 0x3F, 0x03, 0x03, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00, 0x00}, // 0x35 - '5'
+ {0x00, 0x1C, 0x06, 0x03, 0x03, 0x1F, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x36 - '6'
+ {0x00, 0x7F, 0x63, 0x63, 0x60, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00, 0x00}, // 0x37 - '7'
+ {0x00, 0x1E, 0x33, 0x33, 0x37, 0x1E, 0x3B, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x38 - '8'
+ {0x00, 0x1E, 0x33, 0x33, 0x33, 0x3E, 0x18, 0x18, 0x0C, 0x0E, 0x00, 0x00}, // 0x39 - '9'
+ {0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x00}, // 0x3A - ':'
+ {0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x1C, 0x1C, 0x18, 0x0C, 0x00}, // 0x3B - ';'
+ {0x00, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x00}, // 0x3C - '<'
+ {0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3D - '='
+ {0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00}, // 0x3E - '>'
+ {0x00, 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00, 0x00}, // 0x3F - '?'
+ {0x00, 0x3E, 0x63, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x03, 0x3E, 0x00, 0x00}, // 0x40 - '@'
+ {0x00, 0x0C, 0x1E, 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0x41 - 'A'
+ {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x66, 0x3F, 0x00, 0x00}, // 0x42 - 'B'
+ {0x00, 0x3C, 0x66, 0x63, 0x03, 0x03, 0x03, 0x63, 0x66, 0x3C, 0x00, 0x00}, // 0x43 - 'C'
+ {0x00, 0x1F, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00, 0x00}, // 0x44 - 'D'
+ {0x00, 0x7F, 0x46, 0x06, 0x26, 0x3E, 0x26, 0x06, 0x46, 0x7F, 0x00, 0x00}, // 0x45 - 'E'
+ {0x00, 0x7F, 0x66, 0x46, 0x26, 0x3E, 0x26, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0x46 - 'F'
+ {0x00, 0x3C, 0x66, 0x63, 0x03, 0x03, 0x73, 0x63, 0x66, 0x7C, 0x00, 0x00}, // 0x47 - 'G'
+ {0x00, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0x48 - 'H'
+ {0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, // 0x49 - 'I'
+ {0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x4A - 'J'
+ {0x00, 0x67, 0x66, 0x36, 0x36, 0x1E, 0x36, 0x36, 0x66, 0x67, 0x00, 0x00}, // 0x4B - 'K'
+ {0x00, 0x0F, 0x06, 0x06, 0x06, 0x06, 0x46, 0x66, 0x66, 0x7F, 0x00, 0x00}, // 0x4C - 'L'
+ {0x00, 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00}, // 0x4D - 'M'
+ {0x00, 0x63, 0x63, 0x67, 0x6F, 0x7F, 0x7B, 0x73, 0x63, 0x63, 0x00, 0x00}, // 0x4E - 'N'
+ {0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00}, // 0x4F - 'O'
+ {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0x50 - 'P'
+ {0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x73, 0x7B, 0x3E, 0x30, 0x78, 0x00}, // 0x51 - 'Q'
+ {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x66, 0x67, 0x00, 0x00}, // 0x52 - 'R'
+ {0x00, 0x1E, 0x33, 0x33, 0x03, 0x0E, 0x18, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x53 - 'S'
+ {0x00, 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, // 0x54 - 'T'
+ {0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x55 - 'U'
+ {0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00, 0x00}, // 0x56 - 'V'
+ {0x00, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x6B, 0x36, 0x36, 0x36, 0x00, 0x00}, // 0x57 - 'W'
+ {0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x1E, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0x58 - 'X'
+ {0x00, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, // 0x59 - 'Y'
+ {0x00, 0x7F, 0x73, 0x19, 0x18, 0x0C, 0x06, 0x46, 0x63, 0x7F, 0x00, 0x00}, // 0x5A - 'Z'
+ {0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00}, // 0x5B - '['
+ {0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00}, // 0x5C - '\'
+ {0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00}, // 0x5D - ']'
+ {0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5E - '^'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00}, // 0x5F - '_'
+ {0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x60 - '`'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x33, 0x6E, 0x00, 0x00}, // 0x61 - 'a'
+ {0x00, 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x00, 0x00}, // 0x62 - 'b'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x03, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0x63 - 'c'
+ {0x00, 0x38, 0x30, 0x30, 0x3E, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00, 0x00}, // 0x64 - 'd'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0x65 - 'e'
+ {0x00, 0x1C, 0x36, 0x06, 0x06, 0x1F, 0x06, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0x66 - 'f'
+ {0x00, 0x00, 0x00, 0x00, 0x6E, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x33, 0x1E}, // 0x67 - 'g'
+ {0x00, 0x07, 0x06, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x66, 0x67, 0x00, 0x00}, // 0x68 - 'h'
+ {0x00, 0x18, 0x18, 0x00, 0x1E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00}, // 0x69 - 'i'
+ {0x00, 0x30, 0x30, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // 0x6A - 'j'
+ {0x00, 0x07, 0x06, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00, 0x00}, // 0x6B - 'k'
+ {0x00, 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00}, // 0x6C - 'l'
+ {0x00, 0x00, 0x00, 0x00, 0x3F, 0x6B, 0x6B, 0x6B, 0x6B, 0x63, 0x00, 0x00}, // 0x6D - 'm'
+ {0x00, 0x00, 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0x6E - 'n'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0x6F - 'o'
+ {0x00, 0x00, 0x00, 0x00, 0x3B, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // 0x70 - 'p'
+ {0x00, 0x00, 0x00, 0x00, 0x6E, 0x33, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x78}, // 0x71 - 'q'
+ {0x00, 0x00, 0x00, 0x00, 0x37, 0x76, 0x6E, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0x72 - 'r'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x06, 0x18, 0x33, 0x1E, 0x00, 0x00}, // 0x73 - 's'
+ {0x00, 0x00, 0x04, 0x06, 0x3F, 0x06, 0x06, 0x06, 0x36, 0x1C, 0x00, 0x00}, // 0x74 - 't'
+ {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00, 0x00}, // 0x75 - 'u'
+ {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00, 0x00}, // 0x76 - 'v'
+ {0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x6B, 0x6B, 0x36, 0x36, 0x00, 0x00}, // 0x77 - 'w'
+ {0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00, 0x00}, // 0x78 - 'x'
+ {0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x30, 0x18, 0x0F}, // 0x79 - 'y'
+ {0x00, 0x00, 0x00, 0x00, 0x3F, 0x31, 0x18, 0x06, 0x23, 0x3F, 0x00, 0x00}, // 0x7A - 'z'
+ {0x00, 0x38, 0x0C, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x0C, 0x38, 0x00, 0x00}, // 0x7B - '{'
+ {0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00}, // 0x7C - '|'
+ {0x00, 0x07, 0x0C, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x0C, 0x07, 0x00, 0x00}, // 0x7D - '}'
+ {0x00, 0xCE, 0x5B, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7E - '~'
+ {0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x00, 0x00, 0x00}, // 0x7F - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x80 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x81 - '�'
+ {0x00, 0x0C, 0x0C, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x82 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x83 - '�'
+ {0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x84 - '�'
+ {0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x00}, // 0x85 - '�'
+ {0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, // 0x86 - '�'
+ {0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18}, // 0x87 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88 - '�'
+ {0x00, 0x00, 0x00, 0x23, 0x33, 0x18, 0x0C, 0x06, 0x33, 0x31, 0x00, 0x00}, // 0x89 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A - '�'
+ {0x00, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x00}, // 0x8B - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 - '�'
+ {0x00, 0x0C, 0x0C, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91 - '�'
+ {0x00, 0x0C, 0x0C, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x92 - '�'
+ {0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x93 - '�'
+ {0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00}, // 0x95 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x96 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x97 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 - '�'
+ {0x00, 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, // 0x99 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A - '�'
+ {0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00}, // 0x9B - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 - '�'
+ {0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, 0x00}, // 0xA1 - '�'
+ {0x00, 0x00, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x30, 0x18, 0x0F}, // 0xA2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 - '�'
+ {0x00, 0x00, 0x66, 0x3C, 0x24, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA4 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA5 - '�'
+ {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, // 0xA6 - '�'
+ {0x00, 0x7E, 0xC6, 0x0C, 0x3C, 0x66, 0x66, 0x3C, 0x30, 0x63, 0x7E, 0x00}, // 0xA7 - '�'
+ {0x36, 0x7F, 0x46, 0x06, 0x26, 0x3E, 0x26, 0x06, 0x46, 0x7F, 0x00, 0x00}, // 0xA8 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x03, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0xA9 - '�'
+ {0x00, 0x3C, 0x66, 0x63, 0x03, 0x0F, 0x03, 0x63, 0x66, 0x3C, 0x00, 0x00}, // 0xAA - '�'
+ {0x00, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x00}, // 0xAB - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, // 0xAC - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAD - '�'
+ {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x66, 0x67, 0x00, 0x00}, // 0xAE - '�'
+ {0x33, 0x33, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00}, // 0xAF - '�'
+ {0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB0 - '�'
+ {0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, // 0xB1 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x30, 0x00, 0x00}, // 0xB5 - '�'
+ {0x00, 0xFE, 0xDB, 0xDB, 0xDB, 0xDE, 0xD8, 0xD8, 0xD8, 0xD8, 0x00, 0x00}, // 0xB6 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB7 - '�'
+ {0x00, 0x12, 0x12, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0xB8 - '�'
+ {0x00, 0x73, 0x73, 0x33, 0x37, 0x7F, 0x7B, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0xB9 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x0F, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0xBA - '�'
+ {0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00}, // 0xBB - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE - '�'
+ {0x00, 0x66, 0x66, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00}, // 0xBF - '�'
+ {0x00, 0x0C, 0x1E, 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0xC0 - '�'
+ {0x00, 0x7F, 0x46, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x3F, 0x00, 0x00}, // 0xC1 - '�'
+ {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x66, 0x3F, 0x00, 0x00}, // 0xC2 - '�'
+ {0x00, 0x7F, 0x46, 0x46, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0xC3 - '�'
+ {0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFF, 0xC3, 0x00}, // 0xC4 - '�'
+ {0x00, 0x7F, 0x46, 0x06, 0x26, 0x3E, 0x26, 0x06, 0x46, 0x7F, 0x00, 0x00}, // 0xC5 - '�'
+ {0x00, 0x99, 0xDB, 0x5A, 0x7E, 0x3C, 0x7E, 0x5A, 0xDB, 0x99, 0x00, 0x00}, // 0xC6 - '�'
+ {0x00, 0x3C, 0x66, 0x62, 0x60, 0x38, 0x60, 0x62, 0x66, 0x3C, 0x00, 0x00}, // 0xC7 - '�'
+ {0x00, 0x63, 0x63, 0x73, 0x7B, 0x7F, 0x6F, 0x67, 0x63, 0x63, 0x00, 0x00}, // 0xC8 - '�'
+ {0x18, 0x6B, 0x6F, 0x73, 0x7B, 0x7F, 0x6F, 0x67, 0x63, 0x63, 0x00, 0x00}, // 0xC9 - '�'
+ {0x00, 0x67, 0x66, 0x36, 0x36, 0x1E, 0x36, 0x36, 0x66, 0x67, 0x00, 0x00}, // 0xCA - '�'
+ {0x00, 0x78, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x63, 0x00, 0x00}, // 0xCB - '�'
+ {0x00, 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00}, // 0xCC - '�'
+ {0x00, 0x63, 0x63, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00}, // 0xCD - '�'
+ {0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00}, // 0xCE - '�'
+ {0x00, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00}, // 0xCF - '�'
+ {0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x0F, 0x00, 0x00}, // 0xD0 - '�'
+ {0x00, 0x3C, 0x66, 0x63, 0x03, 0x03, 0x03, 0x63, 0x66, 0x3C, 0x00, 0x00}, // 0xD1 - '�'
+ {0x00, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00}, // 0xD2 - '�'
+ {0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, 0x00}, // 0xD3 - '�'
+ {0x00, 0x18, 0x7E, 0xDB, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00, 0x00}, // 0xD4 - '�'
+ {0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x1E, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0xD5 - '�'
+ {0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x7F, 0x60, 0x00}, // 0xD6 - '�'
+ {0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7E, 0x60, 0x60, 0x60, 0x00, 0x00}, // 0xD7 - '�'
+ {0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x00, 0x00}, // 0xD8 - '�'
+ {0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0xFF, 0xC0, 0x00}, // 0xD9 - '�'
+ {0x00, 0x07, 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x00}, // 0xDA - '�'
+ {0x00, 0x63, 0x63, 0x63, 0x63, 0x6F, 0x7B, 0x7B, 0x7B, 0x6F, 0x00, 0x00}, // 0xDB - '�'
+ {0x00, 0x00, 0x03, 0x03, 0x03, 0x3F, 0x63, 0x63, 0x63, 0x3F, 0x00, 0x00}, // 0xDC - '�'
+ {0x00, 0x1E, 0x33, 0x63, 0x60, 0x78, 0x60, 0x63, 0x33, 0x1E, 0x00, 0x00}, // 0xDD - '�'
+ {0x00, 0x73, 0xDB, 0xDB, 0xDF, 0xDF, 0xDB, 0xDB, 0xDB, 0x73, 0x00, 0x00}, // 0xDE - '�'
+ {0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0xE7, 0x00, 0x00}, // 0xDF - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x33, 0x6E, 0x00, 0x00}, // 0xE0 - '�'
+ {0x00, 0x00, 0x00, 0x20, 0x3E, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0xE1 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1F, 0x33, 0x1F, 0x33, 0x33, 0x1F, 0x00, 0x00}, // 0xE2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x3F, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00}, // 0xE3 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x3E, 0x36, 0x36, 0x36, 0x36, 0x7F, 0x63, 0x00}, // 0xE4 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0xE5 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x49, 0x6B, 0x3E, 0x3E, 0x6B, 0x49, 0x00, 0x00}, // 0xE6 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x31, 0x1C, 0x30, 0x31, 0x1E, 0x00, 0x00}, // 0xE7 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x3B, 0x3F, 0x37, 0x33, 0x00, 0x00}, // 0xE8 - '�'
+ {0x00, 0x10, 0x18, 0x08, 0x33, 0x33, 0x3B, 0x3F, 0x37, 0x33, 0x00, 0x00}, // 0xE9 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x33, 0x1B, 0x0F, 0x1B, 0x13, 0x33, 0x00, 0x00}, // 0xEA - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x38, 0x3C, 0x34, 0x36, 0x32, 0x33, 0x00, 0x00}, // 0xEB - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x63, 0x77, 0x6B, 0x6B, 0x63, 0x63, 0x00, 0x00}, // 0xEC - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0xED - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00, 0x00}, // 0xEE - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00}, // 0xEF - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x1F, 0x03, 0x03}, // 0xF0 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x03, 0x03, 0x33, 0x1E, 0x00, 0x00}, // 0xF1 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x3F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x00, 0x00}, // 0xF2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x66, 0x3C}, // 0xF3 - '�'
+ {0x00, 0x00, 0x00, 0x08, 0x3E, 0x6B, 0x6B, 0x6B, 0x3E, 0x08, 0x08, 0x00}, // 0xF4 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00, 0x00}, // 0xF5 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x7F, 0x60, 0x00}, // 0xF6 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x30, 0x00, 0x00}, // 0xF7 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x00, 0x00}, // 0xF8 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0xFF, 0xC0, 0x00}, // 0xF9 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00}, // 0xFA - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x6F, 0x7B, 0x7B, 0x6F, 0x00, 0x00}, // 0xFB - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x1F, 0x33, 0x33, 0x1F, 0x00, 0x00}, // 0xFC - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x3C, 0x30, 0x33, 0x1E, 0x00, 0x00}, // 0xFD - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x3B, 0x6F, 0x6F, 0x6F, 0x6F, 0x3B, 0x00, 0x00}, // 0xFE - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x3E, 0x33, 0x33, 0x3E, 0x36, 0x33, 0x00, 0x00} // 0xFF - '�'
+};
+
+const unsigned char font12x16[256][32] =
+{
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 - ' '
+ {0xE0, 0x00, 0x18, 0x03, 0x04, 0x04, 0x04, 0x04, 0xB2, 0x09, 0xB2, 0x09, 0x02, 0x08, 0x02, 0x08, 0x12, 0x09, 0xE2, 0x08, 0x04, 0x04, 0x04, 0x04, 0x18, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x01 - ''
+ {0xE0, 0x00, 0xF8, 0x03, 0xFC, 0x07, 0xFC, 0x07, 0x4E, 0x0E, 0x4E, 0x0E, 0xFE, 0x0F, 0xFE, 0x0F, 0xEE, 0x0E, 0x1E, 0x0F, 0xFC, 0x07, 0xFC, 0x07, 0xF8, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x02 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0xBC, 0x07, 0xFC, 0x07, 0xFC, 0x07, 0xFC, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x03 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x04 - ''
+ {0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF0, 0x01, 0xF0, 0x01, 0xEC, 0x06, 0xFE, 0x0F, 0xFE, 0x0F, 0xFE, 0x0F, 0x4C, 0x06, 0xE0, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x05 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xFC, 0x07, 0xFC, 0x07, 0x58, 0x03, 0xE0, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x06 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x07 - ''
+ {0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x9F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x9F, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F}, // 0x08 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 - ' '
+ {0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x9F, 0x0F, 0x6F, 0x0F, 0xF7, 0x0E, 0xF7, 0x0E, 0xF7, 0x0E, 0xF7, 0x0E, 0x6F, 0x0F, 0x9F, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F}, // 0x0A - ' '
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x06, 0x78, 0x05, 0xCC, 0x04, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01, 0xCC, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0B - ' '
+ {0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x30, 0x03, 0x18, 0x06, 0x18, 0x06, 0x18, 0x06, 0x30, 0x03, 0xE0, 0x01, 0xC0, 0x00, 0xC0, 0x00, 0xF0, 0x03, 0xC0, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0C - ' '
+ {0x40, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x01, 0x40, 0x00, 0x40, 0x00, 0x70, 0x00, 0x78, 0x00, 0x78, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D - ' '
+ {0x30, 0x00, 0x70, 0x00, 0xD0, 0x00, 0x90, 0x01, 0x30, 0x03, 0x70, 0x02, 0xD0, 0x02, 0x90, 0x03, 0x1C, 0x03, 0x1E, 0x02, 0x1E, 0x02, 0x8C, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0x80, 0x01, 0x00, 0x00}, // 0x0E - ''
+ {0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0xE4, 0x04, 0xF8, 0x03, 0x18, 0x03, 0x0C, 0x06, 0x0E, 0x0E, 0x0C, 0x06, 0x18, 0x03, 0xF8, 0x03, 0xE4, 0x04, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0F - ''
+ {0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xF8, 0x00, 0xF8, 0x01, 0xF8, 0x00, 0x78, 0x00, 0x38, 0x00, 0x18, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x10 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x01, 0xC0, 0x01, 0xE0, 0x01, 0xF0, 0x01, 0xF8, 0x01, 0xF0, 0x01, 0xE0, 0x01, 0xC0, 0x01, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x11 - ''
+ {0x00, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x12 - ''
+ {0x00, 0x00, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x00, 0x00, 0x98, 0x01, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x13 - ''
+ {0x00, 0x00, 0xF8, 0x07, 0x6C, 0x03, 0x66, 0x03, 0x66, 0x03, 0x66, 0x03, 0x6C, 0x03, 0x78, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x14 - ''
+ {0x00, 0x00, 0xF8, 0x01, 0x0C, 0x03, 0x0C, 0x00, 0x0C, 0x00, 0xF8, 0x01, 0x0C, 0x03, 0x0C, 0x03, 0xF8, 0x01, 0x00, 0x03, 0x00, 0x03, 0x0C, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x15 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0xF8, 0x07, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x16 - ''
+ {0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0xF8, 0x03, 0x00, 0x00}, // 0x17 - ''
+ {0x00, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x18 - ''
+ {0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x19 - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x01, 0x80, 0x03, 0xFC, 0x07, 0x80, 0x03, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1A - ' '
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x38, 0x00, 0xFC, 0x07, 0x38, 0x00, 0x30, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1B - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x1C - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x18, 0x03, 0x1C, 0x07, 0xFE, 0x0F, 0x1C, 0x07, 0x18, 0x03, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1D - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xF8, 0x03, 0xFC, 0x07, 0xFE, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1E - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0xFC, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1F - ''
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 - ' '
+ {0x60, 0x00, 0x60, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x21 - '!'
+ {0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x22 - '"'
+ {0x00, 0x00, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0xFC, 0x0F, 0x30, 0x03, 0x30, 0x03, 0x98, 0x01, 0x98, 0x01, 0xFE, 0x03, 0xCC, 0x00, 0xCC, 0x00, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x23 - '#'
+ {0x60, 0x00, 0x60, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x6C, 0x00, 0x6C, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0x60, 0x03, 0x60, 0x03, 0xFC, 0x03, 0xF8, 0x01, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x24 - '$'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x0C, 0x1C, 0x0E, 0x1C, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x07, 0x0E, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x25 - '%'
+ {0x00, 0x00, 0xE0, 0x00, 0xB0, 0x01, 0x98, 0x01, 0x98, 0x01, 0xD8, 0x00, 0x70, 0x00, 0x78, 0x00, 0x7C, 0x00, 0xCC, 0x06, 0xCC, 0x03, 0x8C, 0x01, 0xDC, 0x03, 0x78, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x26 - '&'
+ {0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x27 - '''
+ {0xC0, 0x01, 0x60, 0x00, 0x70, 0x00, 0x30, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x30, 0x00, 0x70, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x28 - '('
+ {0x38, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x60, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x29 - ')'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x03, 0x6C, 0x03, 0xF8, 0x01, 0xF0, 0x00, 0xFC, 0x03, 0xF0, 0x00, 0xF8, 0x01, 0x6C, 0x03, 0x6C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2A - '*'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFC, 0x03, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2B - '+'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x30, 0x00}, // 0x2C - ','
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x03, 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2D - '-'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2E - '.'
+ {0x00, 0x00, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x2F - '/'
+ {0xF0, 0x01, 0xFC, 0x07, 0x0C, 0x06, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x0C, 0x06, 0xFC, 0x07, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x30 - '0'
+ {0xC0, 0x00, 0xE0, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xF8, 0x07, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x31 - '1'
+ {0xF8, 0x03, 0xFC, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x06, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x00, 0x00, 0x00}, // 0x32 - '2'
+ {0xF8, 0x03, 0xFC, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x00, 0x0C, 0x00, 0x0E, 0xF0, 0x07, 0xF0, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x33 - '3'
+ {0x80, 0x03, 0xC0, 0x03, 0xE0, 0x03, 0x70, 0x03, 0x38, 0x03, 0x1C, 0x03, 0x0E, 0x03, 0x06, 0x03, 0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x34 - '4'
+ {0xFE, 0x0F, 0xFE, 0x0F, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x03, 0xFC, 0x07, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x35 - '5'
+ {0xC0, 0x03, 0xE0, 0x03, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0xFE, 0x03, 0xFE, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x36 - '6'
+ {0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x06, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x80, 0x01, 0x80, 0x01, 0xC0, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x37 - '7'
+ {0xF0, 0x01, 0xF8, 0x03, 0x1C, 0x07, 0x0C, 0x06, 0x0C, 0x06, 0x1C, 0x07, 0xF8, 0x03, 0xFC, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x38 - '8'
+ {0xF8, 0x03, 0xFC, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x0F, 0xF8, 0x0F, 0x00, 0x06, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xF8, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x39 - '9'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3A - ':'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00}, // 0x3B - ';'
+ {0x00, 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x3C - '<'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x07, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x07, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3D - '='
+ {0x0C, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3E - '>'
+ {0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x3F - '?'
+ {0xF8, 0x03, 0xFC, 0x07, 0x0C, 0x06, 0xE6, 0x0D, 0xF6, 0x0D, 0xB6, 0x0D, 0xB6, 0x0D, 0xB6, 0x0D, 0xB6, 0x0D, 0xF6, 0x07, 0xE6, 0x03, 0x0E, 0x00, 0xFC, 0x03, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x40 - '@'
+ {0x60, 0x00, 0x60, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0x0C, 0x03, 0xFC, 0x03, 0xFC, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x41 - 'A'
+ {0xFE, 0x00, 0xFE, 0x01, 0x86, 0x03, 0x06, 0x03, 0x06, 0x03, 0x86, 0x03, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x42 - 'B'
+ {0xF0, 0x01, 0xF8, 0x03, 0x1C, 0x07, 0x0C, 0x06, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0C, 0x06, 0x1C, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x43 - 'C'
+ {0xFE, 0x00, 0xFE, 0x01, 0x86, 0x03, 0x06, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x03, 0x86, 0x03, 0xFE, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x44 - 'D'
+ {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x45 - 'E'
+ {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x46 - 'F'
+ {0xF0, 0x03, 0xF8, 0x07, 0x1C, 0x06, 0x0C, 0x00, 0x06, 0x00, 0x06, 0x00, 0xC6, 0x07, 0xC6, 0x07, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x06, 0x1C, 0x06, 0xF8, 0x07, 0xF0, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x47 - 'G'
+ {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x48 - 'H'
+ {0xF8, 0x01, 0xF8, 0x01, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x49 - 'I'
+ {0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x03, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x4A - 'J'
+ {0x06, 0x06, 0x06, 0x07, 0x86, 0x03, 0xC6, 0x01, 0xE6, 0x00, 0x76, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x76, 0x00, 0xE6, 0x00, 0xC6, 0x01, 0x86, 0x03, 0x06, 0x07, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x4B - 'K'
+ {0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x4C - 'L'
+ {0x06, 0x06, 0x0E, 0x07, 0x0E, 0x07, 0x9E, 0x07, 0x9E, 0x07, 0xF6, 0x06, 0xF6, 0x06, 0x66, 0x06, 0x66, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x4D - 'M'
+ {0x06, 0x06, 0x0E, 0x06, 0x0E, 0x06, 0x1E, 0x06, 0x36, 0x06, 0x36, 0x06, 0x66, 0x06, 0x66, 0x06, 0xC6, 0x06, 0xC6, 0x06, 0x86, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x4E - 'N'
+ {0xF0, 0x00, 0xF8, 0x01, 0x9C, 0x03, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x9C, 0x03, 0xF8, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x4F - 'O'
+ {0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x50 - 'P'
+ {0xF0, 0x00, 0xF8, 0x01, 0x9C, 0x03, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xC6, 0x06, 0xCC, 0x03, 0x9C, 0x03, 0xF8, 0x07, 0xF0, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x51 - 'Q'
+ {0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0xE6, 0x00, 0xC6, 0x01, 0x86, 0x03, 0x06, 0x07, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x52 - 'R'
+ {0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x00, 0x0E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0x00, 0x07, 0x00, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x53 - 'S'
+ {0xFC, 0x03, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x54 - 'T'
+ {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x55 - 'U'
+ {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x56 - 'V'
+ {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x06, 0x66, 0x06, 0xF6, 0x06, 0x9E, 0x07, 0x0E, 0x07, 0x0E, 0x07, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x57 - 'W'
+ {0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0xF0, 0x00, 0x98, 0x01, 0x0C, 0x03, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x58 - 'X'
+ {0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x59 - 'Y'
+ {0xFE, 0x07, 0xFE, 0x07, 0x00, 0x03, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x5A - 'Z'
+ {0xF8, 0x01, 0xF8, 0x01, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x5B - '['
+ {0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5C - '\'
+ {0xF8, 0x01, 0xF8, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x5D - ']'
+ {0x40, 0x00, 0xE0, 0x00, 0xF0, 0x01, 0xB8, 0x03, 0x1C, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x5E - '^'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x0F, 0xFE, 0x0F}, // 0x5F - '_'
+ {0x00, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x60, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x60 - '`'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x03, 0xFC, 0x07, 0x00, 0x06, 0xF8, 0x07, 0xFC, 0x07, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x61 - 'a'
+ {0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xF6, 0x01, 0xFE, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x62 - 'b'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x06, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0E, 0x06, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x63 - 'c'
+ {0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0xF8, 0x06, 0xFC, 0x07, 0x8E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x06, 0xFC, 0x07, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0x64 - 'd'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x06, 0xFE, 0x07, 0xFE, 0x03, 0x06, 0x00, 0x0E, 0x00, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x65 - 'e'
+ {0xE0, 0x01, 0xF0, 0x01, 0x38, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x66 - 'f'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0xFC, 0x07, 0x0E, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x07, 0xF8, 0x06, 0x00, 0x06, 0x00, 0x07, 0xFC, 0x03, 0xFC, 0x01}, // 0x67 - 'g'
+ {0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xF6, 0x00, 0xFE, 0x01, 0x8E, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x68 - 'h'
+ {0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x69 - 'i'
+ {0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x98, 0x01, 0xF8, 0x01, 0xF0, 0x00}, // 0x6A - 'j'
+ {0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x8C, 0x01, 0xCC, 0x01, 0xEC, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0xEC, 0x00, 0xCC, 0x01, 0x8C, 0x03, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x6B - 'k'
+ {0x70, 0x00, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x6C - 'l'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x01, 0xFE, 0x03, 0xFE, 0x07, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x6D - 'm'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0xFC, 0x03, 0x0C, 0x07, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x6E - 'n'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x6F - 'o'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFE, 0x03, 0xF6, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00}, // 0x70 - 'p'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0xFC, 0x07, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x07, 0xF8, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06}, // 0x71 - 'q'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x03, 0xFC, 0x07, 0x1C, 0x06, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x72 - 'r'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0xFE, 0x01, 0x06, 0x00, 0xFE, 0x00, 0xFC, 0x01, 0x80, 0x01, 0x80, 0x01, 0xFE, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x73 - 's'
+ {0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xF8, 0x01, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x74 - 't'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x07, 0xF8, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0x75 - 'u'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x76 - 'v'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xF6, 0x06, 0xFC, 0x03, 0x9C, 0x03, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0x77 - 'w'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x8E, 0x03, 0xDC, 0x01, 0xF8, 0x00, 0x70, 0x00, 0xF8, 0x00, 0xDC, 0x01, 0x8E, 0x03, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x78 - 'x'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0x00}, // 0x79 - 'y'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x03, 0xFE, 0x01, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0C, 0x00, 0xFE, 0x03, 0xFE, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0x7A - 'z'
+ {0xC0, 0x03, 0xE0, 0x03, 0x70, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x70, 0x00, 0xE0, 0x03, 0xC0, 0x03, 0x00, 0x00}, // 0x7B - '{'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7C - '|'
+ {0x3C, 0x00, 0x7C, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0xC0, 0x01, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0x7C, 0x00, 0x3C, 0x00, 0x00, 0x00}, // 0x7D - '}'
+ {0x00, 0x00, 0x00, 0x00, 0x38, 0x06, 0x6C, 0x03, 0xC6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7E - '~'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xF0, 0x00, 0x98, 0x01, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7F - ''
+ {0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04, 0x11, 0x01, 0x44, 0x04}, // 0x80 - '�'
+ {0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05}, // 0x81 - '�'
+ {0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B, 0xEE, 0x0E, 0xBB, 0x0B}, // 0x82 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x83 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x84 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x85 - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x86 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x87 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x88 - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x60, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x89 - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x8A - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x8B - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x8F - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x92 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x93 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x95 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0x96 - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEC, 0x0F, 0xEC, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x97 - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEC, 0x0F, 0xEC, 0x0F, 0x0C, 0x00, 0xFC, 0x0F, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0xFC, 0x0F, 0x0C, 0x00, 0xEC, 0x0F, 0xEC, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x99 - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEF, 0x0F, 0xEF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xEF, 0x0F, 0xEF, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x9B - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEC, 0x0F, 0xEC, 0x0F, 0x0C, 0x00, 0xEC, 0x0F, 0xEC, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x9C - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEF, 0x0F, 0xEF, 0x0F, 0x00, 0x00, 0xEF, 0x0F, 0xEF, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0x9E - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0xA1 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0xA2 - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xFC, 0x0F, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA3 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA4 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0xA5 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0xFC, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0xA6 - '�'
+ {0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0xEF, 0x0F, 0xEF, 0x0F, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6C, 0x00}, // 0xA7 - '�'
+ {0x98, 0x01, 0x98, 0x01, 0x00, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0xA8 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0xA9 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAA - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00}, // 0xAB - '�'
+ {0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F}, // 0xAC - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F}, // 0xAD - '�'
+ {0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00}, // 0xAE - '�'
+ {0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F}, // 0xAF - '�'
+ {0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB0 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0xA4, 0x04, 0x44, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x02, 0x10, 0x01, 0xA0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB1 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x20, 0x04, 0x1C, 0x08, 0xFE, 0x0F, 0xFE, 0x0F, 0xFE, 0x0F, 0xFE, 0x0F, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x20, 0x04, 0x1C, 0x08, 0xFE, 0x0F, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x04, 0x04, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB3 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB4 - '�'
+ {0x00, 0x00, 0xC0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x00, 0x90, 0x00, 0x90, 0x00, 0xE0, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB5 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x60, 0x00, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0x00}, // 0xB6 - '�'
+ {0xF0, 0x00, 0xF8, 0x01, 0x98, 0x01, 0x98, 0x01, 0xF8, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB7 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x98, 0x01, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xB8 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xB9 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBA - '�'
+ {0x00, 0x00, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC4, 0x00, 0xCC, 0x00, 0xD8, 0x00, 0xF0, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBB - '�'
+ {0xC3, 0x00, 0xC7, 0x06, 0xC7, 0x0F, 0xC7, 0x09, 0xCF, 0x0F, 0xCB, 0x06, 0xCB, 0x00, 0xDB, 0x00, 0xD3, 0x0F, 0xF3, 0x0F, 0xE3, 0x00, 0xE3, 0x00, 0xE3, 0x00, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBC - '�'
+ {0x00, 0x00, 0x06, 0x06, 0xF6, 0x06, 0xFC, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x03, 0xF6, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBD - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBE - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xBF - '�'
+ {0xF0, 0x07, 0xF8, 0x07, 0x1C, 0x06, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xC0 - '�'
+ {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xC1 - '�'
+ {0xFE, 0x00, 0xFE, 0x01, 0x86, 0x03, 0x06, 0x03, 0x06, 0x03, 0x86, 0x03, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xC2 - '�'
+ {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xC3 - '�'
+ {0xF0, 0x07, 0xF8, 0x07, 0x1C, 0x06, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFF, 0x0F, 0xFF, 0x0F, 0x03, 0x0C, 0x03, 0x0C}, // 0xC4 - '�'
+ {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0xC5 - '�'
+ {0x61, 0x08, 0x63, 0x0C, 0x63, 0x0C, 0x67, 0x06, 0x66, 0x06, 0x6E, 0x03, 0xFC, 0x03, 0xFC, 0x03, 0x6E, 0x07, 0x66, 0x06, 0x67, 0x0E, 0x63, 0x0C, 0x63, 0x0C, 0x61, 0x08, 0x00, 0x00, 0x00, 0x00}, // 0xC6 - '�'
+ {0xF8, 0x03, 0xFC, 0x07, 0x0E, 0x0E, 0x06, 0x0C, 0x00, 0x0C, 0x00, 0x0E, 0xF0, 0x07, 0xF0, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0xFC, 0x07, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xC7 - '�'
+ {0x06, 0x06, 0x06, 0x07, 0x06, 0x07, 0x86, 0x07, 0xC6, 0x06, 0xC6, 0x06, 0x66, 0x06, 0x66, 0x06, 0x36, 0x06, 0x36, 0x06, 0x1E, 0x06, 0x0E, 0x06, 0x0E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xC8 - '�'
+ {0x46, 0x06, 0x66, 0x07, 0x26, 0x07, 0x86, 0x07, 0xC6, 0x06, 0xC6, 0x06, 0x66, 0x06, 0x66, 0x06, 0x36, 0x06, 0x36, 0x06, 0x1E, 0x06, 0x0E, 0x06, 0x0E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xC9 - '�'
+ {0x06, 0x06, 0x06, 0x07, 0x86, 0x03, 0xC6, 0x01, 0xE6, 0x00, 0x76, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x76, 0x00, 0xE6, 0x00, 0xC6, 0x01, 0x86, 0x03, 0x06, 0x07, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xCA - '�'
+ {0xF0, 0x07, 0xF8, 0x07, 0x1C, 0x06, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xCB - '�'
+ {0x06, 0x06, 0x0E, 0x07, 0x0E, 0x07, 0x9E, 0x07, 0x9E, 0x07, 0xF6, 0x06, 0xF6, 0x06, 0x66, 0x06, 0x66, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xCC - '�'
+ {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xCD - '�'
+ {0xF0, 0x00, 0xF8, 0x01, 0x9C, 0x03, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x9C, 0x03, 0xF8, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xCE - '�'
+ {0xFE, 0x07, 0xFE, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xCF - '�'
+ {0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD0 - '�'
+ {0xF0, 0x01, 0xF8, 0x03, 0x1C, 0x07, 0x0C, 0x06, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0C, 0x06, 0x1C, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xD1 - '�'
+ {0xFC, 0x03, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD2 - '�'
+ {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFC, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x06, 0x03, 0xFE, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xD3 - '�'
+ {0x60, 0x00, 0x60, 0x00, 0xFC, 0x03, 0xFE, 0x07, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x07, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD4 - '�'
+ {0x06, 0x06, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0xF0, 0x00, 0x98, 0x01, 0x0C, 0x03, 0x0C, 0x03, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xD5 - '�'
+ {0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x06, 0x00, 0x06}, // 0xD6 - '�'
+ {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFC, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xD7 - '�'
+ {0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0xD8 - '�'
+ {0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x0C, 0x00, 0x0C}, // 0xD9 - '�'
+ {0x1F, 0x00, 0x1F, 0x00, 0x1B, 0x00, 0x1B, 0x00, 0x18, 0x00, 0xF8, 0x01, 0xF8, 0x03, 0x18, 0x07, 0x18, 0x06, 0x18, 0x06, 0x18, 0x06, 0x18, 0x07, 0xF8, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xDA - '�'
+ {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x06, 0x7E, 0x06, 0xE6, 0x06, 0xC6, 0x06, 0xC6, 0x06, 0xC6, 0x06, 0xE6, 0x06, 0x7E, 0x06, 0x3E, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xDB - '�'
+ {0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xDC - '�'
+ {0xF8, 0x00, 0xFC, 0x01, 0x8E, 0x03, 0x06, 0x03, 0x00, 0x06, 0x00, 0x06, 0xF0, 0x07, 0xF0, 0x07, 0x00, 0x06, 0x00, 0x06, 0x06, 0x03, 0x8E, 0x03, 0xFC, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xDD - '�'
+ {0xC3, 0x01, 0xE3, 0x03, 0x73, 0x07, 0x33, 0x06, 0x1B, 0x0C, 0x1B, 0x0C, 0x1F, 0x0C, 0x1F, 0x0C, 0x1B, 0x0C, 0x1B, 0x0C, 0x33, 0x06, 0x73, 0x07, 0xE3, 0x03, 0xC3, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xDE - '�'
+ {0xF8, 0x07, 0xFC, 0x07, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x06, 0xFC, 0x07, 0xF8, 0x07, 0x70, 0x06, 0x38, 0x06, 0x1C, 0x06, 0x0E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xDF - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x03, 0xFC, 0x07, 0x00, 0x06, 0xF8, 0x07, 0xFC, 0x07, 0x06, 0x06, 0x06, 0x06, 0xFE, 0x07, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0xE0 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFC, 0x03, 0xFE, 0x01, 0x06, 0x00, 0xF6, 0x01, 0xFE, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0xFE, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xE1 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0xFC, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xFC, 0x01, 0x0C, 0x03, 0x0C, 0x03, 0xFC, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xE2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x03, 0xFC, 0x03, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE3 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0xF8, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xFE, 0x07, 0xFE, 0x07, 0x06, 0x06, 0x06, 0x06}, // 0xE4 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x06, 0xFE, 0x07, 0xFE, 0x03, 0x06, 0x00, 0x0E, 0x00, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xE5 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x0C, 0x67, 0x0E, 0x6E, 0x07, 0xFC, 0x03, 0xFC, 0x03, 0x6C, 0x03, 0x66, 0x06, 0x67, 0x0E, 0x63, 0x0C, 0x00, 0x00, 0x00, 0x00}, // 0xE6 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xF8, 0x01, 0x0C, 0x03, 0x00, 0x03, 0xE0, 0x01, 0x00, 0x03, 0x0C, 0x03, 0xF8, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xE7 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x07, 0x8C, 0x07, 0xCC, 0x06, 0x6C, 0x06, 0x3C, 0x06, 0x1C, 0x06, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xE8 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x40, 0x00, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x07, 0x8C, 0x07, 0xCC, 0x06, 0x6C, 0x06, 0x3C, 0x06, 0x1C, 0x06, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xE9 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x01, 0xCC, 0x01, 0xEC, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0xEC, 0x00, 0xCC, 0x01, 0x8C, 0x03, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xEA - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0xF8, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xEB - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x07, 0x9E, 0x07, 0x9E, 0x07, 0xF6, 0x06, 0x66, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xEC - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0xFC, 0x07, 0xFC, 0x07, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xED - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xEE - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x07, 0xFC, 0x07, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xEF - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0xFE, 0x03, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x0E, 0x07, 0xFE, 0x03, 0xF6, 0x01, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00}, // 0xF0 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0x0E, 0x06, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0E, 0x06, 0xFC, 0x03, 0xF8, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xF1 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x03, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xF2 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x0C, 0x03, 0x98, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0x00}, // 0xF3 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xFC, 0x03, 0xFE, 0x07, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x07, 0xFC, 0x03, 0x60, 0x00, 0x60, 0x00}, // 0xF4 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x8E, 0x03, 0xDC, 0x01, 0xF8, 0x00, 0x70, 0x00, 0xF8, 0x00, 0xDC, 0x01, 0x8E, 0x03, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xF5 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xFC, 0x07, 0xFC, 0x07, 0x00, 0x06, 0x00, 0x06}, // 0xF6 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xFC, 0x03, 0xF8, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xF7 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x07, 0xFE, 0x07, 0x00, 0x00, 0x00, 0x00}, // 0xF8 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0x66, 0x06, 0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x0C, 0x00, 0x0C}, // 0xF9 - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x36, 0x00, 0xF0, 0x03, 0xF0, 0x07, 0x30, 0x06, 0x30, 0x06, 0xF0, 0x07, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00}, // 0xFA - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x06, 0xFE, 0x06, 0xC6, 0x06, 0xC6, 0x06, 0xFE, 0x06, 0x7E, 0x06, 0x00, 0x00, 0x00, 0x00}, // 0xFB - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0xFC, 0x01, 0xFC, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xFC, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xFC - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0xFC, 0x01, 0x06, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0x00, 0x03, 0x86, 0x03, 0xFC, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xFD - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x01, 0xE6, 0x03, 0x76, 0x07, 0x3E, 0x06, 0x3E, 0x06, 0x36, 0x06, 0x76, 0x07, 0xE6, 0x03, 0xC6, 0x01, 0x00, 0x00, 0x00, 0x00}, // 0xFE - '�'
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x03, 0xFC, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0xF8, 0x03, 0x70, 0x03, 0x38, 0x03, 0x1C, 0x03, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x00} // 0xFF - '�'
+};
diff --git a/Display/Fonts.h b/Display/Fonts.h
new file mode 100644
index 0000000..5dc96ca
--- /dev/null
+++ b/Display/Fonts.h
@@ -0,0 +1,47 @@
+//******************************************************************************
+// @file Fonts.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Fonts data, header
+//
+// @section LICENSE
+//
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+//******************************************************************************
+
+#ifndef Fonts_h
+#define Fonts_h
+
+extern const unsigned char font4x6[256][6];
+extern const unsigned char font6x8[256][8];
+extern const unsigned char font8x8[256][8];
+extern const unsigned char font8x12[256][16];
+extern const unsigned char font12x16[256][24];
+
+#endif
diff --git a/Display/ILI9341.cpp b/Display/ILI9341.cpp
new file mode 100644
index 0000000..f680a33
--- /dev/null
+++ b/Display/ILI9341.cpp
@@ -0,0 +1,566 @@
+//******************************************************************************
+// @file ILI9341.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: ILI9341 Low Level Driver Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "ILI9341.h"
+
+// *****************************************************************************
+// *** Defines *************************************************************
+// *****************************************************************************
+
+// Commands definitions
+
+#define CMD_NOP 0x00 // No Operation
+#define CMD_SWRESET 0x01 // Software Reset
+#define CMD_RDDID 0x04 // Read Display Identification Information
+#define CMD_RDDST 0x09 // Read Display Status
+
+#define CMD_RDMODE 0x0A // Read Display Power Mode
+#define CMD_RDMADCTL 0x0B // Read Display MADCTL
+#define CMD_RDPIXFMT 0x0C // Read Display Pixel Format
+#define CMD_RDIMGFMT 0x0D // Read Display Image Format
+#define CMD_RDSIGMOD 0x0E // Read Display Signal Mode
+#define CMD_RDSELFDIAG 0x0F // Read Display Self-Diagnostic Result
+
+#define CMD_SLPIN 0x10 // Enter Sleep Mode
+#define CMD_SLPOUT 0x11 // Sleep OUT
+#define CMD_PTLON 0x12 // Partial Mode ON
+#define CMD_NORON 0x13 // Normal Display Mode ON
+
+#define CMD_INVOFF 0x20 // Display Inversion OFF
+#define CMD_INVON 0x21 // Display Inversion ON
+#define CMD_GAMMASET 0x26 // Gamma Set
+#define CMD_DISPOFF 0x28 // Display OFF
+#define CMD_DISPON 0x29 // Display ON
+
+#define CMD_CASET 0x2A // Column Address Set
+#define CMD_PASET 0x2B // Page Address Set
+#define CMD_RAMWR 0x2C // Memory Write
+#define CMD_GSET 0x2D // Color SET
+#define CMD_RAMRD 0x2E // Memory Read
+
+#define CMD_PTLAR 0x30 // Partial Area
+#define CMD_VSCRDEF 0x33 // Vertical Scrolling Definition
+#define CMD_TELOFF 0x34 // Tearing Effect Line OFF
+#define CMD_TELON 0x35 // Tearing Effect Line ON
+#define CMD_MADCTL 0x36 // Memory Access Control
+#define CMD_VSAADDR 0x37 // Vertical Scrolling Start Address
+#define CMD_IDLMOFF 0x38 // Idle Mode OFF
+#define CMD_IDLMON 0x39 // Idle Mode ON
+#define CMD_PIXFMT 0x3A // Pixel Format Set
+
+#define CMD_RGBISC 0xB0 // RGB Interface Signal Control
+#define CMD_FRMCTR1 0xB1 // Frame Control (In Normal Mode)
+#define CMD_FRMCTR2 0xB2 // Frame Control (In Idle Mode)
+#define CMD_FRMCTR3 0xB3 // Frame Control (In Partial Mode)
+#define CMD_INVCTR 0xB4 // Display Inversion Control
+#define CMD_BLKPC 0xB5 // Blanking Porch Control
+#define CMD_DFUNCTR 0xB6 // Display Function Control
+
+#define CMD_PWCTR1 0xC0 // Power Control 1
+#define CMD_PWCTR2 0xC1 // Power Control 2
+#define CMD_VMCTR1 0xC5 // VCOM Control 1
+#define CMD_VMCTR2 0xC7 // VCOM Control 2
+#define CMD_PWCTRA 0xCB // Power control A
+#define CMD_PWCTRB 0xCF // Power control B
+
+#define CMD_NVMEMWR 0xD0 // NV Memory Write
+#define CMD_NVMEMPK 0xD1 // NV Memory Protection Key
+#define CMD_NVMEMSR 0xD2 // NV Memory Status Read
+#define CMD_READID4 0xD3 // Read ID4
+
+#define CMD_RDID1 0xDA // Read ID1
+#define CMD_RDID2 0xDB // Read ID2
+#define CMD_RDID3 0xDC // Read ID3
+
+#define CMD_GMCTRP1 0xE0 // Positive Gamma Correction
+#define CMD_GMCTRN1 0xE1 // Negative Gamma Correction
+#define CMD_DGCTRL1 0xE2 // Digital Gamma Control 1
+#define CMD_DGCTRL2 0xE3 // Digital Gamma Control 2
+#define CMD_DRVTMCA 0xE8 // Driver timing control A
+#define CMD_DRVTMCB 0xEA // Driver timing control B
+#define CMD_PWONSC 0xED // Power on sequence control
+
+#define CMD_EN3G 0xF2 // Enable 3 gamma control
+#define CMD_INTCTRL 0xF6 // Interface Control
+#define CMD_PUMPRC 0xF7 // Pump ratio control
+
+// Memory Access Control register bits definitions
+
+#define MADCTL_MY 0x80 // Row Address Order
+#define MADCTL_MX 0x40 // Column Address Order
+#define MADCTL_MV 0x20 // Row / Column Exchange
+#define MADCTL_ML 0x10 // Vertical Refresh Order
+#define MADCTL_BGR 0x08 // BGR Order
+#define MADCTL_RGB 0x00 // RGB Order (No BGR bit)
+#define MADCTL_MH 0x04 // Horizontal Refresh ORDER
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+ILI9341::ILI9341(SPI_HandleTypeDef* in_hspi) : hspi(in_hspi) {};
+
+// *****************************************************************************
+// *** Write byte to SPI ***************************************************
+// *****************************************************************************
+inline void ILI9341::SpiWrite(uint8_t c)
+{
+ HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); // Pull down CS
+ HAL_SPI_Transmit(hspi, &c, sizeof(c), 1U);
+ HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); // Pull up CS
+}
+
+// *****************************************************************************
+// *** Write byte stream to SPI ********************************************
+// *****************************************************************************
+void ILI9341::SpiWriteStream(uint8_t* data, uint32_t n)
+{
+ HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); // Pull down CS
+ HAL_SPI_Transmit_DMA(hspi, data, n);
+}
+
+// *****************************************************************************
+// *** Write command to SPI ************************************************
+// *****************************************************************************
+inline void ILI9341::WriteCommand(uint8_t c)
+{
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET); // Command
+ SpiWrite(c);
+}
+
+// *****************************************************************************
+// *** Write data to SPI ***************************************************
+// *****************************************************************************
+inline void ILI9341::WriteData(uint8_t c)
+{
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data
+ SpiWrite(c);
+}
+
+// *****************************************************************************
+// *** Write data steram to SPI ********************************************
+// *****************************************************************************
+void ILI9341::WriteDataStream(uint8_t* data, uint32_t n)
+{
+ // Data
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET);
+ // Pull down CS
+ HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
+ // Send data to screen
+ HAL_SPI_Transmit_DMA(hspi, data, n);
+}
+
+// *****************************************************************************
+// *** Check SPI transfer status *******************************************
+// *****************************************************************************
+bool ILI9341::IsTransferComplete(void)
+{
+ return (hspi->State != HAL_SPI_STATE_BUSY_TX);
+// return (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == SET);
+}
+
+// *****************************************************************************
+// *** Pull up CS line for LCD **********************************************
+// *****************************************************************************
+void ILI9341::StopTransfer(void)
+{
+ // Pull up CS
+ HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
+}
+
+// *****************************************************************************
+// *** Init screen *********************************************************
+// *****************************************************************************
+void ILI9341::Init(void)
+{
+// // Reset sequence. Used only if GPIO pin used as LCD reset.
+// HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET);
+// HAL_Delay(5);
+// HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_RESET);
+// HAL_Delay(20);
+// HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET);
+// HAL_Delay(150);
+
+ // Exit Sleep
+ WriteCommand(CMD_SWRESET);
+ // Delay for execute previous command
+ HAL_Delay(100U);
+
+ // Power control
+ WriteCommand(CMD_PWCTR1);
+ WriteData(0x23); // VRH[5:0] // 25
+
+ // Power control
+ WriteCommand(CMD_PWCTR2);
+ WriteData(0x10); // SAP[2:0]; BT[3:0] // 11
+
+ // VCM control 1
+ WriteCommand(CMD_VMCTR1);
+ WriteData(0x2B);
+ WriteData(0x2B);
+
+ // VCM control 2
+ WriteCommand(CMD_VMCTR2);
+ WriteData(0xC0);
+
+ // Pixel Format Set
+ WriteCommand(CMD_PIXFMT);
+ WriteData(0x55);
+
+ // Frame Control (In Normal Mode)
+ WriteCommand(CMD_FRMCTR1);
+ WriteData(0x00);
+ WriteData(0x18);
+
+ // Power control A
+ WriteCommand(CMD_PWCTRA);
+ WriteData(0x39);
+ WriteData(0x2C);
+ WriteData(0x00);
+ WriteData(0x34);
+ WriteData(0x02);
+
+ // Power control B
+ WriteCommand(CMD_PWCTRB);
+ WriteData(0x00);
+ WriteData(0XC1);
+ WriteData(0X30);
+
+ // Power on sequence control
+ WriteCommand(CMD_PWONSC);
+ WriteData(0x64);
+ WriteData(0x03);
+ WriteData(0X12);
+ WriteData(0X81);
+
+ // Driver timing control A
+ WriteCommand(CMD_DRVTMCA);
+ WriteData(0x85);
+ WriteData(0x00);
+ WriteData(0x78);
+
+ // Driver timing control B
+ WriteCommand(CMD_DRVTMCB);
+ WriteData(0x00);
+ WriteData(0x00);
+
+ // Pump ratio control
+ WriteCommand(CMD_PUMPRC);
+ WriteData(0x20);
+
+ // Memory Access Control
+ WriteCommand(CMD_MADCTL);
+ WriteData(0x48);
+
+ // Display Function Control
+ WriteCommand(CMD_DFUNCTR);
+ WriteData(0x08);
+ WriteData(0x82);
+ WriteData(0x27);
+
+ // Enable 3 gamma control - Disable 3 Gamma Function
+ WriteCommand(CMD_EN3G);
+ WriteData(0x00);
+
+ // Gamma Set - Gamma curve selected
+ WriteCommand(CMD_GAMMASET);
+ WriteData(0x01);
+
+ // Positive Gamma Correction
+ WriteCommand(CMD_GMCTRP1);
+ WriteData(0x0F);
+ WriteData(0x31);
+ WriteData(0x2B);
+ WriteData(0x0C);
+ WriteData(0x0E);
+ WriteData(0x08);
+ WriteData(0x4E);
+ WriteData(0xF1);
+ WriteData(0x37);
+ WriteData(0x07);
+ WriteData(0x10);
+ WriteData(0x03);
+ WriteData(0x0E);
+ WriteData(0x09);
+ WriteData(0x00);
+
+ // Negative Gamma Correction
+ WriteCommand(CMD_GMCTRN1);
+ WriteData(0x00);
+ WriteData(0x0E);
+ WriteData(0x14);
+ WriteData(0x03);
+ WriteData(0x11);
+ WriteData(0x07);
+ WriteData(0x31);
+ WriteData(0xC1);
+ WriteData(0x48);
+ WriteData(0x08);
+ WriteData(0x0F);
+ WriteData(0x0C);
+ WriteData(0x31);
+ WriteData(0x36);
+ WriteData(0x0F);
+
+ // Interface Control
+ WriteCommand(CMD_INTCTRL);
+ WriteData(0x01);
+ WriteData(0x00);
+ WriteData(0x01 << 5);
+
+ // Exit Sleep
+ WriteCommand(CMD_SLPOUT);
+ // Delay for execute previous command
+ HAL_Delay(120U);
+ // Display on
+ WriteCommand(CMD_DISPON);
+}
+
+// *****************************************************************************
+// *** Set output window ***************************************************
+// *****************************************************************************
+void ILI9341::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
+{
+ WriteCommand(CMD_CASET); // Column address set
+ WriteData(x0 >> 8);
+ WriteData(x0 & 0xFF); // XSTART
+ WriteData(x1 >> 8);
+ WriteData(x1 & 0xFF); // XEND
+
+ WriteCommand(CMD_PASET); // Row address set
+ WriteData(y0 >> 8);
+ WriteData(y0); // YSTART
+ WriteData(y1 >> 8);
+ WriteData(y1); // YEND
+
+ WriteCommand(CMD_RAMWR); // write to RAM
+
+ // Prepare for write data
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data
+}
+
+// *****************************************************************************
+// *** Pass 8-bit (each) R,G,B, get back 16-bit packed color ***************
+// *****************************************************************************
+uint16_t ILI9341::GetColor565(uint8_t r, uint8_t g, uint8_t b)
+{
+ return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
+}
+
+// *****************************************************************************
+// *** Set screen orientation **********************************************
+// *****************************************************************************
+void ILI9341::SetRotation(uint8_t m)
+{
+ WriteCommand(CMD_MADCTL);
+ rotation = m % 4; // can't be higher than 3
+ switch (rotation)
+ {
+ case 0:
+ WriteData(MADCTL_BGR);
+ width = TFT_HEIGHT;
+ height = TFT_WIDTH;
+ break;
+
+ case 1:
+ WriteData(MADCTL_MV | MADCTL_BGR);
+ width = TFT_WIDTH;
+ height = TFT_HEIGHT;
+ break;
+
+ case 2: // Y: up -> down
+ WriteData(MADCTL_MX | MADCTL_MY | MADCTL_BGR);
+ width = TFT_HEIGHT;
+ height = TFT_WIDTH;
+ break;
+
+ case 3: // X: left -> right
+ WriteData(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
+ width = TFT_WIDTH;
+ height = TFT_HEIGHT;
+ break;
+
+ default:
+ break;
+ }
+}
+
+// *****************************************************************************
+// *** Write color to screen ***********************************************
+// *****************************************************************************
+void ILI9341::PushColor(uint16_t color)
+{
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data
+
+ SpiWrite(color >> 8);
+ SpiWrite(color);
+}
+
+// *****************************************************************************
+// *** Draw one pixel on screen *******************************************
+// *****************************************************************************
+void ILI9341::DrawPixel(int16_t x, int16_t y, uint16_t color)
+{
+ if((x < 0) ||(x >= width) || (y < 0) || (y >= height)) return;
+
+ SetAddrWindow(x,y,x+1,y+1);
+
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data
+
+ SpiWrite(color >> 8);
+ SpiWrite(color);
+}
+
+// *****************************************************************************
+// *** Draw vertical line **************************************************
+// *****************************************************************************
+void ILI9341::DrawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
+{
+ // Rudimentary clipping
+ if((x >= width) || (y >= height)) return;
+
+ if((y+h-1) >= height) h = height-y;
+
+ SetAddrWindow(x, y, x, y+h-1);
+
+ uint8_t hi = color >> 8, lo = color;
+
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data
+
+ while (h--)
+ {
+ SpiWrite(hi);
+ SpiWrite(lo);
+ }
+}
+
+// *****************************************************************************
+// *** Draw horizontal line ************************************************
+// *****************************************************************************
+void ILI9341::DrawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
+{
+ if((x >= width) || (y >= height)) return;
+ if((x+w-1) >= width) w = width-x;
+
+ SetAddrWindow(x, y, x+w-1, y);
+
+ uint8_t hi = color >> 8, lo = color;
+
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data
+
+ while (w--)
+ {
+ SpiWrite(hi);
+ SpiWrite(lo);
+ }
+}
+
+// *****************************************************************************
+// *** Fill full screen ****************************************************
+// *****************************************************************************
+void ILI9341::FillScreen(uint16_t color)
+{
+ FillRect(0, 0, width, height, color);
+}
+
+// *****************************************************************************
+// *** Fill rectangle on screen ********************************************
+// *****************************************************************************
+void ILI9341::FillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
+{
+ if((x >= width) || (y >= height)) return;
+ if((x + w - 1) >= width) w = width - x;
+ if((y + h - 1) >= height) h = height - y;
+
+ SetAddrWindow(x, y, x+w-1, y+h-1);
+
+ uint8_t hi = color >> 8, lo = color;
+
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data
+
+ HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); // Pull down CS
+ for(y=h; y>0; y--)
+ {
+ for(x=w; x>0; x--)
+ {
+ // Wait until TXE flag is set to send data
+ while(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == RESET);
+ hspi->Instance->DR = hi;
+ while(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == RESET);
+ hspi->Instance->DR = lo;
+ }
+ }
+ HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); // Pull up CS
+}
+
+// *****************************************************************************
+// *** Invert display ******************************************************
+// *****************************************************************************
+void ILI9341::InvertDisplay(bool invert)
+{
+ WriteCommand(invert ? CMD_INVON : CMD_INVOFF);
+}
+
+// *****************************************************************************
+// *** Read data from SPI **************************************************
+// *****************************************************************************
+inline uint8_t ILI9341::SpiRead(void)
+{
+ // Result variable
+ uint8_t r = 0;
+ // Pull down CS
+ HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
+ // Receive data
+ HAL_SPI_Receive(hspi, &r, sizeof(r), 100U);
+ // Pull up CS
+ HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
+ // Return result
+ return r;
+}
+
+// *****************************************************************************
+// *** Read data from display **********************************************
+// *****************************************************************************
+inline uint8_t ILI9341::ReadData(void)
+{
+ // Data
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data
+ // Receive data
+ uint8_t r = SpiRead();
+ // Return result
+ return r;
+}
+
+// *****************************************************************************
+// *** Send read command ad read result ************************************
+// *****************************************************************************
+uint8_t ILI9341::ReadCommand(uint8_t c)
+{
+ // Set command mode
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET); // Command
+ SpiWrite(c);
+
+ // Set data mode
+ HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); // Data
+ // Receive data
+ uint8_t r = SpiRead();
+
+ // Return result
+ return r;
+}
diff --git a/Display/ILI9341.h b/Display/ILI9341.h
new file mode 100644
index 0000000..15712c1
--- /dev/null
+++ b/Display/ILI9341.h
@@ -0,0 +1,258 @@
+//******************************************************************************
+// @file ILI9341.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: ILI9341 Low Level Driver Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+//******************************************************************************
+
+#ifndef ILI9341_h
+#define ILI9341_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include <DevCfg.h>
+
+// *****************************************************************************
+// *** Enums ***************************************************************
+// *****************************************************************************
+
+// Color definitions
+enum Color
+{
+ COLOR_BLACK = 0x0000, // 0, 0, 0
+ COLOR_VERYDARKGREY = 0xEF7B, // 32, 32, 32
+ COLOR_DARKGREY = 0xEF7B, // 64, 64, 64
+ COLOR_GREY = 0xEF7B, // 128, 128, 128
+ COLOR_LIGHTGREY = 0x18C6, // 192, 192, 192
+ COLOR_WHITE = 0xFFFF, // 255, 255, 255
+
+ COLOR_VERYDARKRED = 0x0018, // 32, 0, 0
+ COLOR_DARKRED = 0x0038, // 64, 0, 0
+ COLOR_MEDIUMRED = 0x0078, // 128, 0, 0
+ COLOR_LIGHTRED = 0x00B8, // 192, 0, 0
+ COLOR_RED = 0x00F8, // 255, 0, 0
+
+ COLOR_VERYDARKGREEN = 0xE000, // 0, 32, 0
+ COLOR_DARKGREEN = 0xE001, // 0, 64, 0
+ COLOR_MEDIUMGREEN = 0xE003, // 0, 128, 0
+ COLOR_LIGHTGREEN = 0xE005, // 0, 192, 0
+ COLOR_GREEN = 0xE007, // 0, 255, 0
+
+ COLOR_VERYDARKBLUE = 0x0300, // 0, 0, 32
+ COLOR_DARKBLUE = 0x0700, // 0, 0, 64
+ COLOR_MEDIUMBLUE = 0x0F00, // 0, 0, 128
+ COLOR_LIGHTBLUE = 0x1700, // 0, 0, 192
+ COLOR_BLUE = 0x1F00, // 0, 0, 255
+
+ COLOR_VERYDARKYELLOW = 0xE018, // 32, 32, 0
+ COLOR_DARKYELLOW = 0xE039, // 64, 64, 0
+ COLOR_MEDIUMYELLOW = 0xE07B, // 128, 128, 0
+ COLOR_LIGHTYELLOW = 0xE0BD, // 192, 192, 0
+ COLOR_YELLOW = 0xE0FF, // 255, 255, 0
+
+ COLOR_VERYDARKCYAN = 0xE300, // 0, 32, 32
+ COLOR_DARKCYAN = 0xE701, // 0, 64, 64
+ COLOR_MEDIUMCYAN = 0xEF03, // 0, 128, 128
+ COLOR_LIGHTCYAN = 0xF705, // 0, 192, 192
+ COLOR_CYAN = 0xFF07, // 0, 255, 255
+
+ COLOR_VERYDARKMAGENTA = 0x0318, // 32, 0, 32
+ COLOR_DARKMAGENTA = 0x0738, // 64, 0, 64
+ COLOR_MEDIUMMAGENTA = 0x0F78, // 128, 0, 128
+ COLOR_LIGHTMAGENTA = 0x17B8, // 192, 0, 192
+ COLOR_MAGENTA = 0x1FF8, // 255, 0, 255
+};
+
+class ILI9341
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ ILI9341(SPI_HandleTypeDef* in_hspi);
+
+ // *************************************************************************
+ // *** Write byte to SPI ***********************************************
+ // *************************************************************************
+ inline void SpiWrite(uint8_t c);
+
+ // *************************************************************************
+ // *** Write byte stream to SPI ****************************************
+ // *************************************************************************
+ void SpiWriteStream(uint8_t* data, uint32_t n);
+
+ // *************************************************************************
+ // *** Write command to SPI ********************************************
+ // *************************************************************************
+ inline void WriteCommand(uint8_t c);
+
+ // *************************************************************************
+ // *** Write data to SPI ***********************************************
+ // *************************************************************************
+ inline void WriteData(uint8_t c);
+
+ // *************************************************************************
+ // *** Write data steram to SPI ****************************************
+ // *************************************************************************
+ void WriteDataStream(uint8_t* data, uint32_t n);
+
+ // *************************************************************************
+ // *** Check SPI transfer status ****************************************
+ // *************************************************************************
+ bool IsTransferComplete(void);
+
+ // *************************************************************************
+ // *** Pull up CS line for LCD ******************************************
+ // *************************************************************************
+ void StopTransfer(void);
+
+ // *************************************************************************
+ // *** Init screen *****************************************************
+ // *************************************************************************
+ void Init(void);
+
+ // *************************************************************************
+ // *** Set output window ***********************************************
+ // *************************************************************************
+ void SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
+
+ // *************************************************************************
+ // *** Pass 8-bit (each) R,G,B, get back 16-bit packed color ***********
+ // *************************************************************************
+ uint16_t GetColor565(uint8_t r, uint8_t g, uint8_t b);
+
+ // *************************************************************************
+ // *** Set screen orientation ******************************************
+ // *************************************************************************
+ void SetRotation(uint8_t r);
+
+ // *************************************************************************
+ // *** Write color to screen *******************************************
+ // *************************************************************************
+ void PushColor(uint16_t color);
+
+ // *************************************************************************
+ // *** Draw one pixel on screen ***************************************
+ // *************************************************************************
+ void DrawPixel(int16_t x, int16_t y, uint16_t color);
+
+ // *************************************************************************
+ // *** Draw vertical line **********************************************
+ // *************************************************************************
+ void DrawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
+
+ // *************************************************************************
+ // *** Draw horizontal line ********************************************
+ // *************************************************************************
+ void DrawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
+
+ // *************************************************************************
+ // *** Fill full screen ************************************************
+ // *************************************************************************
+ void FillScreen(uint16_t color);
+
+ // *************************************************************************
+ // *** Fill rectangle on screen ****************************************
+ // *************************************************************************
+ void FillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
+
+ // *************************************************************************
+ // *** Invert display **************************************************
+ // *************************************************************************
+ void InvertDisplay(bool invert);
+
+ // *************************************************************************
+ // *** Read data from SPI **********************************************
+ // *************************************************************************
+ inline uint8_t SpiRead(void);
+
+ // *************************************************************************
+ // *** Read data from display ******************************************
+ // *************************************************************************
+ inline uint8_t ReadData(void);
+
+ // *************************************************************************
+ // *** Send read command ad read result ********************************
+ // *************************************************************************
+ uint8_t ReadCommand(uint8_t c);
+
+ // *************************************************************************
+ // *** Return screen width *********************************************
+ // *************************************************************************
+ inline int32_t GetWidth(void) {return width;}
+
+ // *************************************************************************
+ // *** Return screen height ********************************************
+ // *************************************************************************
+ inline int32_t GetHeight(void) {return height;}
+
+ // *************************************************************************
+ // *** Return byte(s) per pixel ****************************************
+ // *************************************************************************
+ inline int32_t GetBytesPerPixel(void) {return byte_per_pixel;}
+
+ // *************************************************************************
+ // *** Return max line *************************************************
+ // *************************************************************************
+ static constexpr int32_t GetMaxLine(void) {return TFT_WIDTH > TFT_HEIGHT ? TFT_WIDTH : TFT_HEIGHT;}
+
+ // *************************************************************************
+ // *** Return max line *************************************************
+ // *************************************************************************
+ static constexpr int32_t GetMaxBpp(void) {return TFT_BPP;}
+
+ private:
+
+ // Display width
+ static const int32_t TFT_WIDTH = 320;
+ // Display height
+ static const int32_t TFT_HEIGHT = 240;
+ // Display byte per pixel
+ static const int32_t TFT_BPP = 2;
+
+ // Handle to screen SPI
+ SPI_HandleTypeDef* hspi = nullptr;
+
+ // Width
+ int32_t width = TFT_WIDTH;
+ // Height
+ int32_t height = TFT_HEIGHT;
+ // Byte(s) per pixel
+ int32_t byte_per_pixel = TFT_BPP;
+
+ // Rotation
+ uint32_t rotation = 0U;
+};
+
+#endif
diff --git a/Display/Image.cpp b/Display/Image.cpp
new file mode 100644
index 0000000..cc17e54
--- /dev/null
+++ b/Display/Image.cpp
@@ -0,0 +1,366 @@
+//******************************************************************************
+// @file Image.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Image Visual Object Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "Image.h"
+
+// *****************************************************************************
+// *****************************************************************************
+// *** Image ***************************************************************
+// *****************************************************************************
+// *****************************************************************************
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+Image::Image(int32_t x, int32_t y, const ImageDesc& img_dsc) : img_description(img_dsc)
+{
+ x_start = x;
+ y_start = y;
+ width = img_dsc.width;
+ height = img_dsc.height;
+ x_end = x + width - 1;
+ y_end = y + height - 1;
+ bits_per_pixel = img_dsc.bits_per_pixel;
+ img = img_dsc.img;
+ palette = img_dsc.palette;
+ transparent_color = img_dsc.transparent_color;
+ hor_mirror = false;
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Image::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ // Draw only if needed
+ if((line >= y_start) && (line <= y_end))
+ {
+ // Find idx in the image buffer
+ uint32_t idx = (line - y_start) * width;
+ // Find start x position
+ int32_t start = x_start - start_x;
+ // Prevent write in memory before buffer
+ if(start < 0)
+ {
+ // Minus minus - plus
+ idx -= start;
+ start = 0;
+ }
+ // Find start x position
+ int32_t end = x_end - start_x;
+ // Prevent buffer overflow
+ if(end >= n) end = n - 1;
+ // Delta for cycle increment/decrement
+ int32_t delta = 1;
+ // Flip horizontally if needed
+ if(hor_mirror)
+ {
+ idx += end - start;
+ // Set delta to minus one for decrement cycle
+ delta = -1;
+ }
+ // Draw image
+ if(bits_per_pixel == 16)
+ {
+ // Get pointer to 16-bit image data
+ uint16_t* p_img = (uint16_t*)img;
+ // Pixels data copy cycle
+ for(int32_t i = start; i <= end; i++)
+ {
+ // Get pixel data
+ uint16_t data = p_img[idx];
+ // Change index
+ idx += delta;
+ // If not transparent - output to buffer
+ if(data != transparent_color) buf[i] = data;
+ }
+ }
+ else
+ {
+ // Get pointer to 8-bit image data
+ uint8_t* p_img = (uint8_t*)img;
+ // Pixels data copy cycle
+ for(int32_t i = start; i <= end; i++)
+ {
+ // Get pixel data
+ uint16_t data = palette[p_img[idx]];
+ // Change index
+ idx += delta;
+ // If not transparent - output to buffer
+ if(data != transparent_color) buf[i] = data;
+ }
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Image::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ // Draw only if needed
+ if((row >= x_start) && (row <= x_end))
+ {
+ // Find start x position
+ int32_t start = y_start - start_y;
+ // Prevent write in memory before buffer
+ if(start < 0) start = 0;
+ // Find start x position
+ int32_t end = y_end - start_y;
+ // Prevent buffer overflow
+ if(end >= n) end = n - 1;
+ // Have sense draw only if end pointer in buffer
+ if(end > 0)
+ {
+ // Not implemented yet
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Set Image function **************************************************
+// *****************************************************************************
+void Image::SetImage(const ImageDesc& img_dsc, bool semaphore_taken)
+{
+ if(semaphore_taken == false) LockVisObject();
+ width = img_dsc.width;
+ height = img_dsc.height;
+ x_end = x_start + width - 1;
+ y_end = y_start + height - 1;
+ bits_per_pixel = img_dsc.bits_per_pixel;
+ img = img_dsc.img;
+ palette = img_dsc.palette;
+ transparent_color = img_dsc.transparent_color;
+ if(semaphore_taken == false) UnlockVisObject();
+}
+
+// *****************************************************************************
+// *****************************************************************************
+// *** Image8 **************************************************************
+// *****************************************************************************
+// *****************************************************************************
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+Image8::Image8(int32_t x, int32_t y, int32_t w, int32_t h, const uint8_t* p_img, const uint16_t* p_palette)
+{
+ x_start = x;
+ y_start = y;
+ x_end = x + w - 1;
+ y_end = y + h - 1;
+ width = w;
+ height = h;
+ img = p_img;
+ palette = p_palette;
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Image8::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ // Draw only if needed
+ if((line >= y_start) && (line <= y_end))
+ {
+ // Find start x position
+ int32_t start = x_start - start_x;
+ // Prevent write in memory before buffer
+ if(start < 0) start = 0;
+ // Find start x position
+ int32_t end = x_end - start_x;
+ // Prevent buffer overflow
+ if(end >= n) end = n - 1;
+ // Have sense draw only if end pointer in buffer
+ if(x_end > 0)
+ {
+ int idx = (line - y_start) * width;
+ for(int32_t i = start; i <= end; i++)
+ {
+ buf[i] = palette[img[idx++]];
+ }
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Image8::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ // Draw only if needed
+ if((row >= x_start) && (row <= x_end))
+ {
+ // Find start x position
+ int32_t start = y_start - start_y;
+ // Prevent write in memory before buffer
+ if(start < 0) start = 0;
+ // Find start x position
+ int32_t end = y_end - start_y;
+ // Prevent buffer overflow
+ if(end >= n) end = n - 1;
+ // Have sense draw only if end pointer in buffer
+ if(end > 0)
+ {
+ // Not implemented yet
+ }
+ }
+}
+
+// *****************************************************************************
+// *****************************************************************************
+// *** Image16 *************************************************************
+// *****************************************************************************
+// *****************************************************************************
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+Image16::Image16(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t* p_img)
+{
+ x_start = x;
+ y_start = y;
+ x_end = x + w - 1;
+ y_end = y + h - 1;
+ width = w;
+ height = h;
+ img = p_img;
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Image16::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ // Draw only if needed
+ if((line >= y_start) && (line <= y_end))
+ {
+ // Find start x position
+ int32_t start = x_start - start_x;
+ // Prevent write in memory before buffer
+ if(start < 0) start = 0;
+ // Find start x position
+ int32_t end = x_end - start_x;
+ // Prevent buffer overflow
+ if(end >= n) end = n - 1;
+ // Have sense draw only if end pointer in buffer
+ if(x_end > 0)
+ {
+ int idx = (line - y_start) * width;
+ for(int32_t i = start; i <= end; i++)
+ {
+ buf[i] = img[idx++];
+ }
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Image16::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ // Draw only if needed
+ if((row >= x_start) && (row <= x_end))
+ {
+ // Find start x position
+ int32_t start = y_start - start_y;
+ // Prevent write in memory before buffer
+ if(start < 0) start = 0;
+ // Find start x position
+ int32_t end = y_end - start_y;
+ // Prevent buffer overflow
+ if(end >= n) end = n - 1;
+ // Have sense draw only if end pointer in buffer
+ if(end > 0)
+ {
+ // Not implemented yet
+ }
+ }
+}
+
+// *****************************************************************************
+// *****************************************************************************
+// *** Palettes ************************************************************
+// *****************************************************************************
+// *****************************************************************************
+
+// *****************************************************************************
+// *** Palette with 8R-8G-4B levels (bits 3-3-2) ***************************
+// *****************************************************************************
+const uint16_t PALETTE_884[256] = {
+0x0000, 0x0020, 0x0040, 0x0068, 0x0088, 0x00B0, 0x00D0, 0x00F8, 0x0001, 0x0021, 0x0041, 0x0069, 0x0089, 0x00B1, 0x00D1, 0x00F9,
+0x2002, 0x2022, 0x2042, 0x206A, 0x208A, 0x20B2, 0x20D2, 0x20FA, 0x4003, 0x4023, 0x4043, 0x406B, 0x408B, 0x40B3, 0x40D3, 0x40FB,
+0x6004, 0x6024, 0x6044, 0x606C, 0x608C, 0x60B4, 0x60D4, 0x60FC, 0x8005, 0x8025, 0x8045, 0x806D, 0x808D, 0x80B5, 0x80D5, 0x80FD,
+0xA006, 0xA026, 0xA046, 0xA06E, 0xA08E, 0xA0B6, 0xA0D6, 0xA0FE, 0xE007, 0xE027, 0xE047, 0xE06F, 0xE08F, 0xE0B7, 0xE0D7, 0xE0FF,
+0x0A00, 0x0A20, 0x0A40, 0x0A68, 0x0A88, 0x0AB0, 0x0AD0, 0x0AF8, 0x0A01, 0x0A21, 0x0A41, 0x0A69, 0x0A89, 0x0AB1, 0x0AD1, 0x0AF9,
+0x2A02, 0x2A22, 0x2A42, 0x2A6A, 0x2A8A, 0x2AB2, 0x2AD2, 0x2AFA, 0x4A03, 0x4A23, 0x4A43, 0x4A6B, 0x4A8B, 0x4AB3, 0x4AD3, 0x4AFB,
+0x6A04, 0x6A24, 0x6A44, 0x6A6C, 0x6A8C, 0x6AB4, 0x6AD4, 0x6AFC, 0x8A05, 0x8A25, 0x8A45, 0x8A6D, 0x8A8D, 0x8AB5, 0x8AD5, 0x8AFD,
+0xAA06, 0xAA26, 0xAA46, 0xAA6E, 0xAA8E, 0xAAB6, 0xAAD6, 0xAAFE, 0xEA07, 0xEA27, 0xEA47, 0xEA6F, 0xEA8F, 0xEAB7, 0xEAD7, 0xEAFF,
+0x1400, 0x1420, 0x1440, 0x1468, 0x1488, 0x14B0, 0x14D0, 0x14F8, 0x1401, 0x1421, 0x1441, 0x1469, 0x1489, 0x14B1, 0x14D1, 0x14F9,
+0x3402, 0x3422, 0x3442, 0x346A, 0x348A, 0x34B2, 0x34D2, 0x34FA, 0x5403, 0x5423, 0x5443, 0x546B, 0x548B, 0x54B3, 0x54D3, 0x54FB,
+0x7404, 0x7424, 0x7444, 0x746C, 0x748C, 0x74B4, 0x74D4, 0x74FC, 0x9405, 0x9425, 0x9445, 0x946D, 0x948D, 0x94B5, 0x94D5, 0x94FD,
+0xB406, 0xB426, 0xB446, 0xB46E, 0xB48E, 0xB4B6, 0xB4D6, 0xB4FE, 0xF407, 0xF427, 0xF447, 0xF46F, 0xF48F, 0xF4B7, 0xF4D7, 0xF4FF,
+0x1F00, 0x1F20, 0x1F40, 0x1F68, 0x1F88, 0x1FB0, 0x1FD0, 0x1FF8, 0x1F01, 0x1F21, 0x1F41, 0x1F69, 0x1F89, 0x1FB1, 0x1FD1, 0x1FF9,
+0x3F02, 0x3F22, 0x3F42, 0x3F6A, 0x3F8A, 0x3FB2, 0x3FD2, 0x3FFA, 0x5F03, 0x5F23, 0x5F43, 0x5F6B, 0x5F8B, 0x5FB3, 0x5FD3, 0x5FFB,
+0x7F04, 0x7F24, 0x7F44, 0x7F6C, 0x7F8C, 0x7FB4, 0x7FD4, 0x7FFC, 0x9F05, 0x9F25, 0x9F45, 0x9F6D, 0x9F8D, 0x9FB5, 0x9FD5, 0x9FFD,
+0xBF06, 0xBF26, 0xBF46, 0xBF6E, 0xBF8E, 0xBFB6, 0xBFD6, 0xBFFE, 0xFF07, 0xFF27, 0xFF47, 0xFF6F, 0xFF8F, 0xFFB7, 0xFFD7, 0xFFFF};
+
+// *****************************************************************************
+// *** Palette with 7R-7G-5B levels (245 colors) ***************************
+// *****************************************************************************
+const uint16_t PALETTE_775[256] = {
+0x0000, 0x0028, 0x0050, 0x0078, 0x00A0, 0x00C8, 0x00F8, 0x4001, 0x4029, 0x4051, 0x4079, 0x40A1, 0x40C9, 0x40F9, 0xA002, 0xA02A,
+0xA052, 0xA07A, 0xA0A2, 0xA0CA, 0xA0FA, 0xE003, 0xE02B, 0xE053, 0xE07B, 0xE0A3, 0xE0CB, 0xE0FB, 0x4005, 0x402D, 0x4055, 0x407D,
+0x40A5, 0x40CD, 0x40FD, 0x8006, 0x802E, 0x8056, 0x807E, 0x80A6, 0x80CE, 0x80FE, 0xE007, 0xE02F, 0xE057, 0xE07F, 0xE0A7, 0xE0CF,
+0xE0FF, 0x0700, 0x0728, 0x0750, 0x0778, 0x07A0, 0x07C8, 0x07F8, 0x4701, 0x4729, 0x4751, 0x4779, 0x47A1, 0x47C9, 0x47F9, 0xA702,
+0xA72A, 0xA752, 0xA77A, 0xA7A2, 0xA7CA, 0xA7FA, 0xE703, 0xE72B, 0xE753, 0xE77B, 0xE7A3, 0xE7CB, 0xE7FB, 0x4705, 0x472D, 0x4755,
+0x477D, 0x47A5, 0x47CD, 0x47FD, 0x8706, 0x872E, 0x8756, 0x877E, 0x87A6, 0x87CE, 0x87FE, 0xE707, 0xE72F, 0xE757, 0xE77F, 0xE7A7,
+0xE7CF, 0xE7FF, 0x0F00, 0x0F28, 0x0F50, 0x0F78, 0x0FA0, 0x0FC8, 0x0FF8, 0x4F01, 0x4F29, 0x4F51, 0x4F79, 0x4FA1, 0x4FC9, 0x4FF9,
+0xAF02, 0xAF2A, 0xAF52, 0xAF7A, 0xAFA2, 0xAFCA, 0xAFFA, 0xEF03, 0xEF2B, 0xEF53, 0xEF7B, 0xEFA3, 0xEFCB, 0xEFFB, 0x4F05, 0x4F2D,
+0x4F55, 0x4F7D, 0x4FA5, 0x4FCD, 0x4FFD, 0x8F06, 0x8F2E, 0x8F56, 0x8F7E, 0x8FA6, 0x8FCE, 0x8FFE, 0xEF07, 0xEF2F, 0xEF57, 0xEF7F,
+0xEFA7, 0xEFCF, 0xEFFF, 0x1700, 0x1728, 0x1750, 0x1778, 0x17A0, 0x17C8, 0x17F8, 0x5701, 0x5729, 0x5751, 0x5779, 0x57A1, 0x57C9,
+0x57F9, 0xB702, 0xB72A, 0xB752, 0xB77A, 0xB7A2, 0xB7CA, 0xB7FA, 0xF703, 0xF72B, 0xF753, 0xF77B, 0xF7A3, 0xF7CB, 0xF7FB, 0x5705,
+0x572D, 0x5755, 0x577D, 0x57A5, 0x57CD, 0x57FD, 0x9706, 0x972E, 0x9756, 0x977E, 0x97A6, 0x97CE, 0x97FE, 0xF707, 0xF72F, 0xF757,
+0xF77F, 0xF7A7, 0xF7CF, 0xF7FF, 0x1F00, 0x1F28, 0x1F50, 0x1F78, 0x1FA0, 0x1FC8, 0x1FF8, 0x5F01, 0x5F29, 0x5F51, 0x5F79, 0x5FA1,
+0x5FC9, 0x5FF9, 0xBF02, 0xBF2A, 0xBF52, 0xBF7A, 0xBFA2, 0xBFCA, 0xBFFA, 0xFF03, 0xFF2B, 0xFF53, 0xFF7B, 0xFFA3, 0xFFCB, 0xFFFB,
+0x5F05, 0x5F2D, 0x5F55, 0x5F7D, 0x5FA5, 0x5FCD, 0x5FFD, 0x9F06, 0x9F2E, 0x9F56, 0x9F7E, 0x9FA6, 0x9FCE, 0x9FFE, 0xFF07, 0xFF2F,
+0xFF57, 0xFF7F, 0xFFA7, 0xFFCF, 0xFFFF, 0x0000, 0x0028, 0x0050, 0x0078, 0x00A0, 0x00C8, 0x00F8, 0x4001, 0x4029, 0x4051, 0x4079};
+
+// *****************************************************************************
+// *** Palette with 6R-7G-6B levels (252 colors) ***************************
+// *****************************************************************************
+const uint16_t PALETTE_676[256] = {
+0x0000, 0x0030, 0x0060, 0x0090, 0x00C0, 0x00F8, 0x4001, 0x4031, 0x4061, 0x4091, 0x40C1, 0x40F9, 0xA002, 0xA032, 0xA062, 0xA092,
+0xA0C2, 0xA0FA, 0xE003, 0xE033, 0xE063, 0xE093, 0xE0C3, 0xE0FB, 0x4005, 0x4035, 0x4065, 0x4095, 0x40C5, 0x40FD, 0x8006, 0x8036,
+0x8066, 0x8096, 0x80C6, 0x80FE, 0xE007, 0xE037, 0xE067, 0xE097, 0xE0C7, 0xE0FF, 0x0600, 0x0630, 0x0660, 0x0690, 0x06C0, 0x06F8,
+0x4601, 0x4631, 0x4661, 0x4691, 0x46C1, 0x46F9, 0xA602, 0xA632, 0xA662, 0xA692, 0xA6C2, 0xA6FA, 0xE603, 0xE633, 0xE663, 0xE693,
+0xE6C3, 0xE6FB, 0x4605, 0x4635, 0x4665, 0x4695, 0x46C5, 0x46FD, 0x8606, 0x8636, 0x8666, 0x8696, 0x86C6, 0x86FE, 0xE607, 0xE637,
+0xE667, 0xE697, 0xE6C7, 0xE6FF, 0x0C00, 0x0C30, 0x0C60, 0x0C90, 0x0CC0, 0x0CF8, 0x4C01, 0x4C31, 0x4C61, 0x4C91, 0x4CC1, 0x4CF9,
+0xAC02, 0xAC32, 0xAC62, 0xAC92, 0xACC2, 0xACFA, 0xEC03, 0xEC33, 0xEC63, 0xEC93, 0xECC3, 0xECFB, 0x4C05, 0x4C35, 0x4C65, 0x4C95,
+0x4CC5, 0x4CFD, 0x8C06, 0x8C36, 0x8C66, 0x8C96, 0x8CC6, 0x8CFE, 0xEC07, 0xEC37, 0xEC67, 0xEC97, 0xECC7, 0xECFF, 0x1200, 0x1230,
+0x1260, 0x1290, 0x12C0, 0x12F8, 0x5201, 0x5231, 0x5261, 0x5291, 0x52C1, 0x52F9, 0xB202, 0xB232, 0xB262, 0xB292, 0xB2C2, 0xB2FA,
+0xF203, 0xF233, 0xF263, 0xF293, 0xF2C3, 0xF2FB, 0x5205, 0x5235, 0x5265, 0x5295, 0x52C5, 0x52FD, 0x9206, 0x9236, 0x9266, 0x9296,
+0x92C6, 0x92FE, 0xF207, 0xF237, 0xF267, 0xF297, 0xF2C7, 0xF2FF, 0x1800, 0x1830, 0x1860, 0x1890, 0x18C0, 0x18F8, 0x5801, 0x5831,
+0x5861, 0x5891, 0x58C1, 0x58F9, 0xB802, 0xB832, 0xB862, 0xB892, 0xB8C2, 0xB8FA, 0xF803, 0xF833, 0xF863, 0xF893, 0xF8C3, 0xF8FB,
+0x5805, 0x5835, 0x5865, 0x5895, 0x58C5, 0x58FD, 0x9806, 0x9836, 0x9866, 0x9896, 0x98C6, 0x98FE, 0xF807, 0xF837, 0xF867, 0xF897,
+0xF8C7, 0xF8FF, 0x1F00, 0x1F30, 0x1F60, 0x1F90, 0x1FC0, 0x1FF8, 0x5F01, 0x5F31, 0x5F61, 0x5F91, 0x5FC1, 0x5FF9, 0xBF02, 0xBF32,
+0xBF62, 0xBF92, 0xBFC2, 0xBFFA, 0xFF03, 0xFF33, 0xFF63, 0xFF93, 0xFFC3, 0xFFFB, 0x5F05, 0x5F35, 0x5F65, 0x5F95, 0x5FC5, 0x5FFD,
+0x9F06, 0x9F36, 0x9F66, 0x9F96, 0x9FC6, 0x9FFE, 0xFF07, 0xFF37, 0xFF67, 0xFF97, 0xFFC7, 0xFFFF, 0x0000, 0x0030, 0x0060, 0x0090};
diff --git a/Display/Image.h b/Display/Image.h
new file mode 100644
index 0000000..57061bd
--- /dev/null
+++ b/Display/Image.h
@@ -0,0 +1,178 @@
+//******************************************************************************
+// @file Image.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Image Visual Object Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+//******************************************************************************
+
+#ifndef Images_h
+#define Images_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "VisObject.h"
+
+// *****************************************************************************
+// *** Palettes external ***************************************************
+// *****************************************************************************
+extern const uint16_t PALETTE_884[256];
+extern const uint16_t PALETTE_775[256];
+extern const uint16_t PALETTE_676[256];
+
+// *****************************************************************************
+// *** Image description structure *****************************************
+// *****************************************************************************
+typedef struct typeImageDesc
+{
+ // Image width
+ uint16_t width;
+ // Image height
+ uint16_t height;
+ // Bits per pixel
+ uint8_t bits_per_pixel;
+ // Pointer to image data
+ union
+ {
+ const uint8_t* img8;
+ const uint16_t* img16;
+ const void* img;
+ };
+ // Pointer to palette
+ const uint16_t* palette;
+ // Transparent color (-1 no transparent colors)
+ int32_t transparent_color;
+} ImageDesc;
+
+// *****************************************************************************
+// *** Universal Image Class ***********************************************
+// *****************************************************************************
+class Image : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ Image(int32_t x, int32_t y, const ImageDesc& img_dsc);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ // *************************************************************************
+ // *** Set Horizontal Flip function ************************************
+ // *************************************************************************
+ void SetHorizontalFlip(bool flip) {hor_mirror = flip;}
+
+ // *************************************************************************
+ // *** Set Image function **********************************************
+ // *************************************************************************
+ void SetImage(const ImageDesc& img_dsc, bool semaphore_taken = false);
+
+ protected:
+ // Reference to image description structure
+ const ImageDesc& img_description;
+ // Bits per pixel
+ uint8_t bits_per_pixel;
+ // Pointer to the image
+ const void* img;
+ // Pointer to the palette
+ const uint16_t* palette;
+ // Transparent color (-1 no transparent colors)
+ int32_t transparent_color;
+ // Horizontal mirror
+ bool hor_mirror;
+};
+
+// *****************************************************************************
+// *** Image 8-bit Class ***************************************************
+// *****************************************************************************
+class Image8 : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ Image8(int32_t x, int32_t y, int32_t w, int32_t h, const uint8_t* p_img, const uint16_t* p_palette);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ private:
+ // Pointer to the image
+ const uint8_t* img;
+ // Pointer to the palette
+ const uint16_t* palette;
+};
+
+// *****************************************************************************
+// *** Image 16-bit Class ***************************************************
+// *****************************************************************************
+class Image16 : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ Image16(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t* p_img);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ private:
+ // Pointer to the image
+ const uint16_t* img;
+};
+
+#endif
diff --git a/Display/Primitives.cpp b/Display/Primitives.cpp
new file mode 100644
index 0000000..2b7ad57
--- /dev/null
+++ b/Display/Primitives.cpp
@@ -0,0 +1,326 @@
+//******************************************************************************
+// @file Primitives.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Primitives Visual Object Classes(Box, Line, Circle), implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "Primitives.h"
+
+#include <cstdlib> // for abs()
+
+// *****************************************************************************
+// *****************************************************************************
+// *** Box *****************************************************************
+// *****************************************************************************
+// *****************************************************************************
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+Box::Box(int32_t x, int32_t y, int32_t w, int32_t h, int32_t c, bool is_fill)
+{
+ SetParams(x, y, w, h, c, is_fill);
+}
+
+// *****************************************************************************
+// *** SetParams ***********************************************************
+// *****************************************************************************
+void Box::SetParams(int32_t x, int32_t y, int32_t w, int32_t h, int32_t c, bool is_fill)
+{
+ color = c;
+ x_start = x;
+ y_start = y;
+ x_end = x + w - 1;
+ y_end = y + h - 1;
+ width = w;
+ height = h;
+ rotation = 0;
+ fill = is_fill;
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Box::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ // Draw only if needed
+ if((line >= y_start) && (line <= y_end))
+ {
+ // Find start x position
+ int32_t start = x_start - start_x;
+ // Prevent write in memory before buffer
+ if(start < 0) start = 0;
+ // Find start x position
+ int32_t end = x_end - start_x;
+ // Prevent buffer overflow
+ if(end >= n) end = n - 1;
+ // Have sense draw only if end pointer in buffer
+ if(end > 0)
+ {
+ // If fill or first/last line - must be solid
+ if(fill || line == y_start || line == y_end)
+ {
+ for(int32_t i = start; i <= end; i++) buf[i] = color;
+ }
+ else
+ {
+ if(x_start - start_x >= 0) buf[start] = color;
+ if(x_end - start_x < n) buf[end] = color;
+ }
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Box::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ // Draw only if needed
+ if((row >= x_start) && (row <= x_end))
+ {
+ // Find start x position
+ int32_t start = y_start - start_y;
+ // Prevent write in memory before buffer
+ if(start < 0) start = 0;
+ // Find start x position
+ int32_t end = y_end - start_y;
+ // Prevent buffer overflow
+ if(end >= n) end = n - 1;
+ // Have sense draw only if end pointer in buffer
+ if(end > 0)
+ {
+ // If fill or first/last row - must be solid
+ if(fill || row == x_start || row == x_end)
+ {
+ for(int32_t i = start; i <= end; i++) buf[i] = color;
+ }
+ else
+ {
+ if(y_start - start_y >= 0) buf[start] = color;
+ if(y_end - start_y < n) buf[end] = color;
+ }
+ }
+ }
+}
+
+// *****************************************************************************
+// *****************************************************************************
+// *** Line ****************************************************************
+// *****************************************************************************
+// *****************************************************************************
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+Line::Line(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t c)
+{
+ SetParams(x1, y1, x2, y2, c);
+}
+
+// *****************************************************************************
+// *** SetParams ***********************************************************
+// *****************************************************************************
+void Line::SetParams(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t c)
+{
+ color = c;
+ x_start = x1;
+ y_start = y1;
+ x_end = x2;
+ y_end = y2;
+ width = (x1 < x2) ? (x2 - x1) : (x1 - x2);
+ height = (y1 < y2) ? (y2 - y1) : (y1 - y2);
+ rotation = 0;
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Line::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ // Draw only if needed
+ if((line >= y_start) && (line <= y_end))
+ {
+ const int32_t deltaX = abs(x_end - x_start);
+ const int32_t deltaY = abs(y_end - y_start);
+ const int32_t signX = x_start < x_end ? 1 : -1;
+ const int32_t signY = y_start < y_end ? 1 : -1;
+
+ int32_t error = deltaX - deltaY;
+
+ int32_t x = x_start - start_x;
+ int32_t y = y_start;
+
+ int32_t end_x = x_end - start_x;
+ while((x != end_x || y != y_end) && (y != line))
+ {
+ const int32_t error2 = error * 2;
+ if(error2 > -deltaY)
+ {
+ error -= deltaY;
+ x += signX;
+ }
+ if(error2 < deltaX)
+ {
+ error += deltaX;
+ y += signY;
+ }
+ }
+
+ while((x != end_x || y != y_end) && (y == line))
+ {
+ if((x >= 0) && (x < n)) buf[x] = color;
+ const int32_t error2 = error * 2;
+ if(error2 > -deltaY)
+ {
+ error -= deltaY;
+ x += signX;
+ }
+ if(error2 < deltaX)
+ {
+ break;
+ }
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Line::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ // FIX ME: implement for Vertical Update Mode too
+}
+
+// *****************************************************************************
+// *****************************************************************************
+// *** Circle **************************************************************
+// *****************************************************************************
+// *****************************************************************************
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+Circle::Circle(int32_t x, int32_t y, int32_t r, int32_t c, bool is_fill)
+{
+ SetParams(x, y, r, c, is_fill);
+}
+
+// *****************************************************************************
+// *** SetParams ***********************************************************
+// *****************************************************************************
+void Circle::SetParams(int32_t x, int32_t y, int32_t r, int32_t c, bool is_fill)
+{
+ color = c;
+ radius = r;
+ x_start = x - r;
+ y_start = y - r;
+ x_end = x + r;
+ y_end = y + r;
+ width = r*2;
+ height = r*2;
+ rotation = 0;
+ fill = is_fill;
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Circle::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ // Draw only if needed
+ if((line >= y_start) && (line <= y_end))
+ {
+ int32_t x = 0;
+ int32_t y = radius;
+ int32_t x0 = x_start + radius - start_x;
+ int32_t y0 = y_start + radius;
+ int32_t delta = 1 - 2 * radius;
+ int32_t error = 0;
+ bool line_drawed = false;
+
+ while(y >= 0)
+ {
+ if( (y0 + y == line) || (y0 - y == line) )
+ {
+ if(fill)
+ {
+ int32_t i = x0 - x;
+ if(i < 0) i = 0;
+ if(x0 + x < n) n = x0 + x;
+ for(;i < n; i++)
+ {
+ buf[i] = color;
+ }
+ break;
+ }
+ else
+ {
+ int32_t xl = x0 - x;
+ int32_t xr = x0 + x;
+ if((xl > 0) && (xl < n)) buf[xl] = color;
+ if((xr > 0) && (xr < n)) buf[xr] = color;
+ }
+ line_drawed = true;
+ }
+ else
+ {
+ if(line_drawed == true) break;
+ }
+ error = 2 * (delta + y) - 1;
+ if(delta < 0 && error <= 0)
+ {
+ ++x;
+ delta += 2 * x + 1;
+ continue;
+ }
+ error = 2 * (delta - x) - 1;
+ if(delta > 0 && error > 0)
+ {
+ --y;
+ delta += 1 - 2 * y;
+ continue;
+ }
+ ++x;
+ delta += 2 * (x - y);
+ --y;
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void Circle::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ if((row >= x_start) && (row <= x_end))
+ {
+ // Find start x position
+ int32_t start = y_start - start_y;
+ // Prevent write in memory before buffer
+ if(start < 0) start = 0;
+ // Find start x position
+ int32_t end = y_end - start_y;
+ // Prevent buffer overflow
+ if(end > n) end = n;
+ // Have sense draw only if end pointer in buffer
+ if(end > 0)
+ {
+ for(int32_t i = start; i < end; i++) buf[i] = color;
+ }
+ }
+}
diff --git a/Display/Primitives.h b/Display/Primitives.h
new file mode 100644
index 0000000..2a4e0ee
--- /dev/null
+++ b/Display/Primitives.h
@@ -0,0 +1,161 @@
+//******************************************************************************
+// @file Primitives.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Primitives Visual Object Classes(Box, Line, Circle), header
+//
+// @section LICENSE
+//
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+//******************************************************************************
+
+#ifndef Primitives_h
+#define Primitives_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "VisObject.h"
+
+// *****************************************************************************
+// *** Box Class ***********************************************************
+// *****************************************************************************
+class Box : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ Box() {};
+
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ Box(int32_t x, int32_t y, int32_t w, int32_t h, int32_t c, bool is_fill = false);
+
+ // *************************************************************************
+ // *** SetParams *******************************************************
+ // *************************************************************************
+ void SetParams(int32_t x, int32_t y, int32_t w, int32_t h, int32_t c, bool is_fill = false);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ private:
+ // Box color
+ uint16_t color = 0U;
+ // Is box fill ?
+ bool fill = false;
+};
+
+// *****************************************************************************
+// *** Line Class **********************************************************
+// *****************************************************************************
+class Line : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ Line() {};
+
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ Line(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t c);
+
+ // *************************************************************************
+ // *** SetParams *******************************************************
+ // *************************************************************************
+ void SetParams(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t c);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ private:
+ // Line color
+ uint16_t color = 0U;
+};
+
+// *****************************************************************************
+// *** Circle Class ********************************************************
+// *****************************************************************************
+class Circle : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ Circle() {};
+
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ Circle(int32_t x, int32_t y, int32_t r, int32_t c, bool is_fill = false);
+
+ // *************************************************************************
+ // *** SetParams **************************************II***************
+ // *************************************************************************
+ void SetParams(int32_t x, int32_t y, int32_t r, int32_t c, bool is_fill = false);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ private:
+ // Circle color
+ uint16_t color = 0U;
+ // Circle radius
+ int16_t radius = 0;
+ // Is box fill ?
+ bool fill = false;
+};
+
+#endif
diff --git a/Display/Strings.cpp b/Display/Strings.cpp
new file mode 100644
index 0000000..e600867
--- /dev/null
+++ b/Display/Strings.cpp
@@ -0,0 +1,242 @@
+//******************************************************************************
+// @file String.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: String Visual Object Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "Strings.h"
+#include "Fonts.h"
+
+#include <cstring> // for strlen()
+
+// *****************************************************************************
+// *****************************************************************************
+// *** Strings *************************************************************
+// *****************************************************************************
+// *****************************************************************************
+const String::FontProfile String::fonts[FONTS_MAX] =
+// W H BPP Pointer to data
+{ { 4, 6, 6, (const uint8_t*)font4x6},
+ { 6, 8, 8, (const uint8_t*)font6x8},
+ { 8, 8, 8, (const uint8_t*)font8x8},
+ { 8, 12, 12, (const uint8_t*)font8x12},
+ {12, 16, 32, (const uint8_t*)font12x16} };
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+String::String(const char* str, int32_t x, int32_t y, uint32_t tc, FontType ft)
+{
+ SetParams(str, x, y, tc, ft);
+}
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+String::String(const char* str, int32_t x, int32_t y, uint32_t tc, uint32_t bgc, FontType ft)
+{
+ SetParams(str, x, y, tc, bgc, ft);
+}
+
+// *****************************************************************************
+// *** SetParams ***********************************************************
+// *****************************************************************************
+void String::SetParams(const char* str, int32_t x, int32_t y, uint32_t tc, FontType ft)
+{
+ string = (const uint8_t*)str;
+ x_start = x;
+ y_start = y;
+ txt_color = tc;
+ bg_color = 0;
+ font_type = ft;
+ transpatent_bg = true;
+ width = fonts[ft].w * strlen(str);
+ height = fonts[ft].h;
+ x_end = x + width - 1;
+ y_end = y + height - 1;
+ rotation = 0;
+}
+
+// *****************************************************************************
+// *** SetParams ***********************************************************
+// *****************************************************************************
+void String::SetParams(const char* str, int32_t x, int32_t y, uint32_t tc, uint32_t bgc, FontType ft)
+{
+ string = (const uint8_t*)str;
+ x_start = x;
+ y_start = y;
+ txt_color = tc;
+ bg_color = bgc;
+ font_type = ft;
+ transpatent_bg = false;
+ width = fonts[ft].w * strlen(str);
+ height = fonts[ft].h;
+ x_end = x + width - 1;
+ y_end = y + height - 1;
+ rotation = 0;
+}
+
+// *****************************************************************************
+// *** SetColor ************************************************************
+// *****************************************************************************
+void String::SetColor(uint32_t tc, uint32_t bgc, bool is_trnsp)
+{
+ txt_color = tc;
+ bg_color = bgc;
+ transpatent_bg = is_trnsp;
+}
+
+// *****************************************************************************
+// *** SetString ***********************************************************
+// *****************************************************************************
+void String::SetString(const char* str)
+{
+ // Lock object for changes
+ LockVisObject();
+ //Set new pointer to string
+ string = (const uint8_t*)str;
+ width = fonts[font_type].w * strlen(str);
+ x_end = x_start + width - 1;
+ // Unlock object after changes
+ UnlockVisObject();
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void String::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ // Draw only if needed
+ if((line >= y_start) && (line <= y_end) && (string != nullptr))
+ {
+ // Current symbol X position
+ int32_t x = x_start;
+ // Number of bytes need skipped for draw line
+ uint32_t skip_bytes = (line - y_start) * fonts[font_type].bytes_per_char / fonts[font_type].h;
+ // Pointer to string. Will increment for get characters.
+ const uint8_t* str = string;
+
+ // While we have symbols
+ while(*str != '\0')
+ {
+ uint32_t b = 0;
+ uint32_t w = 0;
+ // Get all symbol line
+ for(uint32_t i = 0; i < fonts[font_type].bytes_per_char; i++)
+ {
+ b |= fonts[font_type].font_data[((uint32_t)(*str)) * fonts[font_type].bytes_per_char + skip_bytes + i] << (i*8);
+ }
+ // Output symbol line
+ while(w < fonts[font_type].w)
+ {
+ // Put color in buffer only if visible
+ if((x >= start_x) && (x < start_x+n))
+ {
+ if((b&1) == 1)
+ {
+ buf[x] = txt_color;
+ }
+ else if(transpatent_bg == false)
+ {
+ buf[x] = bg_color;
+ }
+ else
+ {
+ // Empty statement
+ }
+ }
+ b >>= 1;
+ w++;
+ x++;
+ }
+ str++;
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void String::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ // Draw only if needed
+ if((row >= x_start) && (row <= x_end) && (string != nullptr))
+ {
+ // Find line in symbol
+ int16_t start = y_start - start_y;
+ // Find line in symbol
+ int16_t line = (row - x_start);
+
+ if(line >= 0)
+ {
+ // Get symbol
+ uint8_t c = string[line / fonts[font_type].w];
+ // Find line in symbol
+ line %= fonts[font_type].w;
+ // Index to symbol in data array
+ uint16_t s_idx = c * fonts[font_type].bytes_per_char;
+ // Index to symbol in data array
+ uint16_t bytes_per_line = fonts[font_type].bytes_per_char / fonts[font_type].h;
+ // Get symbols lines
+ for(int32_t i = 0; i < fonts[font_type].h; i++)
+ {
+ uint32_t b = *(uint32_t *)(&fonts[font_type].font_data[s_idx + i*bytes_per_line]);
+ if(b & (1U<<line))
+ {
+ if((start+i > 0) && (start+i < n))
+ {
+ buf[start+i] = txt_color;
+ }
+ }
+ }
+ }
+ }
+}
+
+// *****************************************************************************
+// *** GetFontW ************************************************************
+// *****************************************************************************
+uint32_t String::GetFontW(FontType ft)
+{
+ // Zero my default
+ uint32_t font_w = 0U;
+ // If provided valid font number
+ if(ft < FONTS_MAX)
+ {
+ // Get font width
+ font_w = fonts[ft].w;
+ }
+ // Return result
+ return font_w;
+};
+
+// *****************************************************************************
+// *** GetFontH ************************************************************
+// *****************************************************************************
+uint32_t String::GetFontH(FontType ft)
+{
+ // Zero my default
+ uint32_t font_h = 0U;
+ // If provided valid font number
+ if(ft < FONTS_MAX)
+ {
+ // Get font height
+ font_h = fonts[ft].h;
+ }
+ // Return result
+ return font_h;
+};
diff --git a/Display/Strings.h b/Display/Strings.h
new file mode 100644
index 0000000..4dd5633
--- /dev/null
+++ b/Display/Strings.h
@@ -0,0 +1,146 @@
+//******************************************************************************
+// @file String.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: String Visual Object Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+//******************************************************************************
+
+#ifndef Strings_h
+#define Strings_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "VisObject.h"
+
+// *****************************************************************************
+// *** String Class ********************************************************
+// *****************************************************************************
+class String : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Enum with all fonts types ***************************************
+ // *************************************************************************
+ typedef enum
+ {
+ FONT_4x6,
+ FONT_6x8,
+ FONT_8x8,
+ FONT_8x12,
+ FONT_12x16,
+ FONTS_MAX
+ } FontType;
+
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ String() {};
+
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ String(const char* str, int32_t x, int32_t y, uint32_t tc, FontType ft = FONT_8x8);
+
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ String(const char* str, int32_t x, int32_t y, uint32_t tc, uint32_t bgc, FontType ft = FONT_8x8);
+
+ // *************************************************************************
+ // *** SetParams *******************************************************
+ // *************************************************************************
+ void SetParams(const char* str, int32_t x, int32_t y, uint32_t tc, FontType ft);
+
+ // *************************************************************************
+ // *** SetParams *******************************************************
+ // *************************************************************************
+ void SetParams(const char* str, int32_t x, int32_t y, uint32_t tc, uint32_t bgc, FontType ft);
+
+ // *************************************************************************
+ // *** SetString *******************************************************
+ // *************************************************************************
+ void SetString(const char* str);
+
+ // *************************************************************************
+ // *** SetColor ********************************************************
+ // *************************************************************************
+ void SetColor(uint32_t tc, uint32_t bgc = 0U, bool is_trnsp = true);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ // *************************************************************************
+ // *** GetFontW ********************************************************
+ // *************************************************************************
+ static uint32_t GetFontW(FontType ft);
+
+ // *************************************************************************
+ // *** GetFontH ********************************************************
+ // *************************************************************************
+ static uint32_t GetFontH(FontType ft);
+
+ private:
+ // Pointer to string
+ // FIX ME: must be changed for prevent changing string during drawing
+ const uint8_t* string = nullptr;
+ // Text color
+ uint16_t txt_color = 0;
+ // Background color
+ uint16_t bg_color = 0;
+ // Font type
+ FontType font_type = FONT_8x8;
+ // Is background transparent ?
+ bool transpatent_bg = false;
+
+ typedef struct
+ {
+ uint8_t w; // Width of character
+ uint8_t h; // Height of character
+ uint8_t bytes_per_char; // Bytes Per Char
+ const uint8_t* font_data; // Pointer to font data
+ } FontProfile;
+
+ // Fonts structures. One for all String classes.
+ static const FontProfile fonts[FONTS_MAX];
+};
+
+#endif
diff --git a/Display/TiledMap.cpp b/Display/TiledMap.cpp
new file mode 100644
index 0000000..8b59e42
--- /dev/null
+++ b/Display/TiledMap.cpp
@@ -0,0 +1,179 @@
+//******************************************************************************
+// @file TiledMap.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Tiled Map Class, implementation
+//
+// @copyright Copyright (c) 2017, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "TiledMap.h"
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+TiledMap::TiledMap(int32_t x, int32_t y, int32_t w, int32_t h,
+ uint8_t* map, uint32_t map_w, uint32_t map_h, uint8_t bitmask,
+ const ImageDesc* tiles, uint32_t n, int32_t def_color)
+{
+ x_start = x;
+ y_start = y;
+ width = w;
+ height = h;
+ x_end = x_start + width - 1;
+ y_end = y_start + height - 1;
+ tiles_map = map;
+ map_width = map_w;
+ map_height = map_h;
+ tile_bitmask = bitmask;
+ tiles_img = tiles;
+ tiles_cnt = n;
+ tile_width = tiles->width;
+ tile_height = tiles->height;
+ bg_color = def_color;
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void TiledMap::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ // Draw only if needed
+ if((line >= y_start) && (line <= y_end))
+ {
+ int32_t start_offset = 0;
+ // Find start x position
+ int32_t start = x_start - start_x;
+ // Prevent write in memory before buffer
+ if(start < 0)
+ {
+ start_offset = -start;
+ start = 0;
+ }
+ // Find end x position
+ int32_t end = x_end - start_x;
+ // Prevent buffer overflow
+ if(end >= n) end = n - 1;
+
+ // Find start tile index and offsets
+ int32_t x_tile_idx = (x_pos + start_x + start_offset) / tile_width;
+ int32_t y_tile_idx = (y_pos + line - y_start) / tile_height;
+ int32_t tile_idx = y_tile_idx * map_width + x_tile_idx;
+ int32_t x_tile_offset = (x_pos + start_x + start_offset) % tile_width;
+ int32_t y_tile_offset = ((y_pos + line - y_start) % tile_height) * tile_width;
+
+ // If default color is 0 or greater
+ if(bg_color >= 0)
+ {
+ // Fill buffer by default color
+ for(int32_t i = start; i < end; i++)
+ {
+ buf[i] = bg_color;
+ }
+ }
+ // Prepare variables for first cycle
+ int32_t pix_idx = start;
+ int32_t tile_pix_idx = x_tile_offset;
+ // Draw line with tiles
+ while(pix_idx < n)
+ {
+ // Get tile value
+ uint8_t tile_val = tiles_map[tile_idx] & tile_bitmask;
+ // Skip empty tiles
+ if(tile_val >= tiles_cnt)
+ {
+ pix_idx += tile_width - tile_pix_idx;
+ tile_idx++;
+ tile_pix_idx = 0;
+ continue;
+ }
+ // Get pointer to the current tile image
+ const uint8_t* tile_ptr = &tiles_img[tile_val].img8[y_tile_offset];
+ // Get pointer to the current tile palette
+ const uint16_t* palette_ptr = tiles_img[tile_val].palette;
+ // Get transparent color
+ const int32_t transparent_color = tiles_img[tile_val].transparent_color;
+ // Draw tile
+ for(;(tile_pix_idx < (int32_t)tile_width) && (pix_idx <= end); tile_pix_idx++)
+ {
+ // Get pixel data
+ uint16_t data = palette_ptr[tile_ptr[tile_pix_idx]];
+ // If not transparent - output to buffer
+ if(data != transparent_color) buf[pix_idx] = data;
+ pix_idx++;
+ }
+ // Increase tile index
+ tile_idx++;
+ // Clear tile pixel counter
+ tile_pix_idx = 0;
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void TiledMap::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ // Not implemented yet
+}
+
+// *****************************************************************************
+// *** Scroll tiled map ****************************************************
+// *****************************************************************************
+void TiledMap::ScrollView(int32_t dx, int32_t dy)
+{
+ LockVisObject();
+ x_pos += dx;
+ if(x_pos < 0) x_pos = 0;
+ y_pos += dy;
+ if(y_pos < 0) y_pos = 0;
+ UnlockVisObject();
+}
+
+// *****************************************************************************
+// *** GetLvlIdxByXY *******************************************************
+// *****************************************************************************
+int32_t TiledMap::GetLvlIdxByXY(uint32_t x, uint32_t y)
+{
+ uint32_t result = -1;
+ // Calculate tiles indexes
+ uint32_t x_tile = x/tile_width;
+ uint32_t y_tile = y/tile_height;
+ // Set result only if x & y valid values
+ if(x_tile < map_width && y_tile < map_height)
+ {
+ result = y_tile*map_width + x_tile;
+ }
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** GetLvlDataByXY ******************************************************
+// *****************************************************************************
+int8_t TiledMap::GetLvlDataByXY(uint32_t x, uint32_t y)
+{
+ uint32_t result = 0U;
+ // Calculate tiles indexes
+ uint32_t x_tile = x/tile_width;
+ uint32_t y_tile = y/tile_height;
+ // Set result only if x & y valid values
+ if(x_tile < map_width && y_tile < map_height)
+ {
+ result = tiles_map[y_tile*map_width + x_tile];
+ }
+ // Return result
+ return result;
+}
diff --git a/Display/TiledMap.h b/Display/TiledMap.h
new file mode 100644
index 0000000..fc4bb74
--- /dev/null
+++ b/Display/TiledMap.h
@@ -0,0 +1,131 @@
+//******************************************************************************
+// @file TiledMap.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Tiled Map Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2017, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+//******************************************************************************
+
+#ifndef TilesMap_h
+#define TilesMap_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "VisObject.h"
+#include "Image.h"
+
+// *****************************************************************************
+// *** Tile Map Class ******************************************************
+// *****************************************************************************
+class TiledMap : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ TiledMap(int32_t x, int32_t y, int32_t w, int32_t h,
+ uint8_t* map, uint32_t map_w, uint32_t map_h, uint8_t bitmask,
+ const ImageDesc* tiles, uint32_t n, int32_t def_color);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ // *************************************************************************
+ // *** Scroll tiled map ************************************************
+ // *************************************************************************
+ void ScrollView(int32_t dx, int32_t dy = 0);
+
+ // *************************************************************************
+ // *** GetMapPosX ******************************************************
+ // *************************************************************************
+ int32_t GetLvlIdxByXY(uint32_t x, uint32_t y);
+
+ // *************************************************************************
+ // *** GetMapPosX ******************************************************
+ // *************************************************************************
+ int8_t GetLvlDataByXY(uint32_t x, uint32_t y);
+
+ // *************************************************************************
+ // *** GetMapPosX ******************************************************
+ // *************************************************************************
+ int32_t GetMapPosX(void) {return x_pos;}
+
+ // *************************************************************************
+ // *** GetMapPosY ******************************************************
+ // *************************************************************************
+ int32_t GetMapPosY(void) {return y_pos;}
+
+ // *************************************************************************
+ // *** GetPixWidth *****************************************************
+ // *************************************************************************
+ int32_t GetPixWidth() {return (tile_width * map_width);}
+
+ // *************************************************************************
+ // *** GetPixHeight ****************************************************
+ // *************************************************************************
+ int32_t GetPixHeight() {return (tile_height * map_height);}
+
+ private:
+ // Pointer to the tiles map
+ uint8_t* tiles_map;
+ // Map width in tiles
+ uint32_t map_width;
+ // Map height in tiles
+ uint32_t map_height;
+ // Bitmask for tiles
+ uint8_t tile_bitmask;
+ // Image descriptions of tiles picture
+ const ImageDesc* tiles_img;
+ // Image descriptions of tiles picture
+ uint32_t tiles_cnt;
+ // Tiles width in pixels
+ uint32_t tile_width;
+ // Tiles height in pixels
+ uint32_t tile_height;
+ // Background color (-1 - transparent)
+ int32_t bg_color;
+ // X position of tiled map in the viewport
+ int32_t x_pos = 0;
+ // Y position of tiled map in the viewport
+ int32_t y_pos = 0;
+};
+
+#endif
diff --git a/Display/VisObject.cpp b/Display/VisObject.cpp
new file mode 100644
index 0000000..3b206ea
--- /dev/null
+++ b/Display/VisObject.cpp
@@ -0,0 +1,125 @@
+//******************************************************************************
+// @file VisObject.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Visual Object Base Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "VisObject.h"
+#include "DisplayDrv.h" // for DelVisObjectFromList()
+
+// *****************************************************************************
+// *** Destructor **********************************************************
+// *****************************************************************************
+VisObject::~VisObject()
+{
+ // Remove object from object list before delete
+ DisplayDrv::GetInstance().DelVisObjectFromList(this);
+}
+
+// *****************************************************************************
+// *** Lock Visual Object ***************************************************
+// *****************************************************************************
+void VisObject::LockVisObject()
+{
+ // Lock line
+ DisplayDrv::GetInstance().LockDisplayLine();
+};
+
+// *****************************************************************************
+// *** Unlock Visual Object ************************************************
+// *****************************************************************************
+void VisObject::UnlockVisObject()
+{
+ // Unlock line
+ DisplayDrv::GetInstance().UnlockDisplayLine();
+};
+
+// *****************************************************************************
+// *** Show Visual Object **************************************************
+// *****************************************************************************
+void VisObject::Show(uint32_t z_pos)
+{
+ // Z position is 0 by default. In this case we can use 0 here as "no pos" flag
+ if(z_pos != 0)
+ {
+ z = z_pos;
+ }
+ // Add to VisObject List
+ DisplayDrv::GetInstance().AddVisObjectToList(this, z);
+}
+
+// *****************************************************************************
+// *** Hide Visual Object **************************************************
+// *****************************************************************************
+void VisObject::Hide(void)
+{
+ // Delete from VisObject List
+ DisplayDrv::GetInstance().DelVisObjectFromList(this);
+}
+
+// *****************************************************************************
+// *** Check status of Show Visual Object **********************************
+// *****************************************************************************
+bool VisObject::IsShow(void)
+{
+ // Return false by default
+ bool ret = false;
+ // If any pointer is not null - object in list
+ if( (p_next != nullptr) || (p_prev != nullptr) )
+ {
+ ret = true;
+ }
+ // Return result
+ return ret;
+}
+
+// *****************************************************************************
+// *** Move Visual Object **************************************************
+// *****************************************************************************
+void VisObject::Move(int32_t x, int32_t y, bool is_delta)
+{
+ // Lock object for changes
+ LockVisObject();
+ // Make changes
+ if(is_delta == true)
+ {
+ // Move object in delta coordinates
+ x_start += x;
+ y_start += y;
+ x_end += x;
+ y_end += y;
+ }
+ else
+ {
+ // Move object in absolute coordinates
+ x_start = x;
+ y_start = y;
+ x_end = x + width - 1;
+ y_end = y + height - 1;
+ }
+ // Unlock object after changes
+ UnlockVisObject();
+}
+
+// *****************************************************************************
+// *** Action **************************************************************
+// *****************************************************************************
+void VisObject::Action(ActionType action, int32_t tx, int32_t ty)
+{
+ // Empty function. We can do active object without custom Action function
+ // for cover active object with lower Z.
+}
diff --git a/Display/VisObject.h b/Display/VisObject.h
new file mode 100644
index 0000000..a8b5439
--- /dev/null
+++ b/Display/VisObject.h
@@ -0,0 +1,199 @@
+//******************************************************************************
+// @file VisObject.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Visual Object Base Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+//******************************************************************************
+
+#ifndef VisObject_h
+#define VisObject_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+
+// *****************************************************************************
+// * VisObject class. This class implements base Visual Objects properties.
+class VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Action **********************************************************
+ // *************************************************************************
+ typedef enum
+ {
+ ACT_TOUCH, // When object touched
+ ACT_UNTOUCH, // When object detouched
+ ACT_MOVE, // When object moved on object
+ ACT_MOVEIN, // When object moved in to object
+ ACT_MOVEOUT, // When object moved out of object
+ ACT_MAX // Total possible actions
+ } ActionType;
+
+ // *************************************************************************
+ // *** VisObject *******************************************************
+ // *************************************************************************
+ VisObject() {};
+
+ // *************************************************************************
+ // *** ~VisObject ******************************************************
+ // *************************************************************************
+ // * Destructor. Call DelVisObjectFromList() from DisplayDrv class for
+ // * remove from list before delete and delete semaphore.
+ virtual ~VisObject();
+
+ // *************************************************************************
+ // *** LockVisObject ***************************************************
+ // *************************************************************************
+ void LockVisObject();
+
+ // *************************************************************************
+ // *** UnlockVisObject *************************************************
+ // *************************************************************************
+ void UnlockVisObject();
+
+ // *************************************************************************
+ // *** Show ************************************************************
+ // *************************************************************************
+ // * Show VisObject on screen. This function call AddVisObjectToList() from
+ // * DisplayDrv class. When this function calls first time, user must
+ // * provide Z level. In future user can call this function without
+ // * parameters - previously set Z will be used.
+ virtual void Show(uint32_t z_pos = 0);
+
+ // *************************************************************************
+ // *** Hide ************************************************************
+ // *************************************************************************
+ // * Hide VisObject from screen. This function call DelVisObjectFromList()
+ // * from DisplayDrv class.
+ virtual void Hide(void);
+
+ // *************************************************************************
+ // *** IsShow **********************************************************
+ // *************************************************************************
+ // * Check status of Show Visual Object. Return true if object in DisplayDrv list.
+ virtual bool IsShow(void);
+
+ // *************************************************************************
+ // *** Move ************************************************************
+ // *************************************************************************
+ // * Move object on screen. Set new x and y coordinates. If flag is set -
+ // * move is relative, not absolute.
+ virtual void Move(int32_t x, int32_t y, bool is_delta = false);
+
+ // *************************************************************************
+ // *** DrawInBufH ******************************************************
+ // *************************************************************************
+ // * Draw one horizontal line of object in specified buffer.
+ // * Each derived class must implement this function.
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y = 0) = 0;
+
+ // *************************************************************************
+ // *** DrawInBufW ******************************************************
+ // *************************************************************************
+ // * Draw one vertical line of object in specified buffer.
+ // * Each derived class must implement this function.
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x = 0) = 0;
+
+ // *************************************************************************
+ // *** Action **********************************************************
+ // *************************************************************************
+ virtual void Action(ActionType action, int32_t tx, int32_t ty);
+
+ // *************************************************************************
+ // *** Return Start X coordinate ***************************************
+ // *************************************************************************
+ virtual int32_t GetStartX(void) {return x_start;};
+
+ // *************************************************************************
+ // *** Return Start Y coordinate ***************************************
+ // *************************************************************************
+ virtual int32_t GetStartY(void) {return y_start;};
+
+ // *************************************************************************
+ // *** Return End X coordinate *****************************************
+ // *************************************************************************
+ virtual int32_t GetEndX(void) {return x_end;};
+
+ // *************************************************************************
+ // *** Return End Y coordinate *****************************************
+ // *************************************************************************
+ virtual int32_t GetEndY(void) {return y_end;};
+
+ // *************************************************************************
+ // *** Return Width of object ******************************************
+ // *************************************************************************
+ virtual int32_t GetWidth(void) {return width;};
+
+ // *************************************************************************
+ // *** Return Height of object *****************************************
+ // *************************************************************************
+ virtual int32_t GetHeight(void) {return height;};
+
+ protected:
+ // *************************************************************************
+ // *** Object parameters ***********************************************
+ // *************************************************************************
+
+ // X and Y start coordinates of object
+ int16_t x_start = 0, y_start = 0;
+ // X and Y end coordinates of object
+ int16_t x_end = 0, y_end = 0;
+ // Width and Height of object
+ int16_t width = 0, height = 0;
+ // Rotation of object
+ int8_t rotation = 0;
+ // Object active
+ bool active = false;
+
+ private:
+ // *************************************************************************
+ // *** Object parameters ***********************************************
+ // *************************************************************************
+ // * Only base class and DisplayDrv have access to this parameters
+
+ // Z position of object
+ uint16_t z = 0;
+ // Pointer to next object. This pointer need to maker object list. Object
+ // can be added only to one list.
+ VisObject* p_next = nullptr;
+ // Pointer to next object. This pointer need to maker object list. Object
+ // can be added only to one list.
+ VisObject* p_prev = nullptr;
+
+ // DisplayDrv is friend for access to pointers and Z
+ friend class DisplayDrv;
+};
+
+#endif
diff --git a/Display/XPT2046.cpp b/Display/XPT2046.cpp
new file mode 100644
index 0000000..0e7f396
--- /dev/null
+++ b/Display/XPT2046.cpp
@@ -0,0 +1,145 @@
+//******************************************************************************
+// @file XPT2046.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: XPT2046 Low Level Driver Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include <XPT2046.h>
+
+// *****************************************************************************
+// *** Init touchscreen ****************************************************
+// *****************************************************************************
+void XPT2046::Init(void)
+{
+ // Pull down CS
+ HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_RESET);
+ // Send ON command
+ SpiWrite(TON);
+ // Send empty byte for skip answer
+ SpiWrite(EMP);
+ // Send empty byte for skip answer
+ SpiWrite(EMP);
+ // Pull up CS
+ HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_SET);
+}
+
+// *****************************************************************************
+// *** If touched - return true. *******************************************
+// *****************************************************************************
+bool XPT2046::IsTouch(void)
+{
+ // Check T_IRQ input and return state
+ return(HAL_GPIO_ReadPin(T_IRQ_GPIO_Port, T_IRQ_Pin) == GPIO_PIN_RESET);
+}
+
+// *****************************************************************************
+// *** Get X and Y coordinates. If touched - return true. ******************
+// *****************************************************************************
+bool XPT2046::GetRawXY(int32_t& x, int32_t& y)
+{
+ // Return value
+ bool ret = false;
+ // If touch present
+ if(HAL_GPIO_ReadPin(T_IRQ_GPIO_Port, T_IRQ_Pin) == GPIO_PIN_RESET)
+ {
+ // Pull down CS
+ HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_RESET);
+ // Request X coordinate
+ SpiWrite(CHX);
+ // Receive High byte for X
+ x = SpiWriteRead(EMP) << 8;
+ // Receive Low byte for X
+ x |= SpiWriteRead(EMP);
+ // Shift, because result have only 12 bits, 3 because answer started from
+ // second rise edge
+ x >>= 3;
+ // Pull up CS
+ HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_SET);
+
+ // Pull down CS
+ HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_RESET);
+ // Request Y coordinate
+ SpiWrite(CHY);
+ // Receive High byte for Y
+ y = SpiWriteRead(EMP) << 8;
+ // Receive Low byte for Y
+ y |= SpiWriteRead(EMP);
+ // Shift, because result have only 12 bits, 3 because answer started from
+ // second rise edge
+ y >>= 3;
+ // Pull up CS
+ HAL_GPIO_WritePin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin, GPIO_PIN_SET);
+
+ // Touch present
+ ret = true;
+ }
+ // Return result
+ return ret;
+}
+
+// *****************************************************************************
+// *** Get X and Y coordinates. If touched - return true. ******************
+// *****************************************************************************
+bool XPT2046::GetXY(int32_t& x, int32_t& y)
+{
+ // Return value
+ bool ret = GetRawXY(x, y);
+ // If touch present
+ if(ret)
+ {
+ // Calculate X
+ x = ((x * COEF) / kx) + bx;
+ // Calculate Y
+ y = ((y * COEF) / ky) + by;
+ }
+ // Return touch state
+ return ret;
+}
+
+// *****************************************************************************
+// *** SetCalibrationConsts ************************************************
+// *****************************************************************************
+void XPT2046::SetCalibrationConsts(int32_t nkx, int32_t nky, int32_t nbx, int32_t nby)
+{
+ // Save calibration constants
+ kx = nkx;
+ ky = nky;
+ bx = nbx;
+ by = nby;
+}
+
+// *****************************************************************************
+// *** Write byte to SPI ***************************************************
+// *****************************************************************************
+inline void XPT2046::SpiWrite(uint8_t c)
+{
+ // Call HAL function for send byte by SPI
+ (void) HAL_SPI_Transmit(hspi, &c, sizeof(c), 1U);
+}
+
+// *****************************************************************************
+// *** Write and read byte to/from SPI *************************************
+// *****************************************************************************
+inline uint8_t XPT2046::SpiWriteRead(uint8_t c)
+{
+ // Temporary variable for receive byte
+ uint8_t rcv;
+ // Call HAL function for send/receive byte by SPI
+ (void) HAL_SPI_TransmitReceive(hspi, &c, &rcv, sizeof(uint8_t), 1U);
+ // Return received byte
+ return rcv;
+}
diff --git a/Display/XPT2046.h b/Display/XPT2046.h
new file mode 100644
index 0000000..51b35a5
--- /dev/null
+++ b/Display/XPT2046.h
@@ -0,0 +1,129 @@
+//******************************************************************************
+// @file XPT2046.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: XPT2046 Low Level Driver Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+//******************************************************************************
+
+#ifndef XPT2046_h
+#define XPT2046_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+
+// *****************************************************************************
+// *** Defines *************************************************************
+// *****************************************************************************
+
+// *****************************************************************************
+// * XPT2046 class. Implements work with XPT2046 resistive touchscreen.
+class XPT2046
+{
+ public:
+ // Coefficient for calibration
+ const static int32_t COEF = 100;
+
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ // * This class hasn't task inside. For use this class user must provide
+ // * handle to SPI. Previously I think shape SPI between TFT and Touch.
+ // * But now it is two different SPI. Anyway main idea it is use this class
+ // * in DisplayDrv class for find pressed VisObjects.
+ XPT2046(SPI_HandleTypeDef* in_hspi) : hspi(in_hspi) {};
+
+ // *************************************************************************
+ // *** Init ************************************************************
+ // *************************************************************************
+ // * Init function. Send init sequence to touchscreen controller.
+ void Init(void);
+
+ // *************************************************************************
+ // *** IsTouch *********************************************************
+ // *************************************************************************
+ // * Check touched or not by T_IRQ pin. Return true if touched.
+ bool IsTouch(void);
+
+ // *************************************************************************
+ // *** GetRawXY ********************************************************
+ // *************************************************************************
+ // * Return raw X and Y coordinates. If touched - return true.
+ bool GetRawXY(int32_t& x, int32_t& y);
+
+ // *************************************************************************
+ // *** GetXY ***********************************************************
+ // *************************************************************************
+ // * Return recalculated using calibration constants X and Y coordinates.
+ // * If touched - return true. Can be used for second calibration.
+ bool GetXY(int32_t& x, int32_t& y);
+
+ // *************************************************************************
+ // *** SetCalibrationConsts ********************************************
+ // *************************************************************************
+ // * Set calibration constants. Must be call for calibration touchscreen.
+ void SetCalibrationConsts(int32_t nkx, int32_t nky, int32_t nbx, int32_t nby);
+
+ private:
+ // Turn touchscreen ON
+ const static uint8_t TON = 0x80;
+ // Empty byte
+ const static uint8_t EMP = 0x00;
+ // Request X coordinate
+ const static uint8_t CHX = 0x90;
+ // Request Y coordinate
+ const static uint8_t CHY = 0xD0;
+
+ // Handle to SPI used for touchscreen
+ SPI_HandleTypeDef* hspi = nullptr;
+
+ // Display width and height offset
+ int32_t kx = -1097, ky = -1499;
+ // Display width and height coefficient
+ int32_t bx = 334, by = 259;
+
+ // *************************************************************************
+ // *** SpiWrite ********************************************************
+ // *************************************************************************
+ // * Write byte to SPI
+ inline void SpiWrite(uint8_t c);
+
+ // *************************************************************************
+ // *** SpiWriteRead ****************************************************
+ // *************************************************************************
+ // * Write/read byte from/to SPI
+ inline uint8_t SpiWriteRead(uint8_t c);
+};
+
+#endif
diff --git a/Drivers/StHalIic.cpp b/Drivers/StHalIic.cpp
new file mode 100644
index 0000000..2f231a1
--- /dev/null
+++ b/Drivers/StHalIic.cpp
@@ -0,0 +1,245 @@
+//******************************************************************************
+// @file StHalIic.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: STM32 HAL I2C driver, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "StHalIic.h"
+
+// *****************************************************************************
+// *** This driver can be compiled only if I2C configured in CubeMX ********
+// *****************************************************************************
+#ifdef HAL_I2C_MODULE_ENABLED
+
+// *****************************************************************************
+// *** Public: Enable ******************************************************
+// *****************************************************************************
+Result StHalIic::Enable()
+{
+ // Set PE bit
+ __HAL_I2C_ENABLE(&hi2c);
+ // No errors to return
+ return Result::RESULT_OK;
+}
+
+// *****************************************************************************
+// *** Public: Disable *****************************************************
+// *****************************************************************************
+Result StHalIic::Disable()
+{
+ // Clear PE bit
+ __HAL_I2C_DISABLE(&hi2c);
+ // No errors to return
+ return Result::RESULT_OK;
+}
+
+// *****************************************************************************
+// *** Public: Reset *******************************************************
+// *****************************************************************************
+Result StHalIic::Reset()
+{
+ // Clear PE bit
+ CLEAR_BIT(hi2c.Instance->CR1, I2C_CR1_PE);
+ // PE must be kept low during at least 3 APB clock cycles in order to
+ // perform the software reset. Wait until it actually cleared.
+ while(READ_BIT(hi2c.Instance->CR1, I2C_CR1_PE));
+ // TODO: make some clock on the SCL line here
+ // Set PE bit
+ SET_BIT(hi2c.Instance->CR1, I2C_CR1_PE);
+ // No errors to return
+ return Result::RESULT_OK;
+}
+
+// *************************************************************************
+// *** Public: IsDeviceReady *******************************************
+// *************************************************************************
+Result StHalIic::IsDeviceReady(uint16_t addr, uint8_t retries)
+{
+ Result result;
+ // Shift address one bit left - HAL blow away LSB, not MSB.
+ addr <<= 1U;
+ // Check device status
+ HAL_StatusTypeDef hal_result = HAL_I2C_IsDeviceReady(&hi2c1, addr, retries, i2c_tx_timeout_ms);
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Transfer ****************************************************
+// *****************************************************************************
+Result StHalIic::Transfer(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size, uint8_t* rx_buf_ptr, uint32_t rx_size)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ if(tx_buf_ptr != nullptr)
+ {
+ // Transmit data
+ result = Write(addr, tx_buf_ptr, tx_size);
+ }
+
+ if((rx_buf_ptr != nullptr) && result.IsGood())
+ {
+ // Clear RX buffer
+ for(uint32_t i = 0; i < rx_size; i++)
+ {
+ rx_buf_ptr[i] = 0;
+ }
+ // Receive data
+ result = Read(addr, rx_buf_ptr, rx_size);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Write *******************************************************
+// *****************************************************************************
+Result StHalIic::Write(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ if(tx_buf_ptr != nullptr)
+ {
+ // Variable for store result from the HAL
+ HAL_StatusTypeDef hal_result = HAL_OK;
+
+ // Shift address one bit left - HAL blow away LSB, not MSB.
+ addr <<= 1U;
+
+ // Transmit data
+ hal_result = HAL_I2C_Master_Transmit(&hi2c, addr, tx_buf_ptr, tx_size, i2c_tx_timeout_ms);
+
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Read ********************************************************
+// *****************************************************************************
+Result StHalIic::Read(uint16_t addr, uint8_t* rx_buf_ptr, uint32_t rx_size)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ if(rx_buf_ptr != nullptr)
+ {
+ // Variable for store result from the HAL
+ HAL_StatusTypeDef hal_result = HAL_OK;
+
+ // Shift address one bit left - HAL blow away LSB, not MSB.
+ addr <<= 1U;
+
+ // Transmit data
+ hal_result = HAL_I2C_Master_Receive(&hi2c, addr, rx_buf_ptr, rx_size, i2c_tx_timeout_ms);
+
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: WriteAsync **************************************************
+// *****************************************************************************
+Result StHalIic::WriteAsync(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size)
+{
+ Result result = Result::ERR_NOT_IMPLEMENTED;
+
+ // Check DMA handler - if it is nullptr this function not implemented in hardware
+ if(hi2c.hdmatx != nullptr)
+ {
+ // Shift address one bit left - HAL blow away LSB, not MSB.
+ addr <<= 1U;
+ // Receive data using DMA
+ HAL_StatusTypeDef hal_result = HAL_I2C_Master_Transmit_DMA(&hi2c, addr, tx_buf_ptr, tx_size);
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: ReadAsync ***************************************************
+// *****************************************************************************
+Result StHalIic::ReadAsync(uint16_t addr, uint8_t* rx_buf_ptr, uint32_t rx_size)
+{
+ Result result = Result::ERR_NOT_IMPLEMENTED;
+
+ // Check DMA handler - if it is nullptr this function not implemented in hardware
+ if(hi2c.hdmarx != nullptr)
+ {
+ // Shift address one bit left - HAL blow away LSB, not MSB.
+ addr <<= 1U;
+ // Receive data using DMA
+ HAL_StatusTypeDef hal_result = HAL_I2C_Master_Receive_DMA(&hi2c, addr, rx_buf_ptr, rx_size);
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Transfer ****************************************************
+// *****************************************************************************
+bool StHalIic::IsBusy(void)
+{
+ return (hi2c.State != HAL_I2C_STATE_READY);
+}
+
+// *****************************************************************************
+// *** Private: ConvertResult **********************************************
+// *****************************************************************************
+Result StHalIic::ConvertResult(HAL_StatusTypeDef hal_result)
+{
+ Result result = Result::RESULT_OK;
+
+ // Convert operation result to Result
+ switch(hal_result)
+ {
+ case HAL_OK:
+ result = Result::RESULT_OK;
+ break;
+
+ case HAL_ERROR:
+ result = Result::ERR_I2C_GENERAL;
+ break;
+
+ case HAL_BUSY:
+ result = Result::ERR_I2C_BUSY;
+ break;
+
+ case HAL_TIMEOUT:
+ result = Result::ERR_I2C_TIMEOUT;
+ break;
+
+ default:
+ result = Result::ERR_SPI_UNKNOWN;
+ break;
+ }
+
+ // Return result
+ return result;
+}
+
+#endif
diff --git a/Drivers/StHalIic.h b/Drivers/StHalIic.h
new file mode 100644
index 0000000..b06c8fa
--- /dev/null
+++ b/Drivers/StHalIic.h
@@ -0,0 +1,153 @@
+//******************************************************************************
+// @file StHalIic.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: STM32 HAL I2C driver, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef StmHalIic_h
+#define StmHalIic_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "IIic.h"
+
+// *****************************************************************************
+// *** This driver can be compiled only if UART configured in CubeMX *******
+// *****************************************************************************
+#ifndef HAL_I2C_MODULE_ENABLED
+ typedef uint32_t I2C_HandleTypeDef; // Dummy I2C handle for header compilation
+#endif
+
+// *****************************************************************************
+// *** STM32 HAL I2C Driver Class ******************************************
+// *****************************************************************************
+class StHalIic : public IIic
+{
+ public:
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ explicit StHalIic(I2C_HandleTypeDef& hi2c_ref) : hi2c(hi2c_ref) {};
+
+ // *************************************************************************
+ // *** Public: Destructor **********************************************
+ // *************************************************************************
+ ~StHalIic() {};
+
+ // *************************************************************************
+ // *** Public: Init ****************************************************
+ // *************************************************************************
+ virtual Result Init() {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Enable **************************************************
+ // *************************************************************************
+ virtual Result Enable();
+
+ // *************************************************************************
+ // *** Public: Disable *************************************************
+ // *************************************************************************
+ virtual Result Disable();
+
+ // *************************************************************************
+ // *** Public: Reset ***************************************************
+ // *************************************************************************
+ virtual Result Reset();
+
+ // *************************************************************************
+ // *** Public: IsDeviceReady *******************************************
+ // *************************************************************************
+ virtual Result IsDeviceReady(uint16_t addr, uint8_t retries = 1U);
+
+ // *************************************************************************
+ // *** Public: Transfer ************************************************
+ // *************************************************************************
+ virtual Result Transfer(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size,
+ uint8_t* rx_buf_ptr, uint32_t rx_size);
+
+ // *************************************************************************
+ // *** Public: Write ***************************************************
+ // *************************************************************************
+ virtual Result Write(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size);
+
+ // *************************************************************************
+ // *** Public: Read ****************************************************
+ // *************************************************************************
+ virtual Result Read(uint16_t addr, uint8_t* rx_buf_ptr, uint32_t rx_size);
+
+ // *************************************************************************
+ // *** Public: WriteAsync **********************************************
+ // *************************************************************************
+ virtual Result WriteAsync(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size);
+
+ // *************************************************************************
+ // *** Public: ReadAsync ***********************************************
+ // *************************************************************************
+ virtual Result ReadAsync(uint16_t addr, uint8_t* rx_buf_ptr, uint32_t rx_size);
+
+ // *************************************************************************
+ // *** Public: IsBusy **************************************************
+ // *************************************************************************
+ virtual bool IsBusy(void);
+
+ private:
+ // Reference to the I2C handle
+ I2C_HandleTypeDef& hi2c;
+
+ // *************************************************************************
+ // *** Private: ConvertResult ******************************************
+ // *************************************************************************
+ Result ConvertResult(HAL_StatusTypeDef hal_result);
+
+ // *************************************************************************
+ // *** Private: Constructors and assign operator - prevent copying *****
+ // *************************************************************************
+ StHalIic();
+ StHalIic(const StHalIic&);
+ StHalIic& operator=(const StHalIic);
+};
+
+#endif
diff --git a/Drivers/StHalSpi.cpp b/Drivers/StHalSpi.cpp
new file mode 100644
index 0000000..19f1865
--- /dev/null
+++ b/Drivers/StHalSpi.cpp
@@ -0,0 +1,335 @@
+//******************************************************************************
+// @file StHalIic.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: STM32 HAL SPI driver, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "StHalSpi.h"
+
+// *****************************************************************************
+// *** This driver can be compiled only if SPI configured in CubeMX ********
+// *****************************************************************************
+#ifdef HAL_SPI_MODULE_ENABLED
+
+// *****************************************************************************
+// *** Public: Transfer ****************************************************
+// *****************************************************************************
+Result StHalSpi::Transfer(uint8_t* rx_buf_ptr, uint8_t* tx_buf_ptr, uint32_t size)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ // Check for null pointer
+ if((rx_buf_ptr != nullptr) && (tx_buf_ptr != nullptr))
+ {
+ // Read data from SPI port
+ HAL_StatusTypeDef hal_result = HAL_SPI_TransmitReceive(&hspi, tx_buf_ptr, rx_buf_ptr, size, spi_tx_timeout_ms);
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Write *******************************************************
+// *****************************************************************************
+Result StHalSpi::Write(uint8_t* tx_buf_ptr, uint32_t size)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ // Check for null pointer
+ if (tx_buf_ptr != nullptr)
+ {
+ // Read data from SPI port
+ HAL_StatusTypeDef hal_result = HAL_SPI_Transmit(&hspi, tx_buf_ptr, size, spi_tx_timeout_ms);
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Read ********************************************************
+// *****************************************************************************
+Result StHalSpi::Read(uint8_t* rx_buf_ptr, uint32_t size)
+{
+ Result result = Result::RESULT_OK;
+
+ // Check for null pointer
+ if (rx_buf_ptr != nullptr)
+ {
+ // Read data from the SPI port
+ HAL_StatusTypeDef hal_result = HAL_SPI_Receive(&hspi, rx_buf_ptr, size, spi_rx_timeout_ms);
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: TransferAsync ***********************************************
+// *****************************************************************************
+Result StHalSpi::TransferAsync(uint8_t* rx_buf_ptr, uint8_t* tx_buf_ptr, uint32_t size)
+{
+ Result result = Result::RESULT_OK;
+
+ // Check for null pointer
+ if((rx_buf_ptr != nullptr) && (tx_buf_ptr != nullptr))
+ {
+ // Read data from SPI port
+ HAL_StatusTypeDef hal_result = HAL_SPI_TransmitReceive_DMA(&hspi, tx_buf_ptr, rx_buf_ptr, size);
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: WriteAsync **************************************************
+// *****************************************************************************
+Result StHalSpi::WriteAsync(uint8_t* tx_buf_ptr, uint32_t size)
+{
+ Result result = Result::RESULT_OK;
+
+ // Check for null pointer
+ if(tx_buf_ptr != nullptr)
+ {
+ // Read data from SPI port
+ HAL_StatusTypeDef hal_result = HAL_SPI_Transmit_DMA(&hspi, tx_buf_ptr, size);
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: ReadAsync ***************************************************
+// *****************************************************************************
+Result StHalSpi::ReadAsync(uint8_t* rx_buf_ptr, uint32_t size)
+{
+ Result result = Result::RESULT_OK;
+
+ // Check for null pointer
+ if(rx_buf_ptr != nullptr)
+ {
+ // Read data from SPI port
+ HAL_StatusTypeDef hal_result = HAL_SPI_Receive_DMA(&hspi, rx_buf_ptr, size);
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Check SPI transfer status ***********************************
+// *****************************************************************************
+bool StHalSpi::IsTransferComplete(void)
+{
+ return(hspi.State != HAL_SPI_STATE_BUSY_TX);
+}
+
+// *****************************************************************************
+// *** Public: Abort *******************************************************
+// *****************************************************************************
+Result StHalSpi::Abort(void)
+{
+ Result result = Result::RESULT_OK;
+
+ // Abort SPI transmissions data from SPI port
+ HAL_StatusTypeDef hal_result = HAL_SPI_Abort(&hspi); // TODO: what difference from HAL_SPI_Abort_IT(&hspi) ???
+ // Convert operation result to Result
+ result = ConvertResult(hal_result);
+
+ return result;
+}
+
+// *************************************************************************
+// *** Public: SetSpeed ************************************************
+// *************************************************************************
+Result StHalSpi::SetSpeed(uint32_t clock_rate)
+{
+ Result result = Result::RESULT_OK;
+
+ // Get SPI bus clock
+ uint32_t pclk2 = HAL_RCC_GetPCLK2Freq();
+ // Find divider
+ uint32_t divider = pclk2 / clock_rate;
+ // Variable for baud prescaler
+ uint32_t baud_prescaler = SPI_BAUDRATEPRESCALER_2;
+
+ // Set prescaler for SPI
+ if(divider <= 2U)
+ {
+ baud_prescaler = SPI_BAUDRATEPRESCALER_2;
+ clock_rate = pclk2 * 2U;
+ }
+ else if(divider <= 4U)
+ {
+ baud_prescaler = SPI_BAUDRATEPRESCALER_4;
+ clock_rate = pclk2 * 4U;
+ }
+ else if(divider <= 8U)
+ {
+ baud_prescaler = SPI_BAUDRATEPRESCALER_8;
+ clock_rate = pclk2 * 8U;
+ }
+ else if(divider <= 16U)
+ {
+ baud_prescaler = SPI_BAUDRATEPRESCALER_16;
+ clock_rate = pclk2 * 16U;
+ }
+ else if(divider <= 32U)
+ {
+ baud_prescaler = SPI_BAUDRATEPRESCALER_32;
+ clock_rate = pclk2 * 32U;
+ }
+ else if(divider <= 64U)
+ {
+ baud_prescaler = SPI_BAUDRATEPRESCALER_64;
+ clock_rate = pclk2 * 64U;
+ }
+ else if(divider <= 128U)
+ {
+ baud_prescaler = SPI_BAUDRATEPRESCALER_128;
+ clock_rate = pclk2 * 128U;
+ }
+ else if(divider <= 256U)
+ {
+ baud_prescaler = SPI_BAUDRATEPRESCALER_256;
+ clock_rate = pclk2 * 256U;
+ }
+ else
+ {
+ // We can't set requested or lower speed
+ result = Result::ERR_SPI_GENERAL;
+ }
+
+ if(result.IsGood())
+ {
+ // Set prescaler
+ MODIFY_REG(hspi.Instance->CR1, (uint32_t)SPI_CR1_BR_Msk, baud_prescaler);
+ }
+
+ return result;
+}
+
+// *************************************************************************
+// *** Public: GetSpeed ************************************************
+// *************************************************************************
+Result StHalSpi::GetSpeed(uint32_t& clock_rate)
+{
+ Result result = Result::RESULT_OK;
+
+ // Get SPI bus clock
+ uint32_t pclk2 = HAL_RCC_GetPCLK2Freq();
+ // Get prescaler
+ uint32_t baud_prescaler = READ_REG(hspi.Instance->CR1) & (uint32_t)SPI_CR1_BR_Msk;
+
+ // Set prescaler for SPI
+ if(baud_prescaler == SPI_BAUDRATEPRESCALER_2)
+ {
+ clock_rate = pclk2 * 2U;
+ }
+ else if(baud_prescaler == SPI_BAUDRATEPRESCALER_4)
+ {
+ clock_rate = pclk2 * 4U;
+ }
+ else if(baud_prescaler == SPI_BAUDRATEPRESCALER_8)
+ {
+ clock_rate = pclk2 * 8U;
+ }
+ else if(baud_prescaler == SPI_BAUDRATEPRESCALER_16)
+ {
+ clock_rate = pclk2 * 16U;
+ }
+ else if(baud_prescaler == SPI_BAUDRATEPRESCALER_32)
+ {
+ clock_rate = pclk2 * 32U;
+ }
+ else if(baud_prescaler == SPI_BAUDRATEPRESCALER_64)
+ {
+ clock_rate = pclk2 * 64U;
+ }
+ else if(baud_prescaler == SPI_BAUDRATEPRESCALER_128)
+ {
+ clock_rate = pclk2 * 128U;
+ }
+ else if(baud_prescaler == SPI_BAUDRATEPRESCALER_256)
+ {
+ clock_rate = pclk2 * 256U;
+ }
+ else
+ {
+ // Clear result clock rate
+ clock_rate = 0U;
+ // We shouldn't get here
+ result = Result::ERR_SPI_GENERAL;
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Private: GetToDataSizeBytes *****************************************
+// *****************************************************************************
+uint32_t StHalSpi::GetToDataSizeBytes()
+{
+ // Shift by a byte and add one because 0x300 is 4 bits
+ return(hspi.Init.DataSize >> 8U) + 1U;
+}
+
+// *****************************************************************************
+// *** Private: ConvertResult **********************************************
+// *****************************************************************************
+Result StHalSpi::ConvertResult(HAL_StatusTypeDef hal_result)
+{
+ Result result = Result::RESULT_OK;
+
+ // Convert operation result to Result
+ switch(hal_result)
+ {
+ case HAL_OK:
+ result = Result::RESULT_OK;
+ break;
+
+ case HAL_ERROR:
+ result = Result::ERR_SPI_GENERAL;
+ break;
+
+ case HAL_BUSY:
+ result = Result::ERR_SPI_BUSY;
+ break;
+
+ case HAL_TIMEOUT:
+ result = Result::ERR_SPI_TIMEOUT;
+ break;
+
+ default:
+ result = Result::ERR_SPI_UNKNOWN;
+ break;
+ }
+
+ // Return result
+ return result;
+}
+
+#endif
diff --git a/Drivers/StHalSpi.h b/Drivers/StHalSpi.h
new file mode 100644
index 0000000..2681f19
--- /dev/null
+++ b/Drivers/StHalSpi.h
@@ -0,0 +1,162 @@
+//******************************************************************************
+// @file StHalSpi.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: STM32 HAL SPI driver, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef StmHalSpi_h
+#define StmHalSpi_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "ISpi.h"
+
+// *****************************************************************************
+// *** This driver can be compiled only if UART configured in CubeMX *******
+// *****************************************************************************
+#ifndef HAL_SPI_MODULE_ENABLED
+ typedef uint32_t SPI_HandleTypeDef; // Dummy SPI handle for header compilation
+#endif
+
+// *****************************************************************************
+// *** STM32 HAL ISPI Driver Class ****************************************
+// *****************************************************************************
+class StHalSpi : public ISpi
+{
+ public:
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ explicit StHalSpi(SPI_HandleTypeDef& hspi_ref) : hspi(hspi_ref) {};
+
+ // *************************************************************************
+ // *** Public: Destructor **********************************************
+ // *************************************************************************
+ ~StHalSpi() {};
+
+ // *************************************************************************
+ // *** Public: Init ****************************************************
+ // *************************************************************************
+ virtual Result Init() {return Result::RESULT_OK;}
+
+ // *************************************************************************
+ // *** Public: DeInit **************************************************
+ // *************************************************************************
+ virtual Result DeInit() {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Transfer ************************************************
+ // *************************************************************************
+ virtual Result Transfer(uint8_t* rx_buf_ptr, uint8_t* tx_buf_ptr, uint32_t size);
+
+ // *************************************************************************
+ // *** Public: Write ***************************************************
+ // *************************************************************************
+ virtual Result Write(uint8_t* tx_buf_ptr, uint32_t tx_size);
+
+ // *************************************************************************
+ // *** Public: Read ****************************************************
+ // *************************************************************************
+ virtual Result Read(uint8_t* rx_buf_ptr, uint32_t rx_size);
+
+ // *************************************************************************
+ // *** Public: TransferAsync *******************************************
+ // *************************************************************************
+ virtual Result TransferAsync(uint8_t* rx_buf_ptr, uint8_t* tx_buf_ptr, uint32_t size);
+
+ // *************************************************************************
+ // *** Public: WriteAsync **********************************************
+ // *************************************************************************
+ virtual Result WriteAsync(uint8_t* tx_buf_ptr, uint32_t tx_size);
+
+ // *************************************************************************
+ // *** Public: ReadAsync ***********************************************
+ // *************************************************************************
+ virtual Result ReadAsync(uint8_t* rx_buf_ptr, uint32_t rx_size);
+
+ // *************************************************************************
+ // *** Public: Check SPI transfer status *******************************
+ // *************************************************************************
+ virtual bool IsTransferComplete(void);
+
+ // *************************************************************************
+ // *** Public: Abort ***************************************************
+ // *************************************************************************
+ virtual Result Abort(void);
+
+ // *************************************************************************
+ // *** Public: SetSpeed ************************************************
+ // *************************************************************************
+ virtual Result SetSpeed(uint32_t clock_rate);
+
+ // *************************************************************************
+ // *** Public: GetSpeed ************************************************
+ // *************************************************************************
+ virtual Result GetSpeed(uint32_t& clock_rate);
+
+ private:
+ // Reference to the SPI handle
+ SPI_HandleTypeDef& hspi;
+
+ // *************************************************************************
+ // *** Private: GetToDataSizeBytes *************************************
+ // *************************************************************************
+ uint32_t GetToDataSizeBytes();
+
+ // *************************************************************************
+ // *** Private: ConvertResult ******************************************
+ // *************************************************************************
+ Result ConvertResult(HAL_StatusTypeDef hal_result);
+
+ // *************************************************************************
+ // *** Private: Constructors and assign operator - prevent copying *****
+ // *************************************************************************
+ StHalSpi();
+ StHalSpi(const StHalSpi&);
+ StHalSpi& operator=(const StHalSpi);
+};
+
+#endif
diff --git a/Drivers/StHalUart.cpp b/Drivers/StHalUart.cpp
new file mode 100644
index 0000000..e9b261a
--- /dev/null
+++ b/Drivers/StHalUart.cpp
@@ -0,0 +1,202 @@
+//******************************************************************************
+// @file StHalUart.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: STM32 HAL UART driver, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "StHalUart.h"
+
+// *****************************************************************************
+// *** This driver can be compiled only if UART configured in CubeMX *******
+// *****************************************************************************
+#ifdef HAL_USART_MODULE_ENABLED
+
+// *****************************************************************************
+// *** Public: Init ********************************************************
+// *****************************************************************************
+Result StHalUart::Init()
+{
+ Result result = Result::RESULT_OK;
+
+ // Clear array
+ memset(rx_buf, 0xFFU, sizeof(rx_buf));
+
+ // Start the RX DMA - this is circular, so it will never stop
+ if(HAL_UART_Receive_DMA(&huart, rx_buf, RX_BUF_SIZE) == HAL_OK)
+ {
+ // This is the first access to this object and ndtr must be initialized
+ ndtr = huart.RxXferSize;
+ }
+ else
+ {
+ result = Result::ERR_UART_RECEIVE;
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: DeInit ******************************************************
+// *****************************************************************************
+Result StHalUart::DeInit()
+{
+ Result result = Result::RESULT_OK;
+
+ if(HAL_UART_Abort(&huart) != HAL_OK)
+ {
+ result = Result::ERR_UART_GENERAL;
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Read ********************************************************
+// *****************************************************************************
+Result StHalUart::Read(uint8_t* rx_buf_ptr, uint32_t& size)
+{
+ Result result = Result::RESULT_OK;
+
+ uint16_t rx_idx = 0U;
+ // Read bytes in cycle
+ while(rx_idx < size)
+ {
+ // Temporary variable for received byte
+ uint8_t rx_byte;
+ // Read byte - this function overwrite byte in case of overrun. So,
+ // we use additional variable here. May be it isn't so necessary.
+ result = Pop(rx_byte);
+ // If read successful
+ if(result.IsGood())
+ {
+ // Save received byte
+ rx_buf_ptr[rx_idx] = rx_byte;
+ // Increment index
+ rx_idx++;
+ }
+ else
+ {
+ // Exit from the cycle
+ break;
+ }
+ }
+ // Save read bytes count
+ size = rx_idx;
+ // If we received any number of bytes - override "empty" error
+ if((rx_idx != 0U) && (result == Result::ERR_UART_EMPTY))
+ {
+ result = Result::RESULT_OK;
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Write *******************************************************
+// *****************************************************************************
+Result StHalUart::Write(uint8_t* tx_buf_ptr, uint32_t size)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ // Check input parameters
+ if(tx_buf_ptr != nullptr)
+ {
+ // Transfer data
+ HAL_StatusTypeDef hal_result = HAL_UART_Transmit_DMA(&huart, tx_buf_ptr, size);
+
+ // Convert operation result to Result
+ if(hal_result == HAL_BUSY)
+ {
+ // Busy error
+ result = Result::ERR_UART_BUSY;
+ }
+ else if(hal_result != HAL_OK)
+ {
+ // All other errors
+ result = Result::ERR_UART_TRANSMIT;
+ }
+ else
+ {
+ result = Result::RESULT_OK;
+ }
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: IsTxComplete ************************************************
+// *****************************************************************************
+bool StHalUart::IsTxComplete(void)
+{
+ // Check gState
+ return (huart.gState == HAL_UART_STATE_READY);
+}
+
+// *****************************************************************************
+// *** Private: GetRxSize **************************************************
+// *****************************************************************************
+Result StHalUart::GetRxSize(uint16_t& rx_cnt)
+{
+ // Get DMA counter from register
+ uint16_t new_ndtr = __HAL_DMA_GET_COUNTER(huart.hdmarx);
+ // Calculate number of received bytes
+ if(ndtr >= new_ndtr)
+ {
+ rx_cnt = ndtr - new_ndtr;
+ }
+ else
+ {
+ rx_cnt = huart.RxXferSize - (new_ndtr - ndtr);
+ }
+
+ return Result::RESULT_OK;
+}
+
+// *****************************************************************************
+// *** Private: Pop ********************************************************
+// *****************************************************************************
+Result StHalUart::Pop(uint8_t& value)
+{
+ Result result = Result::RESULT_OK;
+
+ // Calculate index in circular buffer
+ uint16_t index = RX_BUF_SIZE - ndtr;
+
+ // Check data
+ if(ndtr != __HAL_DMA_GET_COUNTER(huart.hdmarx))
+ {
+ // Store value
+ value = rx_buf[index];
+ // Decrease counter
+ ndtr--;
+ // Check reset
+ if(ndtr == 0U)
+ {
+ ndtr = RX_BUF_SIZE;
+ }
+ }
+ else
+ {
+ // No data
+ result = Result::ERR_UART_EMPTY;
+ }
+
+ return result;
+}
+
+#endif
diff --git a/Drivers/StHalUart.h b/Drivers/StHalUart.h
new file mode 100644
index 0000000..0864c24
--- /dev/null
+++ b/Drivers/StHalUart.h
@@ -0,0 +1,131 @@
+//******************************************************************************
+// @file StHalUart.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: STM32 HAL UART driver, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef StHalUart_h
+#define StHalUart_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "IUart.h"
+
+// *****************************************************************************
+// *** This driver can be compiled only if UART configured in CubeMX *******
+// *****************************************************************************
+#ifndef HAL_USART_MODULE_ENABLED
+ typedef uint32_t UART_HandleTypeDef; // Dummy UART handle for header compilation
+#endif
+
+// *****************************************************************************
+// *** STM32 HAL UART Driver Class *****************************************
+// *****************************************************************************
+class StHalUart : public IUart
+{
+ public:
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ explicit StHalUart(UART_HandleTypeDef& huart_ref) : huart(huart_ref) {};
+
+ // *************************************************************************
+ // *** Public: Init ****************************************************
+ // *************************************************************************
+ Result Init();
+
+ // *************************************************************************
+ // *** Public: DeInit **************************************************
+ // *************************************************************************
+ Result DeInit();
+
+ // *************************************************************************
+ // *** Public: Read ****************************************************
+ // *************************************************************************
+ Result Read(uint8_t* rx_buf_ptr, uint32_t& size);
+
+ // *************************************************************************
+ // *** Public: Write ***************************************************
+ // *************************************************************************
+ Result Write(uint8_t* tx_buf_ptr, uint32_t size);
+
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ bool IsTxComplete(void);
+
+ private:
+ // Size of buffer for receive data
+ static const uint16_t RX_BUF_SIZE = 128U;
+
+ // Buffer for receive data
+ uint8_t rx_buf[RX_BUF_SIZE];
+
+ // Reference to the UART handle
+ UART_HandleTypeDef& huart;
+
+ // Offset into DMA receive buffer of next character to receive
+ uint16_t ndtr = 0U;
+
+ // *************************************************************************
+ // *** Private: GetRxSize **********************************************
+ // *************************************************************************
+ Result GetRxSize(uint16_t& rx_cnt);
+
+ // *************************************************************************
+ // *** Private: Pop ****************************************************
+ // *************************************************************************
+ Result Pop(uint8_t& value);
+
+ // *************************************************************************
+ // *** Private: Constructors and assign operator - prevent copying *****
+ // *************************************************************************
+ StHalUart();
+ StHalUart(const StHalUart&);
+ StHalUart& operator=(const StHalUart);
+};
+
+#endif
diff --git a/Framework/AppTask.cpp b/Framework/AppTask.cpp
new file mode 100644
index 0000000..aeedc1f
--- /dev/null
+++ b/Framework/AppTask.cpp
@@ -0,0 +1,274 @@
+//******************************************************************************
+// @file AppTask.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Application Task Base Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "AppTask.h"
+#include "RtosMutex.h"
+
+// *****************************************************************************
+// *** Static variables ****************************************************
+// *****************************************************************************
+static RtosMutex startup_mutex;
+static uint32_t startup_cnt = 0U;
+
+// *****************************************************************************
+// *** Create task function ************************************************
+// *****************************************************************************
+void AppTask::CreateTask()
+{
+ Result result = Result::RESULT_OK;
+
+ // If interval timer period isn't zero or task queue present
+ if((timer.GetTimerPeriod() != 0U) || (task_queue.GetQueueLen() != 0U))
+ {
+ // Set Control Queue name
+ ctrl_queue.SetName(task_name, "Ctrl");
+ // Create control queue
+ result = ctrl_queue.Create();
+ }
+ // If task queue present
+ if(task_queue.GetQueueLen() != 0U)
+ {
+ // Set Task Queue name
+ task_queue.SetName(task_name, "Task");
+ // Create task queue
+ result |= task_queue.Create();
+ }
+ // If interval timer period isn't zero
+ if(timer.GetTimerPeriod() != 0U)
+ {
+ // Create timer
+ result |= timer.Create();
+ }
+ // Create task: function - TaskFunctionCallback(), parameter - pointer to "this"
+ result |= Rtos::TaskCreate(TaskFunctionCallback, task_name, stack_size, this, task_priority);
+
+ // Check result
+ if(result.IsBad())
+ {
+ // TODO: implement error handling
+ Break();
+ }
+}
+
+// *****************************************************************************
+// *** SendTaskMessage function ********************************************
+// *****************************************************************************
+Result AppTask::SendTaskMessage(const void* task_msg, bool is_priority)
+{
+ Result result = Result::RESULT_OK;
+
+ // Send task message to front or back of task queue
+ if(is_priority == true)
+ {
+ result = task_queue.SendToFront(task_msg);
+ }
+ else
+ {
+ result = task_queue.SendToBack(task_msg);
+ }
+
+ // If successful - send message to the control queue
+ if(result.IsGood())
+ {
+ CtrlQueueMsg ctrl_msg;
+ ctrl_msg.type = CTRL_TASK_QUEUE_MSG;
+ result = SendControlMessage(ctrl_msg, is_priority);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** IntLoop function ****************************************************
+// *****************************************************************************
+Result AppTask::IntLoop()
+{
+ Result result = Result::RESULT_OK;
+
+ while(result.IsGood())
+ {
+ // Buffer for control message
+ CtrlQueueMsg ctrl_msg;
+ // Read on the control queue
+ result = ctrl_queue.Receive(&ctrl_msg, timer.GetTimerPeriod() * 2U);
+ // If successful
+ if(result.IsGood())
+ {
+ // Check message type
+ switch(ctrl_msg.type)
+ {
+ case CTRL_TIMER_MSG:
+ result = TimerExpired();
+ break;
+
+ case CTRL_TASK_QUEUE_MSG:
+ {
+ // Non blocking read from the task queue
+ result = task_queue.Receive(task_msg_ptr, 0U);
+ // If successful
+ if(result.IsGood())
+ {
+ // Process it!
+ result = ProcessMessage();
+ }
+ break;
+ }
+
+ default:
+ result = Result::ERR_INVALID_ITEM;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** TaskFunctionCallback ************************************************
+// *****************************************************************************
+void AppTask::TaskFunctionCallback(void* ptr)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ if(ptr != nullptr)
+ {
+ // Set good result
+ result = Result::RESULT_OK;
+ // Get reference to the task object
+ AppTask& app_task = *(static_cast<AppTask*>(ptr));
+
+ // Increment counter before call Setup()
+ ChangeCnt(true);
+ // Call virtual Setup() function from AppTask class
+ app_task.Setup();
+ // Decrement counter after call Setup()
+ ChangeCnt(false);
+ // Pause for give other tasks run Setup()
+ RtosTick::DelayTicks(1U);
+ // Pause while other tasks run Setup() before executing any Loop()
+ while(startup_cnt) RtosTick::DelayTicks(1U);
+
+ // If no timer or queue - just call Loop() function
+ if((app_task.timer.GetTimerPeriod() == 0U) && (app_task.task_queue.GetQueueLen() == 0U))
+ {
+ // Call virtual Loop() function from AppTask class
+ while(app_task.Loop() == Result::RESULT_OK);
+ }
+ else
+ {
+ // Start task timer if needed
+ if(app_task.timer.GetTimerPeriod() != 0U)
+ {
+ result = app_task.timer.Start();
+ }
+ // Check result
+ if(result.IsGood())
+ {
+ // Call internal AppTask function
+ result = app_task.IntLoop();
+ }
+ // Stop task timer if needed
+ if(app_task.timer.GetTimerPeriod() != 0U)
+ {
+ result |= app_task.timer.Stop();
+ }
+ }
+ }
+
+ // Check result
+ if(result.IsBad())
+ {
+ // TODO: implement error handling
+ Break();
+ }
+
+ // Delete task after exit
+ Rtos::TaskDelete();
+}
+
+// *****************************************************************************
+// *** TimerCallback function **********************************************
+// *****************************************************************************
+void AppTask::TimerCallback(void* ptr)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ if(ptr != nullptr)
+ {
+ // Get reference to the task object
+ AppTask& task = *((AppTask*)ptr);
+
+ // Create control timer message
+ CtrlQueueMsg timer_msg;
+ timer_msg.type = CTRL_TIMER_MSG;
+
+ // Send message to the control queue
+ result = task.SendControlMessage(timer_msg);
+ }
+
+ // Check result
+ if(result.IsBad())
+ {
+ // TODO: implement error handling
+ Break();
+ }
+}
+
+// *****************************************************************************
+// *** SendControlMessage function *****************************************
+// *****************************************************************************
+Result AppTask::SendControlMessage(const CtrlQueueMsg& ctrl_msg, bool is_priority)
+{
+ Result result;
+
+ if(is_priority == true)
+ {
+ result = ctrl_queue.SendToFront(&ctrl_msg);
+ }
+ else
+ {
+ result = ctrl_queue.SendToBack(&ctrl_msg);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Change counter ******************************************************
+// *****************************************************************************
+void AppTask::ChangeCnt(bool is_up)
+{
+ // Take semaphore before change counter
+ startup_mutex.Lock();
+ // Check direction
+ if(is_up == true)
+ {
+ // Increment counter
+ startup_cnt++;
+ }
+ else
+ {
+ // Decrement counter
+ startup_cnt--;
+ }
+ // Give semaphore after changes
+ startup_mutex.Release();
+}
diff --git a/Framework/AppTask.h b/Framework/AppTask.h
new file mode 100644
index 0000000..bf54487
--- /dev/null
+++ b/Framework/AppTask.h
@@ -0,0 +1,185 @@
+//******************************************************************************
+// @file AppTask.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Application Task Base Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef AppTask_h
+#define AppTask_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+
+// *****************************************************************************
+// * AppTask class. This class is wrapper for call C++ function from class. ****
+// *****************************************************************************
+class AppTask
+{
+ public:
+ // *************************************************************************
+ // *** Init Task *******************************************************
+ // *************************************************************************
+ virtual void InitTask(void) {CreateTask();}
+
+ protected:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ AppTask(uint16_t stk_size, uint8_t task_prio, const char name[],
+ uint16_t queue_len = 0U, uint16_t queue_msg_size = 0U,
+ void* task_msg_p = nullptr, uint32_t task_interval_ms = 0U) :
+ ctrl_queue((queue_len + 2U), sizeof(CtrlQueueMsg)),
+ task_queue(queue_len, queue_msg_size), task_msg_ptr(task_msg_p),
+ timer(task_interval_ms, RtosTimer::REPEATING, TimerCallback, (void*)this),
+ stack_size(stk_size), task_priority(task_prio), task_name(name) {};
+
+ // *************************************************************************
+ // *** Virtual destructor - prevent warning ****************************
+ // *************************************************************************
+ virtual ~AppTask() {};
+
+ // *************************************************************************
+ // *** Create task function ********************************************
+ // *************************************************************************
+ // * This function creates new task in FreeRTOS, provide pointer to function
+ // * and pointer to class as parameter. When TaskFunctionCallback() called
+ // * from FreeRTOS, it use pointer to class from parameter to call virtual
+ // * functions.
+ void CreateTask();
+
+ // *************************************************************************
+ // *** Setup function **************************************************
+ // *************************************************************************
+ // * * virtual function - some tasks may not have Setup() actions
+ virtual Result Setup() {return Result::RESULT_OK;}
+
+ // *************************************************************************
+ // *** IntervalTimerExpired function ***********************************
+ // *************************************************************************
+ // * Empty virtual function - some tasks may not have TimerExpired() actions
+ virtual Result TimerExpired() {return Result::RESULT_OK;}
+
+ // *************************************************************************
+ // *** ProcessMessage function *****************************************
+ // *************************************************************************
+ // * Empty virtual function - some tasks may not have ProcessMessage() actions
+ virtual Result ProcessMessage() {return Result::RESULT_OK;}
+
+ // *************************************************************************
+ // *** Loop function ***************************************************
+ // *************************************************************************
+ // * Empty virtual function - some tasks may not have Loop() actions
+ virtual Result Loop() {return Result::RESULT_OK;}
+
+ // *************************************************************************
+ // *** SendTaskMessage function ****************************************
+ // *************************************************************************
+ Result SendTaskMessage(const void* task_msg, bool is_priority = false);
+
+ private:
+ // Task control queue message types
+ enum CtrlQueueMsgType
+ {
+ CTRL_TIMER_MSG,
+ CTRL_TASK_QUEUE_MSG
+ };
+ // Task control queue message struct
+ struct CtrlQueueMsg
+ {
+ CtrlQueueMsgType type;
+ };
+ // Task control queue
+ RtosQueue ctrl_queue;
+
+ // Task queue
+ RtosQueue task_queue;
+ // Pointer to receive message buffer
+ void* task_msg_ptr;
+
+ // Timer object
+ RtosTimer timer;
+
+ // Task stack size
+ uint16_t stack_size;
+ // Task priority
+ uint8_t task_priority;
+ // Pointer to the task name
+ const char* task_name;
+
+ // *************************************************************************
+ // *** IntLoop function ************************************************
+ // *************************************************************************
+ Result IntLoop();
+
+ // *************************************************************************
+ // *** TaskFunctionCallback ********************************************
+ // *************************************************************************
+ static void TaskFunctionCallback(void* ptr);
+
+ // *************************************************************************
+ // *** IntervalTimerCallback function **********************************
+ // *************************************************************************
+ static void TimerCallback(void* ptr);
+
+ // *************************************************************************
+ // *** SendControlMessage function *************************************
+ // *************************************************************************
+ Result SendControlMessage(const CtrlQueueMsg& ctrl_msg, bool is_priority = false);
+
+ // *************************************************************************
+ // *** Change counter **************************************************
+ // *************************************************************************
+ static void ChangeCnt(bool is_up);
+
+ // *************************************************************************
+ // *** Private constructor and assign operator - prevent copying *******
+ // *************************************************************************
+ AppTask();
+ AppTask(const AppTask&);
+ AppTask& operator=(const AppTask&);
+};
+
+#endif
diff --git a/Framework/Result.h b/Framework/Result.h
new file mode 100644
index 0000000..74d27b9
--- /dev/null
+++ b/Framework/Result.h
@@ -0,0 +1,232 @@
+//******************************************************************************
+// @file Result.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Result codes, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef Result_h
+#define Result_h
+
+// *****************************************************************************
+// *** Result **************************************************************
+// *****************************************************************************
+class Result
+{
+ public:
+ // *************************************************************************
+ // *** Enum with all possible result codes *****************************
+ // *************************************************************************
+ enum ResultCode
+ {
+ // *** No error ******************************************************
+ RESULT_OK = 0,
+
+ // *** Generic *******************************************************
+ ERR_NULL_PTR,
+ ERR_BAD_PARAMETER,
+ ERR_INVALID_ITEM,
+ ERR_NOT_IMPLEMENTED,
+ ERR_BUSY,
+
+ // *** RTOS errors ***************************************************
+ ERR_TASK_CREATE,
+ ERR_QUEUE_CREATE,
+ ERR_QUEUE_GENERAL,
+ ERR_QUEUE_EMPTY,
+ ERR_QUEUE_READ,
+ ERR_QUEUE_WRITE,
+ ERR_QUEUE_RESET,
+ ERR_TIMER_CREATE,
+ ERR_TIMER_START,
+ ERR_TIMER_UPDATE,
+ ERR_TIMER_STOP,
+ ERR_MUTEX_CREATE,
+ ERR_MUTEX_LOCK,
+ ERR_MUTEX_RELEASE,
+ ERR_SEMAPHORE_CREATE,
+ ERR_SEMAPHORE_TAKE,
+ ERR_SEMAPHORE_GIVE,
+
+ // *** UART errors ***************************************************
+ ERR_UART_GENERAL,
+ ERR_UART_TRANSMIT,
+ ERR_UART_RECEIVE,
+ ERR_UART_EMPTY,
+ ERR_UART_BUSY,
+ ERR_UART_TIMEOUT,
+ ERR_UART_UNKNOWN,
+
+ // *** I2C errors ****************************************************
+ ERR_I2C_GENERAL,
+ ERR_I2C_BUSY,
+ ERR_I2C_TIMEOUT,
+ ERR_I2C_UNKNOWN,
+
+ // *** SPI errors ****************************************************
+ ERR_SPI_GENERAL,
+ ERR_SPI_BUSY,
+ ERR_SPI_TIMEOUT,
+ ERR_SPI_UNKNOWN,
+
+ // *** Elements count ************************************************
+ RESULTS_CNT
+ };
+
+ // *************************************************************************
+ // *** Result **********************************************************
+ // *************************************************************************
+ Result() {};
+
+ // *************************************************************************
+ // *** Result **********************************************************
+ // *************************************************************************
+ Result(ResultCode res)
+ {
+ result = res;
+ }
+
+ // *************************************************************************
+ // *** IsGood **********************************************************
+ // *************************************************************************
+ bool IsGood() const
+ {
+ return result == RESULT_OK;
+ }
+
+ // *************************************************************************
+ // *** IsBad ***********************************************************
+ // *************************************************************************
+ bool IsBad() const
+ {
+ return result != RESULT_OK;
+ }
+
+ // *************************************************************************
+ // *** operator ResultCode *********************************************
+ // *************************************************************************
+ operator ResultCode() const
+ {
+ return result;
+ }
+
+ // *************************************************************************
+ // *** operator= *******************************************************
+ // *************************************************************************
+ Result& operator=(ResultCode res)
+ {
+ result = res;
+ return *this;
+ }
+
+ // *************************************************************************
+ // *** operator= *******************************************************
+ // *************************************************************************
+ Result& operator=(const Result& r_arg)
+ {
+ result = r_arg.result;
+ return *this;
+ }
+
+ // *************************************************************************
+ // *** operator|= ******************************************************
+ // *************************************************************************
+ Result& operator|=(ResultCode res)
+ {
+ if(result == RESULT_OK)
+ {
+ result = res;
+ }
+ return *this;
+ }
+
+ // *************************************************************************
+ // *** operator|= ******************************************************
+ // *************************************************************************
+ Result& operator|=(const Result& r_arg)
+ {
+ if(result == RESULT_OK)
+ {
+ result = r_arg.result;
+ }
+ return *this;
+ }
+
+ // *************************************************************************
+ // *** operator== ******************************************************
+ // *************************************************************************
+ bool operator==(ResultCode res) const
+ {
+ return(result == res);
+ }
+
+ // *************************************************************************
+ // *** operator== ******************************************************
+ // *************************************************************************
+ bool operator==(const Result& r_arg) const
+ {
+ return result == r_arg.result;
+ }
+
+ // *************************************************************************
+ // *** operator!= ******************************************************
+ // *************************************************************************
+ bool operator!=(ResultCode res) const
+ {
+ return(result != res);
+ }
+
+ // *************************************************************************
+ // *** operator!= ******************************************************
+ // *************************************************************************
+ bool operator!=(const Result& r_arg) const
+ {
+ return(result != r_arg.result);
+ }
+
+ private:
+ // Result code
+ ResultCode result = RESULT_OK;
+};
+
+#endif
diff --git a/FreeRtosWrapper/Rtos.cpp b/FreeRtosWrapper/Rtos.cpp
new file mode 100644
index 0000000..549df51
--- /dev/null
+++ b/FreeRtosWrapper/Rtos.cpp
@@ -0,0 +1,108 @@
+//******************************************************************************
+// @file Rtos.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Wrapper, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "Rtos.h"
+
+// *****************************************************************************
+// *** TaskCreate **********************************************************
+// *****************************************************************************
+Result Rtos::TaskCreate(TaskFunction& function, const char* task_name,
+ const uint16_t stack_depth, void* param_ptr,
+ uint8_t priority)
+{
+ Result result = Result::ERR_TASK_CREATE;
+
+ // Create task: function - TaskFunWrapper(), parameter - pointer "this"
+ BaseType_t res = xTaskCreate(&function, task_name, stack_depth, param_ptr, priority, nullptr);
+ // Check result
+ if(res == pdPASS)
+ {
+ result = Result::RESULT_OK;
+ }
+
+ return result;
+}
+
+// *************************************************************************
+// *** TaskDelete ******************************************************
+// *************************************************************************
+void Rtos::TaskDelete(TaskHandle_t task)
+{
+ // Delete task
+ vTaskDelete(task);
+}
+
+// *****************************************************************************
+// *** Determine whether we are in thread mode or handler mode *************
+// *****************************************************************************
+bool Rtos::IsInHandlerMode(void)
+{
+ return __get_IPSR() != 0;
+}
+
+// *****************************************************************************
+// *** SuspendScheduler ****************************************************
+// *****************************************************************************
+void Rtos::SuspendScheduler()
+{
+ vTaskSuspendAll();
+}
+
+// *****************************************************************************
+// *** ResumeScheduler *****************************************************
+// *****************************************************************************
+void Rtos::ResumeScheduler()
+{
+ // Discard return value, since the destructor can't do anything with it
+ // and it's unlikely to be used.
+ (void) xTaskResumeAll();
+}
+
+// *****************************************************************************
+// *** EnterCriticalSection ************************************************
+// *****************************************************************************
+void Rtos::EnterCriticalSection()
+{
+ taskENTER_CRITICAL();
+}
+
+// *****************************************************************************
+// *** ExitCriticalSection *************************************************
+// *****************************************************************************
+void Rtos::ExitCriticalSection()
+{
+ taskEXIT_CRITICAL();
+}
+
+// *****************************************************************************
+// *** DisableInterrupts ***************************************************
+// *****************************************************************************
+void Rtos::DisableInterrupts()
+{
+ taskDISABLE_INTERRUPTS();
+}
+
+// *****************************************************************************
+// *** EnableInterrupts ****************************************************
+// *****************************************************************************
+void Rtos::EnableInterrupts()
+{
+ taskENABLE_INTERRUPTS();
+}
diff --git a/FreeRtosWrapper/Rtos.h b/FreeRtosWrapper/Rtos.h
new file mode 100644
index 0000000..ee5e2f9
--- /dev/null
+++ b/FreeRtosWrapper/Rtos.h
@@ -0,0 +1,124 @@
+//******************************************************************************
+// @file Rtos.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Wrapper, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef Rtos_h
+#define Rtos_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "DevCfg.h"
+#include "RtosTick.h"
+#include "RtosTimer.h"
+#include "RtosQueue.h"
+#include "RtosMutex.h"
+#include "RtosSemaphore.h"
+
+// *****************************************************************************
+// *** Rtos ****************************************************************
+// *****************************************************************************
+class Rtos
+{
+ public:
+ // Definition of callback function
+ typedef void (TaskFunction)(void* ptr);
+
+ // *************************************************************************
+ // *** TaskCreate ******************************************************
+ // *************************************************************************
+ static Result TaskCreate(TaskFunction& function, const char* task_name,
+ const uint16_t stack_depth, void* param_ptr,
+ uint8_t priority);
+
+ // *************************************************************************
+ // *** TaskDelete ******************************************************
+ // *************************************************************************
+ static void TaskDelete(TaskHandle_t task = nullptr);
+
+ // *************************************************************************
+ // *** IsInHandlerMode *************************************************
+ // *************************************************************************
+ static bool IsInHandlerMode();
+
+ // *************************************************************************
+ // *** SuspendScheduler ************************************************
+ // *************************************************************************
+ static void SuspendScheduler();
+
+ // *************************************************************************
+ // *** ResumeScheduler *************************************************
+ // *************************************************************************
+ static void ResumeScheduler();
+
+ // *************************************************************************
+ // *** EnterCriticalSection ********************************************
+ // *************************************************************************
+ static void EnterCriticalSection();
+
+ // *************************************************************************
+ // *** ExitCriticalSection *********************************************
+ // *************************************************************************
+ static void ExitCriticalSection();
+
+ // *************************************************************************
+ // *** DisableInterrupts ***********************************************
+ // *************************************************************************
+ static void DisableInterrupts();
+
+ // *************************************************************************
+ // *** EnableInterrupts ************************************************
+ // *************************************************************************
+ static void EnableInterrupts();
+
+ private:
+ // None
+};
+
+#endif
diff --git a/FreeRtosWrapper/RtosMutex.cpp b/FreeRtosWrapper/RtosMutex.cpp
new file mode 100644
index 0000000..8a54679
--- /dev/null
+++ b/FreeRtosWrapper/RtosMutex.cpp
@@ -0,0 +1,124 @@
+//******************************************************************************
+// @file RtosMutex.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Mutex Wrapper Class, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "RtosMutex.h"
+#include "Rtos.h"
+
+// *****************************************************************************
+// *** Constructor **********************************************************
+// *****************************************************************************
+RtosMutex::RtosMutex()
+{
+ // Create semaphore
+ mutex = xSemaphoreCreateMutex();
+ // Check error
+ if(mutex == nullptr)
+ {
+ // TODO: implement error handling
+ Break();
+ }
+}
+
+// *****************************************************************************
+// *** Destructor **********************************************************
+// *****************************************************************************
+RtosMutex::~RtosMutex()
+{
+ if(mutex == nullptr)
+ {
+ vSemaphoreDelete(mutex);
+ }
+}
+
+// *****************************************************************************
+// *** Lock ****************************************************************
+// *****************************************************************************
+Result RtosMutex::Lock(TickType_t ticks_to_wait)
+{
+ Result result;
+ // Variable for check result
+ BaseType_t res;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ BaseType_t task_woken;
+ // Take mutex from ISR
+ res = xSemaphoreTakeFromISR(mutex, &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // Take mutex
+ res = xSemaphoreTake(mutex, ticks_to_wait);
+ }
+
+ // Find result
+ if(res == pdTRUE)
+ {
+ result = Result::RESULT_OK;
+ }
+ else
+ {
+ result = Result::ERR_MUTEX_LOCK;
+ }
+
+ // Return result
+ return result;
+}
+
+
+// *****************************************************************************
+// *** Release *************************************************************
+// *****************************************************************************
+Result RtosMutex::Release()
+{
+ Result result;
+ // Variable for check result
+ BaseType_t res = xSemaphoreGive(mutex);
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ BaseType_t task_woken;
+ // Give mutex from ISR
+ res = xSemaphoreGiveFromISR(mutex, &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // Give mutex
+ res = xSemaphoreGive(mutex);
+ }
+
+ // Find result
+ if(res == pdTRUE)
+ {
+ result = Result::RESULT_OK;
+ }
+ else
+ {
+ result = Result::ERR_MUTEX_RELEASE;
+ }
+ // Return result
+ return result;
+}
diff --git a/FreeRtosWrapper/RtosMutex.h b/FreeRtosWrapper/RtosMutex.h
new file mode 100644
index 0000000..4bc2eb4
--- /dev/null
+++ b/FreeRtosWrapper/RtosMutex.h
@@ -0,0 +1,59 @@
+//******************************************************************************
+// @file RtosMutex.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Mutex Wrapper Class, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef RtosMutex_h
+#define RtosMutex_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "Rtos.h"
+#include "semphr.h"
+
+// *****************************************************************************
+// *** RtosMutex ***********************************************************
+// *****************************************************************************
+class RtosMutex
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ RtosMutex();
+
+ // *************************************************************************
+ // *** Destructor ******************************************************
+ // *************************************************************************
+ ~RtosMutex();
+
+ // *************************************************************************
+ // *** Lock ************************************************************
+ // *************************************************************************
+ Result Lock(TickType_t ticks_to_wait = portMAX_DELAY);
+
+ // *************************************************************************
+ // *** Release *********************************************************
+ // *************************************************************************
+ Result Release();
+
+ private:
+ // Mutex handle
+ SemaphoreHandle_t mutex;
+};
+
+#endif
diff --git a/FreeRtosWrapper/RtosQueue.cpp b/FreeRtosWrapper/RtosQueue.cpp
new file mode 100644
index 0000000..eb2e767
--- /dev/null
+++ b/FreeRtosWrapper/RtosQueue.cpp
@@ -0,0 +1,363 @@
+//******************************************************************************
+// @file RtosQueue.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Rtos Wrapper Class, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "RtosQueue.h"
+#include "Rtos.h"
+
+// *****************************************************************************
+// *** RtosQueue ***********************************************************
+// *****************************************************************************
+RtosQueue::RtosQueue(uint32_t q_len, uint32_t itm_size, const char* queue_name)
+ : queue(nullptr), queue_len(q_len), item_size(itm_size)
+{
+ // Set name
+ SetName(queue_name);
+}
+
+// *****************************************************************************
+// *** ~RtosQueue **********************************************************
+// *****************************************************************************
+RtosQueue::~RtosQueue()
+{
+ // Check queue handle
+ if(queue != nullptr)
+ {
+ vQueueDelete(queue);
+ }
+}
+
+// *****************************************************************************
+// *** ~RtosQueue **********************************************************
+// *****************************************************************************
+void RtosQueue::SetName(const char* name, const char* add_name)
+{
+ uint32_t i = 0U;
+ // If name pointer isn't null
+ if(name != nullptr)
+ {
+ // Copy queue name
+ for(; (i < MAX_QUEUE_NAME_LEN - 1U) && (name[i] != '\0'); i++)
+ {
+ queue_name[i] = name[i];
+ }
+ }
+ // If additional name pointer isn't null
+ if(add_name != nullptr)
+ {
+ // Copy additional queue name
+ for(uint32_t j = 0U; (i < MAX_QUEUE_NAME_LEN - 1U) && (add_name[j] != '\0'); i++, j++)
+ {
+ queue_name[i] = add_name[j];
+ }
+ }
+ // Set null-terminator for string
+ queue_name[i] = '\0';
+}
+
+// *****************************************************************************
+// *** Create **************************************************************
+// *****************************************************************************
+Result RtosQueue::Create()
+{
+ Result result = Result::ERR_QUEUE_CREATE;
+
+ // Check queue handle
+ if(queue == nullptr)
+ {
+ // Create queue
+ queue = xQueueCreate(queue_len, item_size);
+
+ // Check result
+ if(queue != nullptr)
+ {
+ // If name present - add to registry
+ if(queue_name[0] != '\0')
+ {
+ vQueueAddToRegistry(queue, queue_name);
+ }
+ // Set result
+ result = Result::RESULT_OK;
+ }
+ }
+
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** Reset ***************************************************************
+// *****************************************************************************
+Result RtosQueue::Reset()
+{
+ Result result = Result::ERR_QUEUE_RESET;
+
+ // Check queue handle
+ if(queue != nullptr)
+ {
+ // Reset queue
+ if(xQueueReset(queue) == pdPASS)
+ {
+ // Set result
+ result = Result::RESULT_OK;
+ }
+ }
+
+ // Return result
+ return result;
+}
+
+
+// *****************************************************************************
+// *** IsEmpty *************************************************************
+// *****************************************************************************
+bool RtosQueue::IsEmpty() const
+{
+ bool is_empty = false;
+
+ // Check queue handle
+ if(queue != nullptr)
+ {
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ // Check is queue empty
+ is_empty = (xQueueIsQueueEmptyFromISR(queue) != pdFALSE);
+ }
+ else
+ {
+ // Check is queue empty
+ is_empty = (uxQueueMessagesWaiting(queue) == 0U);
+ }
+ }
+
+ return is_empty;
+}
+
+// *****************************************************************************
+// *** IsFull **************************************************************
+// *****************************************************************************
+bool RtosQueue::IsFull() const
+{
+ bool is_full = false;
+
+ // Check queue handle
+ if(queue != nullptr)
+ {
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ // Check is queue full
+ is_full = (xQueueIsQueueFullFromISR(queue) != pdFALSE);
+ }
+ else
+ {
+ // Check is queue full
+ is_full = (uxQueueMessagesWaiting(queue) >= queue_len);
+ }
+ }
+
+ return is_full;
+}
+
+// *****************************************************************************
+// *** GetMessagesWaiting **************************************************
+// *****************************************************************************
+Result RtosQueue::GetMessagesWaiting(uint32_t& msg_cnt) const
+{
+ Result result = Result::ERR_QUEUE_GENERAL;
+
+ // Check queue handle
+ if(queue != nullptr)
+ {
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ msg_cnt = uxQueueMessagesWaitingFromISR(queue);
+ }
+ else
+ {
+ msg_cnt = uxQueueMessagesWaiting(queue);
+ }
+ // Set result
+ result = Result::RESULT_OK;
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** SendToBack **********************************************************
+// *****************************************************************************
+Result RtosQueue::SendToBack(const void* item, uint32_t timeout_ms)
+{
+ Result result = Result::ERR_QUEUE_WRITE;
+
+ // Check queue handle and item pointer
+ if((queue != nullptr) && (item != nullptr))
+ {
+ // Result of operation
+ portBASE_TYPE res = pdFALSE;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ BaseType_t task_woken;
+ // Send item to back of queue from ISR
+ res = xQueueSendToBackFromISR(queue, item, &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // Send item to back of queue
+ res = xQueueSendToBack(queue, item, RtosTick::MsToTicks(timeout_ms));
+ }
+ // Check result
+ if(res == pdPASS)
+ {
+ result = Result::RESULT_OK;
+ }
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** SendToFront *********************************************************
+// *****************************************************************************
+Result RtosQueue::SendToFront(const void* item, uint32_t timeout_ms)
+{
+ Result result = Result::ERR_QUEUE_WRITE;
+
+ // Check queue handle and item pointer
+ if((queue != nullptr) && (item != nullptr))
+ {
+ // Result of operation
+ portBASE_TYPE res = pdFALSE;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ BaseType_t task_woken;
+ // Send item to front of queue from ISR
+ res = xQueueSendToFrontFromISR(queue, item, &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // Send item to front of queue
+ res = xQueueSendToFront(queue, item, RtosTick::MsToTicks(timeout_ms));
+ }
+ // Check result
+ if(res == pdPASS)
+ {
+ result = Result::RESULT_OK;
+ }
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Receive *************************************************************
+// *****************************************************************************
+Result RtosQueue::Receive(void* item, uint32_t timeout_ms)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ // Check queue handle and item pointer
+ if((queue != nullptr) && (item != nullptr))
+ {
+ // Set new error result
+ result = Result::ERR_QUEUE_READ;
+ // Result of operation
+ portBASE_TYPE res = pdFALSE;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ if(IsEmpty() == false)
+ {
+ BaseType_t task_woken;
+ // Receive item from the queue from ISR
+ res = xQueueReceiveFromISR(queue, item, &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // Queue is empty - nothing to read
+ result = Result::ERR_QUEUE_EMPTY;
+ }
+ }
+ else
+ {
+ // Receive item from the queue
+ res = xQueueReceive(queue, item, RtosTick::MsToTicks(timeout_ms));
+ // Check empty error
+ if(res == errQUEUE_EMPTY)
+ {
+ result = Result::ERR_QUEUE_EMPTY;
+ }
+ }
+ // Check result
+ if(res == pdPASS)
+ {
+ result = Result::RESULT_OK;
+ }
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Peek ****************************************************************
+// *****************************************************************************
+Result RtosQueue::Peek(void* item, uint32_t timeout_ms) const
+{
+ Result result = Result::ERR_QUEUE_READ;
+
+ // Check queue handle and item pointer
+ if((queue != nullptr) && (item != nullptr))
+ {
+ // Result of operation
+ portBASE_TYPE res = pdFALSE;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ // Peek message from ISR
+ res = xQueuePeekFromISR(queue, item);
+ }
+ else
+ {
+ // Peek message
+ res = xQueuePeek(queue, item, RtosTick::MsToTicks(timeout_ms));
+ }
+ // Check result
+ if(res == pdPASS)
+ {
+ result = Result::RESULT_OK;
+ }
+ }
+
+ return result;
+}
diff --git a/FreeRtosWrapper/RtosQueue.h b/FreeRtosWrapper/RtosQueue.h
new file mode 100644
index 0000000..3757810
--- /dev/null
+++ b/FreeRtosWrapper/RtosQueue.h
@@ -0,0 +1,157 @@
+//******************************************************************************
+// @file RtosMutex.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Queue Wrapper Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef RtosQueue_h
+#define RtosQueue_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "Rtos.h"
+#include "queue.h"
+
+// ******************************************************************************
+// *** RtosQueue ************************************************************
+// ******************************************************************************
+class RtosQueue
+{
+ public:
+ // Maximum queue name length
+ static const uint16_t MAX_QUEUE_NAME_LEN = 24U;
+
+ // *************************************************************************
+ // *** RtosQueue *******************************************************
+ // *************************************************************************
+ RtosQueue(uint32_t q_len, uint32_t itm_size, const char* queue_name = nullptr);
+
+ // *************************************************************************
+ // *** ~RtosQueue ******************************************************
+ // *************************************************************************
+ ~RtosQueue();
+
+ // *************************************************************************
+ // *** SetName *********************************************************
+ // *************************************************************************
+ void SetName(const char* name, const char* add_name = nullptr);
+
+ // *************************************************************************
+ // *** Create **********************************************************
+ // *************************************************************************
+ Result Create();
+
+ // *************************************************************************
+ // *** Reset ***********************************************************
+ // *************************************************************************
+ Result Reset();
+
+ // *************************************************************************
+ // *** IsEmpty *********************************************************
+ // *************************************************************************
+ bool IsEmpty() const;
+
+ // *************************************************************************
+ // *** IsFull **********************************************************
+ // *************************************************************************
+ bool IsFull() const;
+
+ // *************************************************************************
+ // *** GetMessagesWaiting **********************************************
+ // *************************************************************************
+ Result GetMessagesWaiting(uint32_t& msg_cnt) const;
+
+ // *************************************************************************
+ // *** SendToBack ******************************************************
+ // *************************************************************************
+ Result SendToBack(const void* item, uint32_t timeout_ms = 0U);
+
+ // *************************************************************************
+ // *** SendToFront *****************************************************
+ // *************************************************************************
+ Result SendToFront(const void* item, uint32_t timeout_ms = 0U);
+
+ // *************************************************************************
+ // *** Receive *********************************************************
+ // *************************************************************************
+ Result Receive(void* item, uint32_t timeout_ms);
+
+ // *************************************************************************
+ // *** Peek ************************************************************
+ // *************************************************************************
+ Result Peek(void* item, uint32_t timeout_ms) const;
+
+ // *************************************************************************
+ // *** GetQueueLen *****************************************************
+ // *************************************************************************
+ inline uint16_t GetQueueLen(void) const {return queue_len;}
+
+ // *************************************************************************
+ // *** GetItemSize *****************************************************
+ // *************************************************************************
+ inline uint16_t GetItemSize(void) const {return item_size;}
+
+ private:
+ // Queue handle
+ QueueHandle_t queue;
+
+ // Number of items in the queue
+ uint16_t queue_len;
+
+ // Size of item
+ uint16_t item_size;
+
+ // Queue name
+ char queue_name[MAX_QUEUE_NAME_LEN];
+
+ // Prevent copying and assigning
+ RtosQueue();
+ RtosQueue(const RtosQueue&);
+ RtosQueue& operator=(const RtosQueue&);
+};
+
+
+#endif // FREE_RTOS_QUEUE_H
diff --git a/FreeRtosWrapper/RtosSemaphore.cpp b/FreeRtosWrapper/RtosSemaphore.cpp
new file mode 100644
index 0000000..88d5abb
--- /dev/null
+++ b/FreeRtosWrapper/RtosSemaphore.cpp
@@ -0,0 +1,125 @@
+//******************************************************************************
+// @file RtosSemaphore.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Semaphore Wrapper Class, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "RtosSemaphore.h"
+#include "Rtos.h"
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+RtosSemaphore::RtosSemaphore()
+{
+ // Create semaphore
+ semaphore = xSemaphoreCreateBinary();
+ // Check error
+ if(semaphore == nullptr)
+ {
+ // TODO: implement error handling
+ Break();
+ }
+}
+
+// *****************************************************************************
+// *** Destructor **********************************************************
+// *****************************************************************************
+RtosSemaphore::~RtosSemaphore()
+{
+ if(semaphore == nullptr)
+ {
+ vSemaphoreDelete(semaphore);
+ }
+}
+
+// *****************************************************************************
+// *** Take ****************************************************************
+// *****************************************************************************
+Result RtosSemaphore::Take(TickType_t ticks_to_wait)
+{
+ Result result;
+ // Variable for check result
+ BaseType_t res;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ BaseType_t task_woken;
+ // Take semaphore from ISR
+ res = xSemaphoreTakeFromISR(semaphore, &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // Take semaphore
+ res = xSemaphoreTake(semaphore, ticks_to_wait);
+ }
+
+ // Find result
+ if(res == pdTRUE)
+ {
+ result = Result::RESULT_OK;
+ }
+ else
+ {
+ result = Result::ERR_SEMAPHORE_TAKE;
+ }
+
+ // Return result
+ return result;
+}
+
+
+// *****************************************************************************
+// *** Take ****************************************************************
+// *****************************************************************************
+Result RtosSemaphore::Give()
+{
+ Result result;
+ // Variable for check result
+ BaseType_t res = xSemaphoreGive(semaphore);
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ BaseType_t task_woken;
+ // Give semaphore from ISR
+ res = xSemaphoreGiveFromISR(semaphore, &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // Give semaphore
+ res = xSemaphoreGive(semaphore);
+ }
+
+ // Find result
+ if(res == pdTRUE)
+ {
+ result = Result::RESULT_OK;
+ }
+ else
+ {
+ result = Result::ERR_SEMAPHORE_GIVE;
+ }
+
+ // Return result
+ return result;
+}
diff --git a/FreeRtosWrapper/RtosSemaphore.h b/FreeRtosWrapper/RtosSemaphore.h
new file mode 100644
index 0000000..bce1b9e
--- /dev/null
+++ b/FreeRtosWrapper/RtosSemaphore.h
@@ -0,0 +1,89 @@
+//******************************************************************************
+// @file RtosSemaphore.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Semaphore Wrapper Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef RtosSemaphore_h
+#define RtosSemaphore_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "Rtos.h"
+#include "semphr.h"
+
+// *****************************************************************************
+// *** RtosSemaphore *******************************************************
+// *****************************************************************************
+class RtosSemaphore
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ RtosSemaphore();
+
+ // *************************************************************************
+ // *** Destructor ******************************************************
+ // *************************************************************************
+ ~RtosSemaphore();
+
+ // *************************************************************************
+ // *** Take ************************************************************
+ // *************************************************************************
+ Result Take(TickType_t ticks_to_wait = portMAX_DELAY);
+
+ // *************************************************************************
+ // *** Give ************************************************************
+ // *************************************************************************
+ Result Give();
+
+ private:
+ // Semaphore handle
+ SemaphoreHandle_t semaphore;
+};
+
+#endif
diff --git a/FreeRtosWrapper/RtosTick.cpp b/FreeRtosWrapper/RtosTick.cpp
new file mode 100644
index 0000000..d24158f
--- /dev/null
+++ b/FreeRtosWrapper/RtosTick.cpp
@@ -0,0 +1,103 @@
+//******************************************************************************
+// @file RtosTick.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Tick Wrapper Class, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+
+#include "RtosTick.h"
+#include "Rtos.h"
+
+#include "portmacro.h"
+
+// *****************************************************************************
+// *** GetTickCount ********************************************************
+// *****************************************************************************
+uint32_t RtosTick::GetTickCount()
+{
+ uint32_t tick_count = 0U;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ tick_count = xTaskGetTickCountFromISR();
+ }
+ else
+ {
+ tick_count = xTaskGetTickCount();
+ }
+
+ return tick_count;
+}
+
+// *****************************************************************************
+// *** GetTimeMs ***********************************************************
+// *****************************************************************************
+uint32_t RtosTick::GetTimeMs()
+{
+ uint32_t time_ms = TicksToMs(GetTickCount());
+ return time_ms;
+}
+
+// *****************************************************************************
+// *** DelayTicks **********************************************************
+// *****************************************************************************
+void RtosTick::DelayTicks(uint32_t ticks)
+{
+ vTaskDelay(ticks);
+}
+
+// *****************************************************************************
+// *** DelayMs *************************************************************
+// *****************************************************************************
+void RtosTick::DelayMs(uint32_t time_ms)
+{
+ vTaskDelay(MsToTicks(time_ms));
+}
+
+// *****************************************************************************
+// *** DelayUntilTicks *****************************************************
+// *****************************************************************************
+void RtosTick::DelayUntilTicks(uint32_t& last_wake_ticks, uint32_t ticks)
+{
+ vTaskDelayUntil(&last_wake_ticks, ticks);
+}
+
+// *****************************************************************************
+// *** DelayUntilMs ********************************************************
+// *****************************************************************************
+void RtosTick::DelayUntilMs(uint32_t& last_wake_ticks, uint32_t time_ms)
+{
+ vTaskDelayUntil(&last_wake_ticks, MsToTicks(time_ms));
+}
+
+// *****************************************************************************
+// *** MsToTicks ***********************************************************
+// *****************************************************************************
+uint32_t RtosTick::MsToTicks(uint32_t time_ms)
+{
+ return(time_ms * portTICK_PERIOD_MS);
+}
+
+// *****************************************************************************
+// *** TicksToMs ***********************************************************
+// *****************************************************************************
+uint32_t RtosTick::TicksToMs(uint32_t ticks)
+{
+ return(ticks / portTICK_PERIOD_MS);
+}
+
diff --git a/FreeRtosWrapper/RtosTick.h b/FreeRtosWrapper/RtosTick.h
new file mode 100644
index 0000000..4f9f071
--- /dev/null
+++ b/FreeRtosWrapper/RtosTick.h
@@ -0,0 +1,106 @@
+//******************************************************************************
+// @file RtosTick.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Tick Wrapper Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef RtosTick_h
+#define RtosTick_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+
+// *****************************************************************************
+// *** RtosTick ************************************************************
+// *****************************************************************************
+class RtosTick
+{
+ public:
+ // *************************************************************************
+ // *** GetTickCount ****************************************************
+ // *************************************************************************
+ static uint32_t GetTickCount();
+
+ // *************************************************************************
+ // *** GetTimeMs *******************************************************
+ // *************************************************************************
+ static uint32_t GetTimeMs();
+
+ // *************************************************************************
+ // *** DelayTicks ******************************************************
+ // *************************************************************************
+ static void DelayTicks(uint32_t ticks);
+
+ // *************************************************************************
+ // *** DelayMs *********************************************************
+ // *************************************************************************
+ static void DelayMs(uint32_t time_ms);
+
+ // *************************************************************************
+ // *** DelayUntilTicks *************************************************
+ // *************************************************************************
+ static void DelayUntilTicks(uint32_t& last_wake_ticks, uint32_t ticks);
+
+ // *************************************************************************
+ // *** DelayUntilMs ****************************************************
+ // *************************************************************************
+ static void DelayUntilMs(uint32_t& last_wake_ticks, uint32_t time_ms);
+
+ // *************************************************************************
+ // *** MsToTicks *******************************************************
+ // *************************************************************************
+ static uint32_t MsToTicks(uint32_t time_ms);
+
+ // *************************************************************************
+ // *** TicksToMs *******************************************************
+ // *************************************************************************
+ static uint32_t TicksToMs(uint32_t ticks);
+
+ private:
+ // None
+};
+
+#endif
diff --git a/FreeRtosWrapper/RtosTimer.cpp b/FreeRtosWrapper/RtosTimer.cpp
new file mode 100644
index 0000000..3159787
--- /dev/null
+++ b/FreeRtosWrapper/RtosTimer.cpp
@@ -0,0 +1,269 @@
+//******************************************************************************
+// @file RtosTimer.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Timer Wrapper Class, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "RtosTimer.h"
+#include "Rtos.h"
+
+#include "FreeRTOS.h"
+#include "timers.h"
+
+// *****************************************************************************
+// *** ~FreeRtosSoftwareTimer **********************************************
+// *****************************************************************************
+RtosTimer::~RtosTimer()
+{
+ // If timer was created
+ if(timer != nullptr)
+ {
+ // Clear callback handler
+ callback = nullptr;
+ // Delete timer
+ (void) xTimerDelete(timer, 0U);
+ }
+}
+
+// *****************************************************************************
+// *** Create **************************************************************
+// *****************************************************************************
+Result RtosTimer::Create()
+{
+ Result result = Result::ERR_TIMER_CREATE;
+
+ if(timer == nullptr)
+ {
+ // Create timer
+ timer = xTimerCreate(nullptr, RtosTick::MsToTicks(timer_period_ms), (timer_type == REPEATING), this, CallbackFunction);
+ // Check result
+ if(timer != nullptr)
+ {
+ result = Result::RESULT_OK;
+ }
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** IsActive ************************************************************
+// *****************************************************************************
+bool RtosTimer::IsActive() const
+{
+ bool is_active = false;
+ // Check timer handle
+ if(timer != nullptr)
+ {
+ // Check timer state
+ is_active = (xTimerIsTimerActive(timer) != pdFALSE);
+ }
+ // Return result
+ return is_active;
+}
+
+// *****************************************************************************
+// *** Start ***************************************************************
+// *****************************************************************************
+Result RtosTimer::Start(uint32_t timeout_ms)
+{
+ Result result = Result::ERR_TIMER_START;
+ // Check timer handle
+ if(timer != nullptr)
+ {
+ // Result of operation
+ portBASE_TYPE res = pdFALSE;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ BaseType_t task_woken;
+ // Start timer from ISR
+ res = xTimerStartFromISR(timer, &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // Start timer
+ res = xTimerStart(timer, RtosTick::MsToTicks(timeout_ms));
+ }
+ // Check result
+ if(res == pdPASS)
+ {
+ result = Result::RESULT_OK;
+ }
+ }
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** Stop ****************************************************************
+// *****************************************************************************
+Result RtosTimer::Stop(uint32_t timeout_ms)
+{
+ Result result = Result::ERR_TIMER_STOP;
+ // Check timer handle
+ if(timer != nullptr)
+ {
+ // Result of operation
+ portBASE_TYPE res = pdFALSE;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ BaseType_t task_woken;
+ // Stop timer from ISR
+ res = xTimerStopFromISR(timer, &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // Stop timer
+ res = xTimerStop(timer, RtosTick::MsToTicks(timeout_ms));
+ }
+ // Check result
+ if(res == pdPASS)
+ {
+ result = Result::RESULT_OK;
+ }
+ }
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** UpdatePeriod ********************************************************
+// *****************************************************************************
+Result RtosTimer::UpdatePeriod(uint32_t new_period_ms, uint32_t timeout_ms)
+{
+ Result result = Result::ERR_TIMER_UPDATE;
+ // Check timer handle
+ if(timer != nullptr)
+ {
+ // Get current timer state
+ bool is_active = IsActive();
+ // Start timer with new period
+ result = StartWithNewPeriod(new_period_ms, timeout_ms);
+ // StartWithNewPeriod() starts timer. So, if result is successful and timer
+ // wasn't active, it should be stopped.
+ if(result.IsGood() && (is_active == false))
+ {
+ // Stop timer
+ result = Stop(timeout_ms);
+ }
+ }
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** StartWithNewPeriod **************************************************
+// *****************************************************************************
+Result RtosTimer::StartWithNewPeriod(uint32_t new_period_ms, uint32_t timeout_ms)
+{
+ Result result = Result::ERR_TIMER_UPDATE;
+ // Check timer handle
+ if(timer != nullptr)
+ {
+ // Update period
+ timer_period_ms = new_period_ms;
+ // Result of operation
+ portBASE_TYPE res = pdFALSE;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ BaseType_t task_woken;
+ // Restart timer with new period from ISR
+ res = xTimerChangePeriodFromISR(timer, RtosTick::MsToTicks(new_period_ms), &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // The FreeRTOS xTimerChangePeriod() function start timer
+ res = xTimerChangePeriod(timer, RtosTick::MsToTicks(new_period_ms), RtosTick::MsToTicks(timeout_ms));
+ }
+ // Check result
+ if(res == pdPASS)
+ {
+ result = Result::RESULT_OK;
+ }
+ }
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** Reset ***************************************************************
+// *****************************************************************************
+Result RtosTimer::Reset(uint32_t timeout_ms)
+{
+ Result result = Result::ERR_TIMER_STOP;
+ // Check timer handle
+ if(timer != nullptr)
+ {
+ // Result of operation
+ portBASE_TYPE res = pdFALSE;
+
+ // Check handler mode
+ if(Rtos::IsInHandlerMode())
+ {
+ BaseType_t task_woken;
+ // Reset timer from ISR
+ res = xTimerResetFromISR(timer, &task_woken);
+ // Switch context if needed
+ portEND_SWITCHING_ISR((res == pdPASS) ? task_woken : pdFALSE);
+ }
+ else
+ {
+ // Reset timer
+ res = xTimerReset(timer, RtosTick::MsToTicks(timeout_ms));
+ }
+ // Check result
+ if(res == pdPASS)
+ {
+ result = Result::RESULT_OK;
+ }
+ }
+ // Return result
+ return result;
+}
+
+// *****************************************************************************
+// *** CallbackFunction ****************************************************
+// *****************************************************************************
+void RtosTimer::CallbackFunction(TimerHandle_t timer_handle)
+{
+ // Check timer handle
+ if(timer_handle != nullptr)
+ {
+ // Timer ID set to "this" pointer in Create()
+ RtosTimer* this_ptr = static_cast<RtosTimer*>(pvTimerGetTimerID(timer_handle));
+
+ if((this_ptr != nullptr) && (this_ptr->callback != nullptr))
+ {
+ // Execute callback
+ this_ptr->callback(this_ptr->callback_param);
+ }
+ }
+}
+
+
diff --git a/FreeRtosWrapper/RtosTimer.h b/FreeRtosWrapper/RtosTimer.h
new file mode 100644
index 0000000..bd3ba51
--- /dev/null
+++ b/FreeRtosWrapper/RtosTimer.h
@@ -0,0 +1,144 @@
+//******************************************************************************
+// @file RtosTimer.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: FreeRTOS Timer Wrapper Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef RtosTimer_h
+#define RtosTimer_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "Rtos.h"
+#include "timers.h"
+
+// *****************************************************************************
+// *** RtosTimer ***********************************************************
+// *****************************************************************************
+class RtosTimer
+{
+ public:
+ // Definition of callback function
+ typedef void (Callback)(void* ptr);
+
+ // Types of timer
+ enum TimerType
+ {
+ REPEATING,
+ ONE_SHOT
+ };
+
+ // *************************************************************************
+ // *** RtosTimer *******************************************************
+ // *************************************************************************
+ RtosTimer(uint32_t period_ms, TimerType type, Callback& clbk, void* clbk_param) :
+ timer_period_ms(period_ms), timer_type(type),
+ callback(&clbk), callback_param(clbk_param) {};
+
+ // *************************************************************************
+ // *** ~RtosTimer ******************************************************
+ // *************************************************************************
+ ~RtosTimer();
+
+ // *************************************************************************
+ // *** Create **********************************************************
+ // *************************************************************************
+ Result Create();
+
+ // *************************************************************************
+ // *** IsActive ********************************************************
+ // *************************************************************************
+ bool IsActive() const;
+
+ // *************************************************************************
+ // *** Start ***********************************************************
+ // *************************************************************************
+ Result Start(uint32_t timeout_ms = 0);
+
+ // *************************************************************************
+ // *** Stop ************************************************************
+ // *************************************************************************
+ Result Stop(uint32_t timeout_ms = 0);
+
+ // *************************************************************************
+ // *** SetNewPeriod ****************************************************
+ // *************************************************************************
+ Result UpdatePeriod(uint32_t new_period_ms, uint32_t timeout_ms = 0);
+
+ // *************************************************************************
+ // *** StartWithNewPeriod **********************************************
+ // *************************************************************************
+ Result StartWithNewPeriod(uint32_t new_period_ms, uint32_t timeout_ms = 0);
+
+ // *************************************************************************
+ // *** Reset ***********************************************************
+ // *************************************************************************
+ Result Reset(uint32_t timeout_ms = 0);
+
+ // *************************************************************************
+ // *** GetTimerPeriod **************************************************
+ // *************************************************************************
+ inline uint32_t GetTimerPeriod(void) const {return timer_period_ms;}
+
+ private:
+ // Timer handle
+ TimerHandle_t timer = nullptr;
+
+ // Timer period in ms
+ uint32_t timer_period_ms;
+ // Timer type
+ TimerType timer_type;
+
+ // Pointer to the callback function
+ Callback* callback;
+ // Pointer to the callback data
+ void* callback_param = nullptr;
+
+ // Timer callback wrapper function
+ static void CallbackFunction(TimerHandle_t timer_handle);
+};
+
+#endif
diff --git a/Interfaces/IIic.h b/Interfaces/IIic.h
new file mode 100644
index 0000000..5e35ee1
--- /dev/null
+++ b/Interfaces/IIic.h
@@ -0,0 +1,156 @@
+//******************************************************************************
+// @file IIic.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: I2C driver interface, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef IIic_h
+#define IIic_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+
+// *****************************************************************************
+// *** I2C Driver Interface ************************************************
+// *****************************************************************************
+class IIic
+{
+ public:
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ explicit IIic() {};
+
+ // *************************************************************************
+ // *** Public: Destructor **********************************************
+ // *************************************************************************
+ virtual ~IIic() {};
+
+ // *************************************************************************
+ // *** Public: Init ****************************************************
+ // *************************************************************************
+ virtual Result Init() = 0;
+
+ // *************************************************************************
+ // *** Public: DeInit **************************************************
+ // *************************************************************************
+ virtual Result DeInit() {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Enable **************************************************
+ // *************************************************************************
+ virtual Result Enable() {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Disable *************************************************
+ // *************************************************************************
+ virtual Result Disable() {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Reset ***************************************************
+ // *************************************************************************
+ virtual Result Reset() {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: IsDeviceReady *******************************************
+ // *************************************************************************
+ virtual Result IsDeviceReady(uint16_t addr, uint8_t retries = 1U) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Transfer ************************************************
+ // *************************************************************************
+ virtual Result Transfer(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size, uint8_t* rx_buf_ptr, uint32_t rx_size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Write ***************************************************
+ // *************************************************************************
+ virtual Result Write(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Read ****************************************************
+ // *************************************************************************
+ virtual Result Read(uint16_t addr, uint8_t* rx_buf_ptr, uint32_t rx_size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: WriteAsync **********************************************
+ // *************************************************************************
+ virtual Result WriteAsync(uint16_t addr, uint8_t* tx_buf_ptr, uint32_t tx_size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: ReadAsync ***********************************************
+ // *************************************************************************
+ virtual Result ReadAsync(uint16_t addr, uint8_t* rx_buf_ptr, uint32_t rx_size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: IsBusy **************************************************
+ // *************************************************************************
+ virtual bool IsBusy(void) {return false;}
+
+ // *************************************************************************
+ // *** Public: SetTxTimeout ********************************************
+ // *************************************************************************
+ virtual void SetTxTimeout(uint16_t timeout_ms) {i2c_tx_timeout_ms = timeout_ms;}
+
+ // *************************************************************************
+ // *** Public: SetRxTimeout ********************************************
+ // *************************************************************************
+ virtual void SetRxTimeout(uint16_t timeout_ms) {i2c_rx_timeout_ms = timeout_ms;}
+
+ protected:
+ // Timeout for I2C TX operation
+ uint16_t i2c_tx_timeout_ms = 5U;
+
+ // Timeout for I2C RX operation
+ uint16_t i2c_rx_timeout_ms = 5U;
+
+ private:
+ // *************************************************************************
+ // *** Private: Constructors and assign operator - prevent copying *****
+ // *************************************************************************
+ IIic(const IIic&);
+};
+
+#endif
diff --git a/Interfaces/ISpi.h b/Interfaces/ISpi.h
new file mode 100644
index 0000000..1803354
--- /dev/null
+++ b/Interfaces/ISpi.h
@@ -0,0 +1,156 @@
+//******************************************************************************
+// @file ISpi.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: SPI driver interface, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef ISpi_h
+#define ISpi_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+
+// *****************************************************************************
+// *** SPI Driver Interface ************************************************
+// *****************************************************************************
+class ISpi
+{
+ public:
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ explicit ISpi() {};
+
+ // *************************************************************************
+ // *** Public: Destructor **********************************************
+ // *************************************************************************
+ virtual ~ISpi() {};
+
+ // *************************************************************************
+ // *** Public: Init ****************************************************
+ // *************************************************************************
+ virtual Result Init() = 0;
+
+ // *************************************************************************
+ // *** Public: DeInit **************************************************
+ // *************************************************************************
+ virtual Result DeInit() {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Transfer ************************************************
+ // *************************************************************************
+ virtual Result Transfer(uint8_t* rx_buf_ptr, uint8_t* tx_buf_ptr, uint32_t size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Write ***************************************************
+ // *************************************************************************
+ virtual Result Write(uint8_t* tx_buf_ptr, uint32_t tx_size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Read ****************************************************
+ // *************************************************************************
+ virtual Result Read(uint8_t* rx_buf_ptr, uint32_t rx_size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: TransferAsync *******************************************
+ // *************************************************************************
+ virtual Result TransferAsync(uint8_t* rx_buf_ptr, uint8_t* tx_buf_ptr, uint32_t size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: WriteAsync **********************************************
+ // *************************************************************************
+ virtual Result WriteAsync(uint8_t* tx_buf_ptr, uint32_t tx_size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: ReadAsync ***********************************************
+ // *************************************************************************
+ virtual Result ReadAsync(uint8_t* rx_buf_ptr, uint32_t rx_size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Check SPI transfer status *******************************
+ // *************************************************************************
+ virtual bool IsTransferComplete(void) {return true;}
+
+ // *************************************************************************
+ // *** Public: Abort ***************************************************
+ // *************************************************************************
+ virtual Result Abort(void) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: SetSpeed ************************************************
+ // *************************************************************************
+ virtual Result SetSpeed(uint32_t clock_rate) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: GetSpeed ************************************************
+ // *************************************************************************
+ virtual Result GetSpeed(uint32_t& clock_rate) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: SetTxTimeout ********************************************
+ // *************************************************************************
+ virtual void SetTxTimeout(uint16_t timeout_ms) {spi_tx_timeout_ms = timeout_ms;}
+
+ // *************************************************************************
+ // *** Public: SetRxTimeout ********************************************
+ // *************************************************************************
+ virtual void SetRxTimeout(uint16_t timeout_ms) {spi_rx_timeout_ms = timeout_ms;}
+
+ protected:
+ // Timeout for SPI TX operation
+ uint16_t spi_tx_timeout_ms = 100U;
+
+ // Timeout for SPI RX operation
+ uint16_t spi_rx_timeout_ms = 100U;
+
+ private:
+ // *************************************************************************
+ // *** Private: Constructors and assign operator - prevent copying *****
+ // *************************************************************************
+ ISpi(const ISpi&);
+};
+
+#endif
diff --git a/Interfaces/IUart.h b/Interfaces/IUart.h
new file mode 100644
index 0000000..83fa3b1
--- /dev/null
+++ b/Interfaces/IUart.h
@@ -0,0 +1,104 @@
+//******************************************************************************
+// @file IUart.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UART driver interface, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef IUart_h
+#define IUart_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+
+// *****************************************************************************
+// *** UART Driver Interface ***********************************************
+// *****************************************************************************
+class IUart
+{
+ public:
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ explicit IUart() {};
+
+ // *************************************************************************
+ // *** Public: Destructor **********************************************
+ // *************************************************************************
+ virtual ~IUart() {};
+
+ // *************************************************************************
+ // *** Public: Init ****************************************************
+ // *************************************************************************
+ virtual Result Init() = 0;
+
+ // *************************************************************************
+ // *** Public: DeInit **************************************************
+ // *************************************************************************
+ virtual Result DeInit() {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Read ****************************************************
+ // *************************************************************************
+ virtual Result Read(uint8_t* rx_buf_ptr, uint32_t& size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Write ***************************************************
+ // *************************************************************************
+ virtual Result Write(uint8_t* tx_buf_ptr, uint32_t size) {return Result::ERR_NOT_IMPLEMENTED;}
+
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ virtual bool IsTxComplete(void) {return true;}
+
+ private:
+ // *************************************************************************
+ // *** Private: Constructors and assign operator - prevent copying *****
+ // *************************************************************************
+ IUart(const IUart&);
+};
+
+#endif
diff --git a/Libraries/BoschBME280.cpp b/Libraries/BoschBME280.cpp
new file mode 100644
index 0000000..27029ed
--- /dev/null
+++ b/Libraries/BoschBME280.cpp
@@ -0,0 +1,402 @@
+//******************************************************************************
+// @file BoschBME280.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Bosch BME280 library, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "BoschBME280.h"
+
+// *****************************************************************************
+// *** Initialize **********************************************************
+// *****************************************************************************
+Result BoschBME280::Initialize()
+{
+ Result result = Result::RESULT_OK;
+
+ result = iic.Enable();
+
+ if(result.IsGood())
+ {
+ // Read Chip ID
+ result = Read8(BME280_REGISTER_CHIPID, sensor_id);
+ // Check if Chip ID is correct
+ if(result.IsGood() && (sensor_id != 0x60))
+ {
+ result = Result::ERR_I2C_GENERAL;
+ }
+ }
+
+ if(result.IsGood())
+ {
+ // Reset the device
+ Write8(BME280_REGISTER_SOFTRESET, 0xB6);
+ }
+
+ if(result.IsGood())
+ {
+ // Wait for chip to wake up
+ RtosTick::DelayMs(5U);
+ }
+
+ if(result.IsGood())
+ {
+ // If chip is still reading calibration
+ while((result = IsReadingCalibration()) == Result::ERR_BUSY)
+ {
+ // Wait for chip to wake up
+ RtosTick::DelayMs(1U);
+ }
+ }
+
+ if(result.IsGood())
+ {
+ // Read trimming parameters, see DS 4.2.2
+ result = ReadCoefficients();
+ }
+
+ if(result.IsGood())
+ {
+ // Set default sampling values
+ result = SetSampling();
+ }
+
+ if(result.IsGood())
+ {
+ RtosTick::DelayMs(100U);
+ }
+
+ return result;
+}
+
+// ******************************************************************************
+// *** SetSampling **********************************************************
+// ******************************************************************************
+Result BoschBME280::SetSampling(SensorModeType mode,
+ SensorSamplingType temperature_sampling,
+ SensorSamplingType pressurre_sampling,
+ SensorSamplingType humidity_sampling,
+ SensorFilterType filter,
+ StandbyDurationType duration)
+{
+ Result result = Result::RESULT_OK;
+
+ config_reg.spi3w_en = 0U;
+ config_reg.reserved = 0U;
+ config_reg.filter = filter;
+ config_reg.t_sb = duration;
+ result |= Write8(BME280_REGISTER_CONFIG, reinterpret_cast<uint8_t const&>(config_reg));
+
+ // REGISTER_CONTROL should be set after setting the CONTROLHUMID register,
+ // otherwise the values will not be applied (see datasheet 5.4.3)
+ ctrl_hum_reg.reserved = 0U;
+ ctrl_hum_reg.osrs_h = humidity_sampling;
+ result = Write8(BME280_REGISTER_CONTROLHUMID, reinterpret_cast<uint8_t const&>(ctrl_hum_reg));
+
+ ctrl_meas_reg.mode = mode;
+ ctrl_meas_reg.osrs_t = temperature_sampling;
+ ctrl_meas_reg.osrs_p = pressurre_sampling;
+ result |= Write8(BME280_REGISTER_CONTROL, reinterpret_cast<uint8_t const&>(ctrl_meas_reg));
+
+ return result;
+}
+
+// ******************************************************************************
+// *** TakeMeasurement ******************************************************
+// ******************************************************************************
+Result BoschBME280::TakeMeasurement()
+{
+ Result result = Result::RESULT_OK;
+
+ if(ctrl_meas_reg.mode == MODE_FORCED)
+ {
+ // set to forced mode, i.e. "take next measurement"
+ Write8(BME280_REGISTER_CONTROL, reinterpret_cast<uint8_t const&>(ctrl_meas_reg));
+ // Variable
+ uint8_t status = 0U;
+ // Read status
+ result = Read8(BME280_REGISTER_STATUS, status);
+ // Wait until measurement has been completed
+ while(result.IsGood() && (status & 0x08))
+ {
+ RtosTick::DelayMs(1U);
+ // Read status
+ result = Read8(BME280_REGISTER_STATUS, status);
+ }
+ }
+
+ // Read RAW values
+ if(result.IsGood())
+ {
+ uint8_t addr = BME280_REGISTER_PRESSUREDATA;
+ // Local variable for read data(24 bit + 24 bit + 16 bit)
+ uint8_t array[3U+3U+2U] = {0U};
+ // Read all registers at once
+ result = iic.Transfer(i2c_addr, &addr, sizeof(addr), array, sizeof(array));
+ // Create RAW ADC data
+ if(result.IsGood())
+ {
+ // Pressure
+ adc_pressure = 0;
+ result = ReverseArray((uint8_t*)&adc_pressure, &array[0U], 3U);
+ adc_pressure >>= 4;
+ // Temperature
+ adc_temperature = 0;
+ result |= ReverseArray((uint8_t*)&adc_temperature, &array[3U], 3U);
+ adc_temperature >>= 4;
+ // Humidity
+ adc_humidity = 0;
+ result |= ReverseArray((uint8_t*)&adc_humidity, &array[3U+3U], 2U);
+ // Ñalculating t_fine for calculation Pressure & Humidity
+ (void) GetTemperature_x100();
+ }
+ }
+
+ return result;
+}
+
+// ******************************************************************************
+// *** GetTemperature_x100 **************************************************
+// ******************************************************************************
+int32_t BoschBME280::GetTemperature_x100(void)
+{
+ int32_t temp_x100 = 0;
+ int32_t var1, var2;
+
+ int32_t adc = adc_temperature;
+
+ if (adc != 0x800000)
+ {
+ var1 = (((adc >> 3) - ((int32_t)bme280_calibration.dig_t1 << 1)) * ((int32_t)bme280_calibration.dig_t2)) >> 11;
+
+ var2 = (((((adc >> 4) - ((int32_t)bme280_calibration.dig_t1)) * ((adc >> 4) - ((int32_t)bme280_calibration.dig_t1))) >> 12) * ((int32_t)bme280_calibration.dig_t3)) >> 14;
+
+ t_fine = var1 + var2;
+
+ temp_x100 = (t_fine * 5 + 128) >> 8;
+ }
+
+ return temp_x100;
+}
+
+// ******************************************************************************
+// *** GetPressure_x256 *****************************************************
+// ******************************************************************************
+int32_t BoschBME280::GetPressure_x256(void)
+{
+ int64_t var1, var2, press_x256 = 0;
+
+ int32_t adc = adc_pressure;
+ if(adc != 0x800000)
+ {
+ var1 = ((int64_t)t_fine) - 128000;
+ var2 = var1 * var1 * (int64_t)bme280_calibration.dig_p6;
+ var2 = var2 + ((var1 * (int64_t)bme280_calibration.dig_p5) << 17);
+ var2 = var2 + (((int64_t)bme280_calibration.dig_p4) << 35);
+ var1 = ((var1 * var1 * (int64_t)bme280_calibration.dig_p3) >> 8) + ((var1 * (int64_t)bme280_calibration.dig_p2) << 12);
+ var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)bme280_calibration.dig_p1) >> 33;
+
+ if (var1 == 0)
+ {
+ press_x256 = 0; // Avoid exception caused by division by zero
+ }
+ else
+ {
+ press_x256 = 1048576 - adc;
+ press_x256 = (((press_x256 << 31) - var2) * 3125) / var1;
+ var1 = (((int64_t)bme280_calibration.dig_p9) * (press_x256 >> 13) * (press_x256 >> 13)) >> 25;
+ var2 = (((int64_t)bme280_calibration.dig_p8) * press_x256) >> 19;
+ // Result
+ press_x256 = ((press_x256 + var1 + var2) >> 8) + (((int64_t)bme280_calibration.dig_p7) << 4);
+ }
+ }
+
+ return (int32_t)press_x256;
+}
+
+// ******************************************************************************
+// *** GetHumidity_x1024 ****************************************************
+// ******************************************************************************
+int32_t BoschBME280::GetHumidity_x1024(void)
+{
+ int32_t adc = adc_humidity;
+ int32_t v_x1_u32r = 0;
+
+ // value in case humidity measurement was disabled
+ if(adc != 0x8000)
+ {
+ v_x1_u32r = (t_fine - ((int32_t)76800));
+
+ v_x1_u32r = (((((adc << 14) - (((int32_t)bme280_calibration.dig_h4) << 20) -
+ (((int32_t)bme280_calibration.dig_h5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) *
+ (((((((v_x1_u32r * ((int32_t)bme280_calibration.dig_h6)) >> 10) *
+ (((v_x1_u32r * ((int32_t)bme280_calibration.dig_h3)) >> 11) + ((int32_t)32768))) >> 10) +
+ ((int32_t)2097152)) * ((int32_t)bme280_calibration.dig_h2) + 8192) >> 14));
+
+ v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t)bme280_calibration.dig_h1)) >> 4));
+
+ v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r;
+ v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r;
+ }
+
+ return (v_x1_u32r >> 12);
+}
+
+// ******************************************************************************
+// *** ReadCoefficients *****************************************************
+// ******************************************************************************
+Result BoschBME280::ReadCoefficients(void)
+{
+ Result result = Result::RESULT_OK;
+
+ result |= Read16(BME280_REGISTER_DIG_T1, bme280_calibration.dig_t1);
+ result |= Read16(BME280_REGISTER_DIG_T2, bme280_calibration.dig_t2);
+ result |= Read16(BME280_REGISTER_DIG_T3, bme280_calibration.dig_t3);
+
+ result |= Read16(BME280_REGISTER_DIG_P1, bme280_calibration.dig_p1);
+ result |= Read16(BME280_REGISTER_DIG_P2, bme280_calibration.dig_p2);
+ result |= Read16(BME280_REGISTER_DIG_P3, bme280_calibration.dig_p3);
+ result |= Read16(BME280_REGISTER_DIG_P4, bme280_calibration.dig_p4);
+ result |= Read16(BME280_REGISTER_DIG_P5, bme280_calibration.dig_p5);
+ result |= Read16(BME280_REGISTER_DIG_P6, bme280_calibration.dig_p6);
+ result |= Read16(BME280_REGISTER_DIG_P7, bme280_calibration.dig_p7);
+ result |= Read16(BME280_REGISTER_DIG_P8, bme280_calibration.dig_p8);
+ result |= Read16(BME280_REGISTER_DIG_P9, bme280_calibration.dig_p9);
+
+ result |= Read8(BME280_REGISTER_DIG_H1, bme280_calibration.dig_h1);
+ result |= Read16(BME280_REGISTER_DIG_H2, bme280_calibration.dig_h2);
+ result |= Read8(BME280_REGISTER_DIG_H3, bme280_calibration.dig_h3);
+
+ // Variables for store values
+ uint8_t dig_h4;
+ uint8_t dig_h45;
+ uint8_t dig_h5;
+ // Read values
+ result |= Read8(BME280_REGISTER_DIG_H4, dig_h4);
+ result |= Read8(BME280_REGISTER_DIG_H45, dig_h45);
+ result |= Read8(BME280_REGISTER_DIG_H5, dig_h5);
+ // Make digit from values
+ bme280_calibration.dig_h4 = (dig_h4 << 4) | (dig_h45 & 0xF);
+ bme280_calibration.dig_h5 = (dig_h5 << 4) | (dig_h45 >> 4);
+
+ result |= Read8(BME280_REGISTER_DIG_H6, bme280_calibration.dig_h6);
+
+ return result;
+}
+
+// ******************************************************************************
+// *** Check is chip still reading calibration data *************************
+// ******************************************************************************
+Result BoschBME280::IsReadingCalibration(void)
+{
+ Result result = Result::RESULT_OK;
+
+ uint8_t status = 0U;
+ // Read status
+ result = Read8(BME280_REGISTER_STATUS, status);
+ // Check result
+ if(result.IsGood())
+ {
+ if((status & 1U) != 0U)
+ {
+ result = Result::ERR_BUSY;
+ }
+ }
+
+ return result;
+}
+
+// ******************************************************************************
+// *** Read register value(8-bit unsigned) **********************************
+// ******************************************************************************
+Result BoschBME280::Read8(uint8_t reg, uint8_t& value)
+{
+ return iic.Transfer(i2c_addr, &reg, sizeof(reg), &value, sizeof(value));
+}
+
+// ******************************************************************************
+// *** Read register value(8-bit signed) ************************************
+// ******************************************************************************
+Result BoschBME280::Read8(uint8_t reg, int8_t& value)
+{
+ return iic.Transfer(i2c_addr, &reg, sizeof(reg), (uint8_t*)&value, sizeof(value));
+}
+
+// ******************************************************************************
+// *** Write register value(8-bit) ******************************************
+// ******************************************************************************
+Result BoschBME280::Write8(uint8_t reg, uint8_t value)
+{
+ uint8_t buf[2];
+ buf[0] = reg;
+ buf[1] = value;
+ return iic.Write(i2c_addr, buf, sizeof(buf));
+}
+
+// ******************************************************************************
+// *** Read register value(16-bit unsigned) *********************************
+// ******************************************************************************
+Result BoschBME280::Read16(uint8_t reg, uint16_t& value, bool reverse)
+{
+ Result result = Result::RESULT_OK;
+
+ // Read data
+ result = iic.Transfer(i2c_addr, &reg, sizeof(reg), (uint8_t*)&value, sizeof(value));
+ // Change endian if needed
+ if(reverse)
+ {
+ value = (value >> 8) | (value << 8);
+ }
+
+ return result;
+}
+
+// ******************************************************************************
+// *** Read register value(16-bit signed) ***********************************
+// ******************************************************************************
+Result BoschBME280::Read16(uint8_t reg, int16_t& value, bool reverse)
+{
+ Result result = Result::RESULT_OK;
+
+ // Read data
+ result = iic.Transfer(i2c_addr, &reg, sizeof(reg), (uint8_t*)&value, sizeof(value));
+ // Change endian if needed
+ if(reverse)
+ {
+ value = (value >> 8) | (value << 8);
+ }
+
+ return result;
+}
+
+// ******************************************************************************
+// *** Reverse byte order in array ******************************************
+// ******************************************************************************
+Result BoschBME280::ReverseArray(uint8_t* dst, uint8_t* src, uint32_t size)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ if((dst != nullptr) && (src != nullptr))
+ {
+ for(uint32_t i = 0U; i < size; i++)
+ {
+ dst[i] = src[size - i - 1U];
+ }
+ result = Result::RESULT_OK;
+ }
+
+ return result;
+}
diff --git a/Libraries/BoschBME280.h b/Libraries/BoschBME280.h
new file mode 100644
index 0000000..fe38c35
--- /dev/null
+++ b/Libraries/BoschBME280.h
@@ -0,0 +1,306 @@
+//******************************************************************************
+// @file DevCfg.h
+// @author Nicolai Shlapunov
+//
+// @details Bosch BMPE280: Library, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef BoschBME280_h
+#define BoschBME280_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "IIic.h"
+
+// *****************************************************************************
+// *** Bosch BME280 library *************************************************
+// *****************************************************************************
+class BoschBME280
+{
+ public:
+ // *************************************************************************
+ // *** Sampling rates **************************************************
+ // *************************************************************************
+ enum SensorSamplingType
+ {
+ SAMPLING_NONE = 0x00, // 000 = skipped
+ SAMPLING_X1, // 001 = x1
+ SAMPLING_X2, // 010 = x2
+ SAMPLING_X4, // 011 = x4
+ SAMPLING_X8, // 100 = x8
+ SAMPLING_X16 // 101 and above = x16
+ };
+
+ // *************************************************************************
+ // *** Power modes *****************************************************
+ // *************************************************************************
+ enum SensorModeType
+ {
+ MODE_SLEEP = 0x00, // 00 = sleep
+ MODE_FORCED = 0x01, // 01 or 10 = forced
+ MODE_NORMAL = 0x11 // 11 = normal
+ };
+
+ // *************************************************************************
+ // *** Filter values ***************************************************
+ // *************************************************************************
+ enum SensorFilterType
+ {
+ FILTER_OFF = 0x00, // 000 = filter off
+ FILTER_X2, // 001 = x2 filter
+ FILTER_X4, // 010 = x4 filter
+ FILTER_X8, // 011 = x8 filter
+ FILTER_X16, // 100 and above = 16x filter
+ };
+
+ // *************************************************************************
+ // *** Standby duration ************************************************
+ // *************************************************************************
+ enum StandbyDurationType
+ {
+ STANDBY_MS_0_5 = 0x00, // 000 = 0.5 ms
+ STANDBY_MS_10 = 0x06, // 110 = 10 ms
+ STANDBY_MS_20 = 0x07, // 111 = 20 ms
+ STANDBY_MS_62_5 = 0x01, // 001 = 62.5 ms
+ STANDBY_MS_125 = 0x02, // 010 = 125 ms
+ STANDBY_MS_250 = 0x03, // 100 = 500 ms
+ STANDBY_MS_500 = 0x04, // 101 = 1000 ms
+ STANDBY_MS_1000 = 0x05 // 011 = 250 ms
+ };
+
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ BoschBME280(IIic& iic_ref) : iic(iic_ref) {};
+
+ // *************************************************************************
+ // *** Initialize ******************************************************
+ // *************************************************************************
+ Result Initialize();
+
+ // *************************************************************************
+ // *** SetSampling *****************************************************
+ // *************************************************************************
+ Result SetSampling(SensorModeType mode = MODE_NORMAL,
+ SensorSamplingType temperature_sampling = SAMPLING_X16,
+ SensorSamplingType pressure_sampling = SAMPLING_X16,
+ SensorSamplingType humidity_sampling = SAMPLING_X16,
+ SensorFilterType filter = FILTER_OFF,
+ StandbyDurationType duration = STANDBY_MS_0_5);
+
+ // *************************************************************************
+ // *** TakeMeasurement *************************************************
+ // *************************************************************************
+ Result TakeMeasurement();
+
+ // *************************************************************************
+ // *** GetTemperature_x100 *********************************************
+ // *************************************************************************
+ int32_t GetTemperature_x100(void);
+
+ // *************************************************************************
+ // *** GetPressure_x256 ************************************************
+ // *************************************************************************
+ int32_t GetPressure_x256(void);
+
+ // *************************************************************************
+ // *** GetHumidity_x1024 ***********************************************
+ // *************************************************************************
+ int32_t GetHumidity_x1024(void);
+
+ private:
+
+ // *** default I2C address **********************************************
+ const uint8_t BME280_ADDRESS = 0x76;
+
+ // *** Register addresses *********************************************
+ enum Registers
+ {
+ BME280_REGISTER_DIG_T1 = 0x88,
+ BME280_REGISTER_DIG_T2 = 0x8A,
+ BME280_REGISTER_DIG_T3 = 0x8C,
+
+ BME280_REGISTER_DIG_P1 = 0x8E,
+ BME280_REGISTER_DIG_P2 = 0x90,
+ BME280_REGISTER_DIG_P3 = 0x92,
+ BME280_REGISTER_DIG_P4 = 0x94,
+ BME280_REGISTER_DIG_P5 = 0x96,
+ BME280_REGISTER_DIG_P6 = 0x98,
+ BME280_REGISTER_DIG_P7 = 0x9A,
+ BME280_REGISTER_DIG_P8 = 0x9C,
+ BME280_REGISTER_DIG_P9 = 0x9E,
+
+ BME280_REGISTER_DIG_H1 = 0xA1,
+ BME280_REGISTER_DIG_H2 = 0xE1,
+ BME280_REGISTER_DIG_H3 = 0xE3,
+ BME280_REGISTER_DIG_H4 = 0xE4,
+ BME280_REGISTER_DIG_H45 = 0xE5,
+ BME280_REGISTER_DIG_H5 = 0xE6,
+ BME280_REGISTER_DIG_H6 = 0xE7,
+
+ BME280_REGISTER_CHIPID = 0xD0,
+ BME280_REGISTER_SOFTRESET = 0xE0,
+
+ BME280_REGISTER_CONTROLHUMID = 0xF2,
+ BME280_REGISTER_STATUS = 0XF3,
+ BME280_REGISTER_CONTROL = 0xF4,
+ BME280_REGISTER_CONFIG = 0xF5,
+ BME280_REGISTER_PRESSUREDATA = 0xF7,
+ BME280_REGISTER_TEMPDATA = 0xFA,
+ BME280_REGISTER_HUMIDDATA = 0xFD
+ };
+
+ // Reference to I2C interface
+ IIic& iic;
+ // I2C address
+ uint8_t i2c_addr = BME280_ADDRESS;
+ // Sensor ID
+ uint8_t sensor_id = 0;
+
+ // Some data for calculate pressure & humidity
+ int32_t t_fine = 0;
+ // Variables for store raw values
+ int32_t adc_temperature = 0;
+ int32_t adc_pressure = 0;
+ uint16_t adc_humidity = 0;
+
+ // *** Calibration data structure **************************************
+ struct CalibrationData
+ {
+ // Temperature compensation values
+ uint16_t dig_t1;
+ int16_t dig_t2;
+ int16_t dig_t3;
+
+ // Pressure compensation values
+ uint16_t dig_p1;
+ int16_t dig_p2;
+ int16_t dig_p3;
+ int16_t dig_p4;
+ int16_t dig_p5;
+ int16_t dig_p6;
+ int16_t dig_p7;
+ int16_t dig_p8;
+ int16_t dig_p9;
+
+ // Humidity compensation values
+ uint8_t dig_h1;
+ int16_t dig_h2;
+ uint8_t dig_h3;
+ int16_t dig_h4;
+ int16_t dig_h5;
+ int8_t dig_h6;
+ };
+ CalibrationData bme280_calibration;
+
+ // *** Configuration register structure *********************************
+ struct Config
+ {
+ uint8_t spi3w_en : 1;
+ uint8_t reserved : 1;
+ uint8_t filter : 3; // Filter settings
+ uint8_t t_sb : 3; // Inactive duration (StandBy time) in normal mode
+ };
+ Config config_reg;
+
+ // *** Measurement control register *************************************
+ struct CtrlMeas
+ {
+ uint8_t mode : 2; // Device mode
+ uint8_t osrs_p : 3; // Pressure oversampling
+ uint8_t osrs_t : 3; // Temperature oversampling
+ };
+ CtrlMeas ctrl_meas_reg;
+
+ // *** Humidity control register structure *****************************
+ struct CtrlHum
+ {
+ uint8_t osrs_h : 3;
+ uint8_t reserved : 5;
+ };
+ CtrlHum ctrl_hum_reg;
+
+ // *************************************************************************
+ // *** Read Coefficients ***********************************************
+ // *************************************************************************
+ Result ReadCoefficients(void);
+
+ // *************************************************************************
+ // *** Check is chip still reading calibration data ********************
+ // *************************************************************************
+ Result IsReadingCalibration(void);
+
+ // *************************************************************************
+ // *** Write register value(8-bit) *************************************
+ // *************************************************************************
+ Result Write8(uint8_t reg, uint8_t value);
+
+ // *************************************************************************
+ // *** Read register value(8-bit unsigned) *****************************
+ // *************************************************************************
+ Result Read8(uint8_t reg, uint8_t& value);
+
+ // *************************************************************************
+ // *** Read register value(8-bit signed) *******************************
+ // *************************************************************************
+ Result Read8(uint8_t reg, int8_t& value);
+
+ // *************************************************************************
+ // *** Read register value(16-bit unsigned) ****************************
+ // *************************************************************************
+ Result Read16(uint8_t reg, uint16_t& value, bool reverse = false);
+
+ // *************************************************************************
+ // *** Read register value(16-bit signed) ******************************
+ // *************************************************************************
+ Result Read16(uint8_t reg, int16_t& value, bool reverse = false);
+
+ // *************************************************************************
+ // *** Reverse byte order in array *************************************
+ // *************************************************************************
+ Result ReverseArray(uint8_t* dst, uint8_t* src, uint32_t size);
+};
+
+#endif
diff --git a/Libraries/Eeprom24.cpp b/Libraries/Eeprom24.cpp
new file mode 100644
index 0000000..0ed374f
--- /dev/null
+++ b/Libraries/Eeprom24.cpp
@@ -0,0 +1,114 @@
+//******************************************************************************
+// @file Eeprom24.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: EEPROM 24C*** driver, implementation
+//
+// @copyright Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "Eeprom24.h"
+
+// *****************************************************************************
+// *** Public: Init ********************************************************
+// *****************************************************************************
+Result Eeprom24::Init()
+{
+ Result result = Result::RESULT_OK;
+ iic.SetTxTimeout(10U);
+ iic.SetRxTimeout(100U);
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Read ********************************************************
+// *****************************************************************************
+Result Eeprom24::Read(uint16_t addr, uint8_t* rx_buf_ptr, uint16_t size)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ // Check input parameters
+ if(rx_buf_ptr != nullptr)
+ {
+ // Transfer: write two bytes address then read data
+ result = iic.Transfer(I2C_ADDR, (uint8_t*)&addr, sizeof(addr), rx_buf_ptr, size);
+ }
+
+ return result;
+}
+
+// *****************************************************************************
+// *** Public: Write *******************************************************
+// *****************************************************************************
+Result Eeprom24::Write(uint16_t addr, uint8_t* tx_buf_ptr, uint16_t size)
+{
+ Result result = Result::ERR_NULL_PTR;
+
+ // Check input parameters
+ if(tx_buf_ptr != nullptr)
+ {
+ // Clear result to enter in to cycle
+ result = Result::RESULT_OK;
+ // Allocate buffer for address + data
+ uint8_t buf[2U + PAGE_SIZE_BYTES];
+ // Cycle for write pages
+ while(size && result.IsGood())
+ {
+ // Get data size
+ uint8_t data_size = size < PAGE_SIZE_BYTES ? size : PAGE_SIZE_BYTES;
+ // For the first page
+ if((addr % PAGE_SIZE_BYTES) != 0U)
+ {
+ // Calculate data size from start address to the end of current page
+ data_size = PAGE_SIZE_BYTES - (addr % PAGE_SIZE_BYTES);
+ // If size less than remaining page bytes - use size
+ data_size = size < data_size ? size : data_size;
+ }
+ // Decrease number of remaining bytes
+ size -= data_size;
+ // Store address
+ *((uint16_t*)buf) = addr;
+ // Copy data
+ memcpy(buf + 2U, tx_buf_ptr, data_size);
+ // Transfer
+ result = iic.Write(I2C_ADDR, buf, 2U + data_size);
+
+ // Wait until writing finished
+ if(result.IsGood())
+ {
+ // Check device response
+ result = iic.IsDeviceReady(I2C_ADDR);
+ // Clear repetition counter for tracking timeout
+ repetition_cnt = 0U;
+ // Wait until write operation finished
+ while(result.IsBad())
+ {
+ // Delay 1 ms for start writing
+ RtosTick::DelayMs(1U);
+ // Check is device ready
+ result = iic.IsDeviceReady(I2C_ADDR);
+ // Check timeout
+ if(repetition_cnt > WRITING_TIMEOUT_MS)
+ {
+ result = Result::ERR_I2C_TIMEOUT;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
diff --git a/Libraries/Eeprom24.h b/Libraries/Eeprom24.h
new file mode 100644
index 0000000..ff39150
--- /dev/null
+++ b/Libraries/Eeprom24.h
@@ -0,0 +1,107 @@
+//******************************************************************************
+// @file Eeprom24.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: EEPROM 24C*** driver, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2018, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef Eeprom24_h
+#define Eeprom24_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "IIic.h"
+
+// *****************************************************************************
+// *** EEPROM 24C*** Driver Class ******************************************
+// *****************************************************************************
+class Eeprom24
+{
+ public:
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ explicit Eeprom24(IIic& iic_ref) : iic(iic_ref) {};
+
+ // *************************************************************************
+ // *** Public: Init ****************************************************
+ // *************************************************************************
+ Result Init();
+
+ // *************************************************************************
+ // *** Public: Read ****************************************************
+ // *************************************************************************
+ Result Read(uint16_t addr, uint8_t* rx_buf_ptr, uint16_t size);
+
+ // *************************************************************************
+ // *** Public: Write ***************************************************
+ // *************************************************************************
+ Result Write(uint16_t addr, uint8_t* tx_buf_ptr, uint16_t size);
+
+ private:
+ // Chip address
+ static const uint8_t I2C_ADDR = 0x50U;
+
+ // Page size in bytes
+ static const uint8_t PAGE_SIZE_BYTES = 64U;
+
+ // Writing timeout in ms
+ static const uint8_t WRITING_TIMEOUT_MS = 10U;
+
+ // Repetition counter for tracking timeout
+ uint8_t repetition_cnt = 0U;
+
+ // Reference to the I2C handle
+ IIic& iic;
+
+ // *************************************************************************
+ // *** Private: Constructors and assign operator - prevent copying *****
+ // *************************************************************************
+ Eeprom24();
+ Eeprom24(const Eeprom24&);
+ Eeprom24& operator=(const Eeprom24);
+};
+
+#endif
diff --git a/Tasks/InputDrv.cpp b/Tasks/InputDrv.cpp
new file mode 100644
index 0000000..0bfd743
--- /dev/null
+++ b/Tasks/InputDrv.cpp
@@ -0,0 +1,728 @@
+//******************************************************************************
+// @file InputDrv.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Input Driver Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "InputDrv.h"
+#include "Rtos.h"
+
+// *****************************************************************************
+// *** Get Instance ********************************************************
+// *****************************************************************************
+InputDrv& InputDrv::GetInstance(void)
+{
+ // This class is static and declared here
+ static InputDrv input_drv;
+ // Return reference to class
+ return input_drv;
+}
+
+// *****************************************************************************
+// *** Init Input Driver Task **********************************************
+// *****************************************************************************
+void InputDrv::InitTask(TIM_HandleTypeDef* htm, ADC_HandleTypeDef* had)
+{
+ // Save timer handle
+ htim = htm;
+ // Save ADC handle
+ hadc = had;
+ // Auto detect left input device
+ devices[EXT_LEFT] = DetectDeviceType(EXT_LEFT);
+ // Auto detect right input device
+ devices[EXT_RIGHT] = DetectDeviceType(EXT_RIGHT);
+
+ // Configure ADC
+ ConfigADC(devices[EXT_LEFT], devices[EXT_RIGHT]);
+
+ // Create task
+ CreateTask();
+}
+
+// *****************************************************************************
+// *** Input Driver Setup **************************************************
+// *****************************************************************************
+Result InputDrv::Setup()
+{
+ // If has timer handle and at least one device is encoder
+ if( (htim != nullptr)
+ && ((devices[EXT_LEFT] == EXT_DEV_ENC) || (devices[EXT_RIGHT] == EXT_DEV_ENC)))
+ {
+ // Start timer for get interrupts. Should be there, because FreeRTOS
+ // must initialize tasks stacks before runs interrupt.
+ HAL_TIM_Base_Start_IT(htim);
+ }
+ // Init ticks variable
+ last_wake_ticks = RtosTick::GetTickCount();
+ // Always Ok
+ return Result::RESULT_OK;
+}
+
+// *****************************************************************************
+// *** Input Driver Loop ***************************************************
+// *****************************************************************************
+Result InputDrv::Loop()
+{
+ // Call interrupt handler
+ ProcessInput();
+ // Pause until next tick
+ RtosTick::DelayUntilMs(last_wake_ticks, 1U);
+ // Always run
+ return Result::RESULT_OK;
+}
+
+// *****************************************************************************
+// *** Process Input function **********************************************
+// *****************************************************************************
+void InputDrv::ProcessInput(void)
+{
+ // Cycle for process devices
+ for(uint32_t i = 0U; i < EXT_MAX; i++)
+ {
+ // Check device type
+ switch(devices[i])
+ {
+ // Process buttons device
+ case EXT_DEV_BTN:
+ // Process all buttons
+ for(uint32_t j = 0U; j < BTN_MAX; j++)
+ {
+ ProcessButtonInput(buttons[i].button[j]);
+ }
+ // Use buttons to set state of "virtual" encoder
+ EmulateEncodersByButtons((PortType)i);
+ break;
+
+ // Process encoder device
+ case EXT_DEV_ENC:
+ // If no timer handle
+ if(htim == nullptr)
+ {
+ // Process encoders input in task function
+ ProcessEncoderInput(encoders[i].enc);
+ }
+ // Always process encoder buttons in task function
+ ProcessButtonInput(encoders[i].btn[ENC_BTN_ENT]);
+ ProcessButtonInput(encoders[i].btn[ENC_BTN_BACK]);
+ break;
+
+ // Process joysticks device
+ case EXT_DEV_JOY:
+ // Process all joysticks
+ ProcessJoystickInput(joysticks[i].joy, (PortType)i);
+ // Process joystick button
+ ProcessButtonInput(joysticks[i].btn);
+ // Start measurement
+ HAL_ADCEx_InjectedStart(hadc);
+ // Use joystick to set state of "virtual" buttons
+ EmulateButtonsByJoystick((PortType)i);
+ // Use buttons to set state of "virtual" encoder
+ EmulateEncodersByButtons((PortType)i);
+ break;
+
+ case EXT_DEV_NONE:
+ case EXT_DEV_MAX:
+ default:
+ break;
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Process Button Input function ***************************************
+// *****************************************************************************
+void InputDrv::ProcessButtonInput(ButtonProfile& button)
+{
+ // Read Button state
+ bool new_status = (HAL_GPIO_ReadPin(button.button_port, button.button_pin) == button.pin_state);
+
+ // No sense do something if button status already set
+ if(button.btn_state != new_status)
+ {
+ if((button.btn_state_tmp == new_status) && (button.btn_state_cnt == BUTTON_READ_DELAY))
+ {
+ // If temporary button state true and delay done - update state
+ button.btn_state = new_status;
+ }
+ else if(button.btn_state_tmp == new_status)
+ {
+ // If temporary button state true and delay not done - increase counter
+ button.btn_state_cnt++;
+ }
+ else
+ {
+ // If temporary button state true and delay not done - increase counter
+ button.btn_state_tmp = new_status;
+ button.btn_state_cnt = 0;
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Process Encoders Input function *************************************
+// *****************************************************************************
+void InputDrv::ProcessEncodersInput(void)
+{
+ // Cycle for process devices
+ for(uint32_t i = 0U; i < EXT_MAX; i++)
+ {
+ // Check device type
+ if(devices[i] == EXT_DEV_ENC)
+ {
+ // Process encoder device
+ ProcessEncoderInput(encoders[i].enc);
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Process Encoder Input function **************************************
+// *****************************************************************************
+void InputDrv::ProcessEncoderInput(EncoderProfile& encoder)
+{
+ // Read Button state
+ uint8_t en_new_status = (HAL_GPIO_ReadPin(encoder.enc_clk_port, encoder.enc_clk_pin) << 1) |
+ HAL_GPIO_ReadPin(encoder.enc_data_port, encoder.enc_data_pin);
+
+ // States must be different
+ if(en_new_status != encoder.enc_state)
+ {
+ // We check only rise front on CLK pulse
+ if( ((en_new_status >> 1) == 1) && ((encoder.enc_state >> 1) == 0) )
+ {
+ // State of DATA input must be same during CLK pulse rise
+ if( (en_new_status & 1) == (encoder.enc_state & 1) )
+ {
+ // If DATA 1 - rotate in one side, if 0 - in another
+ if((en_new_status & 1) == 0)
+ {
+ // Increment encoder counter
+ encoder.enc_cnt++;
+ }
+ else
+ {
+ // Decrement encoder counter
+ encoder.enc_cnt--;
+ }
+ }
+ }
+ // Save new encoder state
+ encoder.enc_state = en_new_status;
+ }
+}
+
+// *****************************************************************************
+// *** Process Joystick Input function *************************************
+// *****************************************************************************
+void InputDrv::ProcessJoystickInput(JoystickProfile& joystick, PortType port)
+{
+ // Get value for X channel, add it to previous value
+ joystick.x_ch_val += HAL_ADCEx_InjectedGetValue(hadc, ((uint32_t)port << 1U) + 1U);
+ joystick.x_ch_val /= 2; // Find average of two values
+ // Get value for X channel, add it to previous value
+ joystick.y_ch_val += HAL_ADCEx_InjectedGetValue(hadc, ((uint32_t)port << 1U) + 2U);
+ joystick.y_ch_val /= 2; // Find average of two values
+}
+
+// *****************************************************************************
+// *** Emulate buttons using joystick function *****************************
+// *****************************************************************************
+void InputDrv::EmulateButtonsByJoystick(PortType port)
+{
+
+ // Center values
+ int32_t x_val;
+ int32_t y_val;
+
+ // If X channel is inverted
+ if(joysticks[port].joy.x_inverted == true)
+ {
+ // Return inverted X state
+ x_val = ADC_MAX_VAL - joysticks[port].joy.x_ch_val - ADC_MAX_VAL/2;
+ }
+ else
+ {
+ // Return inverted X state
+ x_val = joysticks[port].joy.x_ch_val - ADC_MAX_VAL/2;
+ }
+ // If Y channel is inverted
+ if(joysticks[port].joy.y_inverted == true)
+ {
+ // Return inverted Y state
+ y_val = ADC_MAX_VAL - joysticks[port].joy.y_ch_val - ADC_MAX_VAL/2;
+ }
+ else
+ {
+ // Return Y state
+ y_val = joysticks[port].joy.y_ch_val - ADC_MAX_VAL/2;
+ }
+
+ // Button left
+ if(x_val < -JOY_THRESHOLD)
+ {
+ buttons[port].button[BTN_LEFT].btn_state = true;
+ }
+ else
+ {
+ buttons[port].button[BTN_LEFT].btn_state = false;
+ }
+ // Button right
+ if(x_val > JOY_THRESHOLD)
+ {
+ buttons[port].button[BTN_RIGHT].btn_state = true;
+ }
+ else
+ {
+ buttons[port].button[BTN_RIGHT].btn_state = false;
+ }
+ // Button up
+ if(y_val < -JOY_THRESHOLD)
+ {
+ buttons[port].button[BTN_UP].btn_state = true;
+ }
+ else
+ {
+ buttons[port].button[BTN_UP].btn_state = false;
+ }
+ // Button down
+ if(y_val > JOY_THRESHOLD)
+ {
+ buttons[port].button[BTN_DOWN].btn_state = true;
+ }
+ else
+ {
+ buttons[port].button[BTN_DOWN].btn_state = false;
+ }
+}
+
+// *****************************************************************************
+// *** Emulate encoders using buttons function *****************************
+// *****************************************************************************
+void InputDrv::EmulateEncodersByButtons(PortType port)
+{
+ // Buttons previous states
+ static bool btn_left[EXT_MAX];
+ static bool btn_right[EXT_MAX];
+ // If left button changed
+ if(buttons[port].button[BTN_LEFT].btn_state != btn_left[port])
+ {
+ // Save button state
+ btn_left[port] = buttons[port].button[BTN_LEFT].btn_state;
+ // If button pressed
+ if(btn_left[port])
+ {
+ // Decrease encoder counter
+ encoders[port].enc.enc_cnt--;
+ }
+ }
+ // If right button changed
+ if(buttons[port].button[BTN_RIGHT].btn_state != btn_right[port])
+ {
+ // Save button state
+ btn_right[port] = buttons[port].button[BTN_RIGHT].btn_state;
+ // If button pressed
+ if(btn_right[port])
+ {
+ // Decrease encoder counter
+ encoders[port].enc.enc_cnt++;
+ }
+ }
+ // Copy state of down button to encoder button
+ encoders[port].btn[ENC_BTN_ENT] = buttons[port].button[BTN_DOWN];
+ encoders[port].btn[ENC_BTN_BACK]= buttons[port].button[BTN_UP];
+}
+
+// *****************************************************************************
+// *** Get device type *****************************************************
+// *****************************************************************************
+InputDrv::ExtDeviceType InputDrv::GetDeviceType(PortType port)
+{
+ // Return current state of button
+ return devices[port];
+}
+
+// *****************************************************************************
+// *** Get button state ****************************************************
+// *****************************************************************************
+bool InputDrv::GetButtonState(PortType port, ButtonType button)
+{
+ // Return current state of button
+ return buttons[port].button[button].btn_state;
+}
+
+// *****************************************************************************
+// *** Get button state ****************************************************
+// *****************************************************************************
+bool InputDrv::GetButtonState(PortType port, ButtonType button, bool& btn_state)
+{
+ bool ret = false;
+ // If button state changed
+ if(buttons[port].button[button].btn_state != btn_state)
+ {
+ // Store new state
+ btn_state = buttons[port].button[button].btn_state;
+ ret = true;
+ }
+ // Return result
+ return ret;
+}
+
+// *****************************************************************************
+// *** Get encoder counts from last call - CAN BE CALLED FROM ONE TASK *****
+// *****************************************************************************
+int32_t InputDrv::GetEncoderState(PortType port)
+{
+ return GetEncoderState(port, last_enc_value[port]);
+}
+
+// *****************************************************************************
+// *** Get encoder counts from last call ***********************************
+// *****************************************************************************
+int32_t InputDrv::GetEncoderState(PortType port, int32_t& last_enc_val)
+{
+ // Get current state - atomic operation, prevent multitasking problems
+ int32_t enc_val = encoders[port].enc.enc_cnt;
+ // Calculate return value
+ int32_t retval = enc_val - last_enc_val;
+ // Save current count to user provided variable
+ last_enc_val = enc_val;
+ // return result
+ return retval;
+}
+
+// *****************************************************************************
+// *** Get encoder button state ********************************************
+// *****************************************************************************
+bool InputDrv::GetEncoderButtonCurrentState(PortType port, EncButtonType button)
+{
+ // Return current state of button
+ return encoders[port].btn[button].btn_state;
+}
+
+// *****************************************************************************
+// *** Get encoder button state ********************************************
+// *****************************************************************************
+bool InputDrv::GetEncoderButtonState(PortType port, EncButtonType button)
+{
+ return GetEncoderButtonState(port, button, enc_btn_value[port][button]);
+}
+
+// *****************************************************************************
+// *** Get encoder button state ********************************************
+// *****************************************************************************
+bool InputDrv::GetEncoderButtonState(PortType port, EncButtonType button, bool& btn_state)
+{
+ bool ret = false;
+ // If button state changed
+ if(encoders[port].btn[button].btn_state != btn_state)
+ {
+ // store new state
+ btn_state = encoders[port].btn[button].btn_state;
+ ret = true;
+ }
+ // Return result
+ return ret;
+}
+
+// *****************************************************************************
+// *** Get joystick axis state *********************************************
+// *****************************************************************************
+void InputDrv::GetJoystickState(PortType port, int32_t& x, int32_t& y)
+{
+ // If X channel is inverted
+ if(joysticks[port].joy.x_inverted == true)
+ {
+ // Return inverted X state
+ x = ADC_MAX_VAL - joysticks[port].joy.x_ch_val;
+ }
+ else
+ {
+ // Return inverted X state
+ x = joysticks[port].joy.x_ch_val;
+ }
+ // If Y channel is inverted
+ if(joysticks[port].joy.y_inverted == true)
+ {
+ // Return inverted Y state
+ y = ADC_MAX_VAL - joysticks[port].joy.y_ch_val;
+ }
+ else
+ {
+ // Return Y state
+ y = joysticks[port].joy.y_ch_val;
+ }
+
+ // Calculate X
+ if(x > joysticks[port].joy.bx)
+ {
+ x = ((x - joysticks[port].joy.bx) * joysticks[port].joy.kxmax) / COEF;
+ }
+ else
+ {
+ x = ((x - joysticks[port].joy.bx) * joysticks[port].joy.kxmin) / COEF;
+ }
+ // Calculate Y
+ if(y > joysticks[port].joy.by)
+ {
+ y = ((y - joysticks[port].joy.by) * joysticks[port].joy.kymax) / COEF;
+ }
+ else
+ {
+ y = ((y - joysticks[port].joy.by) * joysticks[port].joy.kymin) / COEF;
+ }
+}
+
+// *****************************************************************************
+// *** SetJoystickCalibrationConsts ****************************************
+// *****************************************************************************
+// * Set calibration constants. Must be call for calibration joystick.
+void InputDrv::SetJoystickCalibrationConsts(PortType port, int32_t x_mid,
+ int32_t x_kmin, int32_t x_kmax,
+ int32_t y_mid, int32_t y_kmin,
+ int32_t y_kmax)
+{
+ // X axis calibration
+ joysticks[port].joy.bx = x_mid;
+ joysticks[port].joy.kxmin = x_kmin;
+ joysticks[port].joy.kxmax = x_kmax;
+ // Y axis calibration
+ joysticks[port].joy.by = y_mid;
+ joysticks[port].joy.kymin = y_kmin;
+ joysticks[port].joy.kymax = y_kmax;
+}
+
+// *****************************************************************************
+// *** Get joystick button state *******************************************
+// *****************************************************************************
+bool InputDrv::GetJoystickButtonState(PortType port)
+{
+ // Return current state of button
+ return joysticks[port].btn.btn_state;
+}
+
+// *****************************************************************************
+// *** Get joystick button state *******************************************
+// *****************************************************************************
+bool InputDrv::GetJoystickButtonState(PortType port, bool& btn_state)
+{
+ bool ret = false;
+ // If button state changed
+ if(joysticks[port].btn.btn_state != btn_state)
+ {
+ // store new state
+ btn_state = joysticks[port].btn.btn_state;
+ ret = true;
+ }
+ // Return result
+ return ret;
+}
+
+// *****************************************************************************
+// *** Configure inputs devices types **************************************
+// *****************************************************************************
+InputDrv::ExtDeviceType InputDrv::DetectDeviceType(PortType port)
+{
+ // Return variable
+ ExtDeviceType ret = EXT_DEV_NONE;
+ // Variable to store X axis value
+ int32_t x_val;
+ // Variable to store Y axis value
+ int32_t y_val;
+
+ if(hadc != nullptr)
+ {
+ // Config ADC for measure
+ if(port == EXT_LEFT) ConfigADC(EXT_DEV_JOY, EXT_DEV_NONE);
+ if(port == EXT_RIGHT) ConfigADC(EXT_DEV_NONE, EXT_DEV_JOY);
+ // Start measurement
+ HAL_ADCEx_InjectedStart(hadc);
+ // Wait until End of Conversion flag is raised
+ while(HAL_IS_BIT_CLR(hadc->Instance->SR, ADC_FLAG_JEOC));
+ x_val = HAL_ADCEx_InjectedGetValue(hadc, (port << 1) + 1);
+ y_val = HAL_ADCEx_InjectedGetValue(hadc, (port << 1) + 2);
+
+ // Center values
+ x_val -= ADC_MAX_VAL/2;
+ y_val -= ADC_MAX_VAL/2;
+ // If at least one value near center
+ if( ((x_val > -JOY_THRESHOLD) && (x_val < JOY_THRESHOLD))
+ || ((y_val > -JOY_THRESHOLD) && (y_val < JOY_THRESHOLD)))
+ {
+ // Joystick connected
+ ret = EXT_DEV_JOY;
+ }
+ else
+ {
+ // Stop ADC before switch to digital inputs
+ HAL_ADCEx_InjectedStop(hadc);
+ // Config input IO to digital
+ ConfigInputIO(true, port);
+ }
+ }
+ else
+ {
+ // Config input IO to digital
+ ConfigInputIO(true, port);
+ }
+
+ // If Joystick not detected
+ if(ret == EXT_DEV_NONE)
+ {
+ // Configure GPIO pins for detect devices
+ GPIO_InitTypeDef GPIO_InitStruct;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+ GPIO_InitStruct.Pin = encoders[port].btn[ENC_BTN_BACK].button_pin;
+ HAL_GPIO_Init(encoders[port].btn[ENC_BTN_BACK].button_port, &GPIO_InitStruct);
+
+ // If pin state low - encoder
+ if(HAL_GPIO_ReadPin(encoders[port].btn[ENC_BTN_BACK].button_port,
+ encoders[port].btn[ENC_BTN_BACK].button_pin) == GPIO_PIN_RESET)
+ {
+ ret = EXT_DEV_ENC;
+ }
+ else
+ {
+ ret = EXT_DEV_BTN;
+ }
+
+ // Restore GPIO pins configuration
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Pin = buttons[port].button[BTN_LEFT].button_pin;
+ HAL_GPIO_Init(buttons[port].button[BTN_LEFT].button_port, &GPIO_InitStruct);
+ }
+ return ret;
+}
+
+// *****************************************************************************
+// *** Config ADC **********************************************************
+// *****************************************************************************
+void InputDrv::ConfigADC(ExtDeviceType dev_left, ExtDeviceType dev_right)
+{
+ // We can configure ADC only if ADC handle is not nullptr and at least one
+ // joystick present
+ if( (hadc != nullptr)
+ && ((dev_left == EXT_DEV_JOY) || (dev_right == EXT_DEV_JOY)))
+ {
+ // Update ADC settings - should be Scan mode
+#if defined(STM32F1)
+ hadc->Init.ScanConvMode = ADC_SCAN_ENABLE;
+#elif defined(STM32F4)
+ hadc->Init.ScanConvMode = ENABLE;
+#endif
+ // Init ADC
+ if (HAL_ADC_Init(hadc) != HAL_OK)
+ {
+ Error_Handler();
+ }
+
+ // Structure for init Injected Channel
+ ADC_InjectionConfTypeDef sConfigInjected;
+ // Configure Injected Channel
+ sConfigInjected.InjectedNbrOfConversion = EXT_MAX*2;
+#if defined(STM32F1)
+ sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_239CYCLES_5;
+#elif defined(STM32F4)
+ sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_480CYCLES;
+#endif
+ sConfigInjected.ExternalTrigInjecConv = ADC_INJECTED_SOFTWARE_START;
+ sConfigInjected.AutoInjectedConv = DISABLE;
+ sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
+ sConfigInjected.InjectedOffset = 0;
+ sConfigInjected.InjectedRank = 1;
+
+ // Channels
+ uint32_t injected_channels[EXT_MAX*2] = {0,0,0,0};
+
+ // If both devices - joysticks
+ if((dev_left == EXT_DEV_JOY) && (dev_right == EXT_DEV_JOY))
+ {
+ // Left joystick
+ injected_channels[0] = joysticks[EXT_LEFT].joy.x_channel;
+ injected_channels[1] = joysticks[EXT_LEFT].joy.y_channel;
+ // Right joystick
+ injected_channels[2] = joysticks[EXT_RIGHT].joy.x_channel;
+ injected_channels[3] = joysticks[EXT_RIGHT].joy.y_channel;
+ }
+ // If only left joystick present
+ else if(dev_left == EXT_DEV_JOY)
+ {
+ // Left joystick for all channels
+ injected_channels[0] = joysticks[EXT_LEFT].joy.x_channel;
+ injected_channels[1] = joysticks[EXT_LEFT].joy.y_channel;
+ injected_channels[2] = joysticks[EXT_LEFT].joy.x_channel;
+ injected_channels[3] = joysticks[EXT_LEFT].joy.y_channel;
+ }
+ // If only right joystick present
+ else if(dev_right == EXT_DEV_JOY)
+ {
+ // Right joystick for all channels
+ injected_channels[0] = joysticks[EXT_RIGHT].joy.x_channel;
+ injected_channels[1] = joysticks[EXT_RIGHT].joy.y_channel;
+ injected_channels[2] = joysticks[EXT_RIGHT].joy.x_channel;
+ injected_channels[3] = joysticks[EXT_RIGHT].joy.y_channel;
+ }
+ else
+ {
+ // FIX ME: CATCH ERROR HERE !!!
+ }
+
+ // Cycle for init Injected channels
+ for(uint32_t i = 0U; i < NumberOf(injected_channels); i++)
+ {
+ // Configure Injected Channel - X axis
+ sConfigInjected.InjectedChannel = injected_channels[i];
+ if (HAL_ADCEx_InjectedConfigChannel(hadc, &sConfigInjected) != HAL_OK)
+ {
+ Error_Handler();
+ }
+ // Increase rank counter
+ sConfigInjected.InjectedRank++;
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Configure inputs for read digital/analog data ***********************
+// *****************************************************************************
+void InputDrv::ConfigInputIO(bool is_digital, PortType port)
+{
+ // Structure for set IO parameters
+ GPIO_InitTypeDef GPIO_InitStruct;
+ // Set no pull - no effect if analog mode selected
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+
+ // Check requested mode
+ if(is_digital == true)
+ {
+ // Set input mode
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ }
+ else
+ {
+ // Set analog mode
+ GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+ }
+
+ // Configure GPIO pins : EXT_L1_Pin
+ GPIO_InitStruct.Pin = joysticks[port].joy.x_pin;
+ HAL_GPIO_Init(joysticks[port].joy.x_port, &GPIO_InitStruct);
+ // Configure GPIO pins : EXT_L2_Pin
+ GPIO_InitStruct.Pin = joysticks[port].joy.y_pin;
+ HAL_GPIO_Init(joysticks[port].joy.y_port, &GPIO_InitStruct);
+}
diff --git a/Tasks/InputDrv.h b/Tasks/InputDrv.h
new file mode 100644
index 0000000..f268afb
--- /dev/null
+++ b/Tasks/InputDrv.h
@@ -0,0 +1,415 @@
+//******************************************************************************
+// @file InputDrv.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Input Driver Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef InputDrv_h
+#define InputDrv_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "AppTask.h"
+
+// *****************************************************************************
+// * Input Driver Class. This class implement work with user input elements like
+// * buttons and encoders.
+class InputDrv : public AppTask
+{
+ public:
+ // *************************************************************************
+ // *** Enum with all buttons *******************************************
+ // *************************************************************************
+ typedef enum
+ {
+ EXT_LEFT, // Left ext port
+ EXT_RIGHT, // Right ext port
+ EXT_MAX // Ext port count
+ } PortType;
+
+ // *************************************************************************
+ // *** Enum with all devices types *************************************
+ // *************************************************************************
+ typedef enum
+ {
+ EXT_DEV_NONE, // No device
+ EXT_DEV_BTN, // Buttons(cross)
+ EXT_DEV_ENC, // Encoder
+ EXT_DEV_JOY, // Joystick
+ EXT_DEV_MAX // Device types count
+ } ExtDeviceType;
+
+ // *************************************************************************
+ // *** Enum with all buttons *******************************************
+ // *************************************************************************
+ typedef enum
+ {
+ BTN_UP, // Up button
+ BTN_LEFT, // Left button
+ BTN_DOWN, // Down button
+ BTN_RIGHT, // Right button
+ BTN_MAX // Buttons count
+ } ButtonType;
+
+ // *************************************************************************
+ // *** Enum with all encoder buttons ***********************************
+ // *************************************************************************
+ typedef enum
+ {
+ ENC_BTN_ENT, // Press on the knob
+ ENC_BTN_BACK, // Small button
+ ENC_BTN_MAX // Buttons count
+ } EncButtonType;
+
+ // *************************************************************************
+ // *** Get Instance ****************************************************
+ // *************************************************************************
+ // * This class is singleton. For use this class you must call GetInstance()
+ // * to receive reference to Input Driver class
+ static InputDrv& GetInstance(void);
+
+ // *************************************************************************
+ // *** Init Input Driver Task ******************************************
+ // *************************************************************************
+ // * This function initialize Input Driver class. If htim provided, this
+ // * timer will be used instead FreeRTOS task.
+ virtual void InitTask(TIM_HandleTypeDef* htm, ADC_HandleTypeDef* had);
+
+ // *************************************************************************
+ // *** Input Driver Setup **********************************************
+ // *************************************************************************
+ virtual Result Setup();
+
+ // *************************************************************************
+ // *** Input Driver Loop ***********************************************
+ // *************************************************************************
+ // * If FreeRTOS task used, this function just call ProcessInput() with 1 ms
+ // * period. If FreeRTOS tick is 1 ms - this task must have highest priority
+ virtual Result Loop();
+
+ // *************************************************************************
+ // *** Process Input function ******************************************
+ // *************************************************************************
+ // * Main class function - must call periodically for process user input.
+ // * If timer used, this function must be called from interrupt handler.
+ void ProcessInput(void);
+
+ // *************************************************************************
+ // *** Process Encoders Input function *********************************
+ // *************************************************************************
+ void ProcessEncodersInput(void);
+
+ // *************************************************************************
+ // *** Get device type *************************************************
+ // *************************************************************************
+ ExtDeviceType GetDeviceType(PortType port);
+
+ // *************************************************************************
+ // *** Get button state ************************************************
+ // *************************************************************************
+ // Return button state: true - pressed, false - unpressed
+ bool GetButtonState(PortType port, ButtonType button);
+
+ // *************************************************************************
+ // *** Get button state ************************************************
+ // *************************************************************************
+ // Return button state change flag: true - changed, false - not changed
+ bool GetButtonState(PortType port, ButtonType button, bool& btn_state);
+
+ // *************************************************************************
+ // *** Get encoder counts from last call - CAN BE CALLED FROM ONE TASK *
+ // *************************************************************************
+ int32_t GetEncoderState(PortType port);
+
+ // *************************************************************************
+ // *** Get encoder counts from last call *******************************
+ // *************************************************************************
+ // * Return state of encoder. Class counts encoder clicks and stored inside.
+ // * This function substract from current encoder counter last_enc_val and
+ // * return it to user. Before return last_enc_val will be assigned to
+ // * current encoder counter.
+ int32_t GetEncoderState(PortType port, int32_t& last_enc_val);
+
+ // *************************************************************************
+ // *** Get button state ************************************************
+ // *************************************************************************
+ // Return button state: true - pressed, false - unpressed
+ bool GetEncoderButtonCurrentState(PortType port, EncButtonType button);
+
+ // *************************************************************************
+ // *** Get encoder button state - CAN BE CALLED FROM ONE TASK **********
+ // *************************************************************************
+ // Return button state: true - state changed, false - state remain
+ bool GetEncoderButtonState(PortType port, EncButtonType button);
+
+ // *************************************************************************
+ // *** Get encoder button state ****************************************
+ // *************************************************************************
+ // Return button state: true - state changed, false - state remain
+ bool GetEncoderButtonState(PortType port, EncButtonType button, bool& btn_state);
+
+ // *************************************************************************
+ // *** Get joystick counts from last call ******************************
+ // *************************************************************************
+ void GetJoystickState(PortType port, int32_t& x, int32_t& y);
+
+ // *************************************************************************
+ // *** SetJoystickCalibrationConsts ************************************
+ // *************************************************************************
+ // * Set calibration constants. Must be call for calibration joystick.
+ void SetJoystickCalibrationConsts(PortType port, int32_t x_mid,
+ int32_t x_kmin, int32_t x_kmax,
+ int32_t y_mid, int32_t y_kmin,
+ int32_t y_kmax);
+
+ // *************************************************************************
+ // *** Get joystick button state ***************************************
+ // *************************************************************************
+ // Return button state: true - pressed, false - unpressed
+ bool GetJoystickButtonState(PortType port);
+
+ // *************************************************************************
+ // *** Get joystick button state ***************************************
+ // *************************************************************************
+ // Return button state: true - pressed, false - unpressed
+ bool GetJoystickButtonState(PortType port, bool& btn_state);
+
+ private:
+ // How many cycles button must change state before state will be changed in
+ // result returned by GetButtonState() function. For reduce debouncing
+ const static uint32_t BUTTON_READ_DELAY = 4U;
+ // Coefficient for calibration
+ const static int32_t COEF = 100;
+
+ // ADC max value - 12 bit
+ const static int32_t ADC_MAX_VAL = 0xFFF;
+ // Joystich threshold
+ const static int32_t JOY_THRESHOLD = 1000;
+
+ // Ticks variable
+ uint32_t last_wake_ticks = 0U;
+
+ // *************************************************************************
+ // *** Structure to describe button ************************************
+ // *************************************************************************
+ typedef struct
+ {
+ bool btn_state; // Button state returned by GetButtonState() function
+ bool btn_state_tmp; // Temporary button state for reduce debouncing
+ uint8_t btn_state_cnt; // Counter for reduce debouncing
+ GPIO_TypeDef* button_port;// Button port
+ uint16_t button_pin; // Button pin
+ GPIO_PinState pin_state; // High/low on input treated as pressed
+ } ButtonProfile;
+
+ // *************************************************************************
+ // *** Structure to describe encoder ***********************************
+ // *************************************************************************
+ typedef struct
+ {
+ // Encoder rotation
+ int32_t enc_cnt; // Encoder counter
+ uint8_t enc_state; // Current state of encder clock & data pins
+ GPIO_TypeDef* enc_clk_port; // Encoder clock port
+ uint16_t enc_clk_pin; // Encoder clock pin
+ GPIO_TypeDef* enc_data_port;// Encoder data port
+ uint16_t enc_data_pin; // Encoder data pin
+ } EncoderProfile;
+
+ // *************************************************************************
+ // *** Structure to describe joysticks *********************************
+ // *************************************************************************
+ typedef struct
+ {
+ int32_t x_ch_val; // Joystick X axis value
+ uint32_t x_channel; // Joystick X axis ADC channel
+ GPIO_TypeDef* x_port; // Joystick X axis port
+ uint16_t x_pin; // Joystick X axis pin
+ int32_t bx; // Joystick X offset
+ int32_t kxmin; // Joystick X coefficient
+ int32_t kxmax; // Joystick X coefficient
+ bool x_inverted; // Joystick X inverted flag
+ int32_t y_ch_val; // Joystick Y axis value
+ uint32_t y_channel; // Joystick Y axis ADC channel
+ GPIO_TypeDef* y_port; // Joystick Y axis port
+ uint16_t y_pin; // Joystick Y axis pin
+ int32_t by; // Joystick Y offset
+ int32_t kymin; // Joystick Y coefficient
+ int32_t kymax; // Joystick Y coefficient
+ bool y_inverted; // Joystick Y inverted flag
+ } JoystickProfile;
+
+ // *************************************************************************
+ // *** Structure to describe encoders **********************************
+ // *************************************************************************
+ typedef struct
+ {
+ EncoderProfile enc;
+ ButtonProfile btn[ENC_BTN_MAX];
+ } DevEncoders;
+
+ // *************************************************************************
+ // *** Structure to describe encoders **********************************
+ // *************************************************************************
+ typedef struct
+ {
+ JoystickProfile joy;
+ ButtonProfile btn;
+ } DevJoysticks;
+
+ // *************************************************************************
+ // *** Structure to describe buttons ***********************************
+ // *************************************************************************
+ typedef struct
+ {
+ ButtonProfile button[BTN_MAX];
+ } DevButtons;
+
+ // *** Array describes types of connected devices ***********************
+ ExtDeviceType devices[EXT_MAX];
+
+ // *** Structures array for describe buttons inputs *********************
+ DevButtons buttons[EXT_MAX] =
+ {
+ // Left device
+ {{{false, false, 0, EXT_L1_GPIO_Port, EXT_L1_Pin, GPIO_PIN_RESET},
+ {false, false, 0, EXT_L2_GPIO_Port, EXT_L2_Pin, GPIO_PIN_RESET},
+ {false, false, 0, EXT_L3_GPIO_Port, EXT_L3_Pin, GPIO_PIN_RESET},
+ {false, false, 0, EXT_L4_GPIO_Port, EXT_L4_Pin, GPIO_PIN_RESET}}},
+ // Right device
+ {{{false, false, 0, EXT_R1_GPIO_Port, EXT_R1_Pin, GPIO_PIN_RESET},
+ {false, false, 0, EXT_R2_GPIO_Port, EXT_R2_Pin, GPIO_PIN_RESET},
+ {false, false, 0, EXT_R3_GPIO_Port, EXT_R3_Pin, GPIO_PIN_RESET},
+ {false, false, 0, EXT_R4_GPIO_Port, EXT_R4_Pin, GPIO_PIN_RESET}}}
+ };
+
+ // *** Structures array for describe encoders inputs ********************
+ DevEncoders encoders[EXT_MAX] =
+ {
+ // Left device
+ {{0, 0, EXT_L1_GPIO_Port, EXT_L1_Pin, EXT_L2_GPIO_Port, EXT_L2_Pin}, // Encoder
+ {{false, false, 0, EXT_L3_GPIO_Port, EXT_L3_Pin, GPIO_PIN_RESET}, // Button Enter
+ {false, false, 0, EXT_L4_GPIO_Port, EXT_L4_Pin, GPIO_PIN_SET}}}, // Button Back
+ // Right device
+ {{0, 0, EXT_R1_GPIO_Port, EXT_R1_Pin, EXT_R2_GPIO_Port, EXT_R2_Pin}, // Encoder
+ {{false, false, 0, EXT_R3_GPIO_Port, EXT_R3_Pin, GPIO_PIN_RESET}, // Button Enter
+ {false, false, 0, EXT_R4_GPIO_Port, EXT_R4_Pin, GPIO_PIN_SET}}} // Button Back
+ };
+
+ // *** Structures array for describe encoders inputs ********************
+ DevJoysticks joysticks[EXT_MAX] =
+ {
+ // Left device
+ {{0, ADC_CHANNEL_11, EXT_L2_GPIO_Port, EXT_L2_Pin, 0, COEF, COEF, false, // Joystick
+ 0, ADC_CHANNEL_10, EXT_L1_GPIO_Port, EXT_L1_Pin, 0, COEF, COEF, true},
+ {false, false, 0, EXT_L3_GPIO_Port, EXT_L3_Pin, GPIO_PIN_RESET}}, // Button
+ // Right device
+ {{0, ADC_CHANNEL_13, EXT_R2_GPIO_Port, EXT_R2_Pin, 0, COEF, COEF, false, // Joystick
+ 0, ADC_CHANNEL_12, EXT_R1_GPIO_Port, EXT_R1_Pin, 0, COEF, COEF, true},
+ {false, false, 0, EXT_R3_GPIO_Port, EXT_R3_Pin, GPIO_PIN_RESET}} // Button
+ };
+
+ // Handle to timer used for process encoders input
+ TIM_HandleTypeDef* htim = nullptr;
+ // Handle to timer used for process encoders input
+ ADC_HandleTypeDef* hadc = nullptr;
+
+ // *************************************************************************
+ // *** Last value for reduce overhead in user task *********************
+ // *************************************************************************
+ // Encoder values
+ int32_t last_enc_value[EXT_MAX] = {0};
+ // Encoder button states
+ bool enc_btn_value[EXT_MAX][ENC_BTN_MAX] = {0};
+
+ // *************************************************************************
+ // *** Process Button Input function ***********************************
+ // *************************************************************************
+ void ProcessButtonInput(ButtonProfile& button);
+
+ // *************************************************************************
+ // *** Process Encoder Input function **********************************
+ // *************************************************************************
+ void ProcessEncoderInput(EncoderProfile& encoder);
+
+ // *************************************************************************
+ // *** Process Joystick Input function *********************************
+ // *************************************************************************
+ void ProcessJoystickInput(JoystickProfile& joysticks, PortType port);
+
+ // *************************************************************************
+ // *** Emulate buttons using joystick function *************************
+ // *************************************************************************
+ void EmulateButtonsByJoystick(PortType port);
+
+ // *************************************************************************
+ // *** Emulate encoders using buttons function *************************
+ // *************************************************************************
+ void EmulateEncodersByButtons(PortType port);
+
+ // *************************************************************************
+ // *** Configure inputs devices types **********************************
+ // *************************************************************************
+ ExtDeviceType DetectDeviceType(PortType port);
+
+ // *************************************************************************
+ // *** Configure ADC ***************************************************
+ // *************************************************************************
+ void ConfigADC(ExtDeviceType dev_left, ExtDeviceType dev_right);
+
+ // *************************************************************************
+ // *** Configure inputs for read digital/analog data *******************
+ // *************************************************************************
+ void ConfigInputIO(bool is_digital, PortType port);
+
+ // *************************************************************************
+ // ** Private constructor. Only GetInstance() allow to access this class. **
+ // *************************************************************************
+ InputDrv() : AppTask(INPUT_DRV_TASK_STACK_SIZE, INPUT_DRV_TASK_PRIORITY,
+ "InputDrv") {};
+};
+
+#endif
diff --git a/Tasks/SoundDrv.cpp b/Tasks/SoundDrv.cpp
new file mode 100644
index 0000000..4831ce9
--- /dev/null
+++ b/Tasks/SoundDrv.cpp
@@ -0,0 +1,273 @@
+//******************************************************************************
+// @file SoundDrv.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Sound Driver Class, implementation
+//
+// @copyright Copyright (c) 2017, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "SoundDrv.h"
+#include "Rtos.h"
+
+// *****************************************************************************
+// *** Get Instance ********************************************************
+// *****************************************************************************
+SoundDrv& SoundDrv::GetInstance(void)
+{
+ // This class is static and declared here
+ static SoundDrv sound_drv;
+ // Return reference to class
+ return sound_drv;
+}
+
+// *****************************************************************************
+// *** Init Display Driver Task ********************************************
+// *****************************************************************************
+void SoundDrv::InitTask(TIM_HandleTypeDef* htm)
+{
+ // Save timer handle
+ htim = htm;
+ // Create task
+ CreateTask();
+}
+
+// *****************************************************************************
+// *** Sound Driver Setup **************************************************
+// *****************************************************************************
+Result SoundDrv::Setup()
+{
+ // Init ticks variable
+ last_wake_ticks = RtosTick::GetTickCount();
+ // Always ok
+ return Result::RESULT_OK;
+}
+
+// *****************************************************************************
+// *** Sound Driver Loop ***************************************************
+// *****************************************************************************
+Result SoundDrv::Loop()
+{
+ // Flag
+ bool is_playing = false;
+ // Take mutex before start playing sound
+ melody_mutex.Lock();
+ // Delay for playing one frequency
+ uint32_t current_delay_ms = delay_ms;
+ // If no current melody or melody size is zero - skip playing
+ if((sound_table != nullptr) && (sound_table_size != 0U))
+ {
+ // Set flag that still playing sound
+ is_playing = true;
+ // If frequency greater than 18 Hz
+ if(((uint32_t)sound_table[sound_table_position] >> 4U) > 0x12U)
+ {
+ Tone(sound_table[sound_table_position] >> 4U);
+ }
+ else
+ {
+ // Otherwise "play" silence
+ Tone(0U);
+ }
+
+ // Get retry counter from table and calculate delay
+ current_delay_ms *= sound_table[sound_table_position] & 0x0FU;
+
+ // Increase array index
+ sound_table_position++;
+ // If end of melody reached
+ if(sound_table_position >= sound_table_size)
+ {
+ // If set repeat flag
+ if(repeat == true)
+ {
+ // Reset index for play melody from beginning
+ sound_table_position = 0U;
+ }
+ else
+ {
+ // Otherwise stop playing sound
+ StopSound();
+ }
+ }
+ }
+ // Give mutex after start playing sound
+ melody_mutex.Release();
+
+ // Pause until next tick
+ RtosTick::DelayUntilMs(last_wake_ticks, current_delay_ms);
+
+ // Using semaphore here helps block this task while task wait request for
+ // sound playing.
+ if(is_playing == false)
+ {
+ // Wait semaphore for start play melody
+ sound_update.Take();
+ }
+
+ // Always run
+ return Result::RESULT_OK;
+}
+
+// *****************************************************************************
+// *** Beep function *******************************************************
+// *****************************************************************************
+void SoundDrv::Beep(uint16_t freq, uint16_t del, bool pause_after_play)
+{
+ // Take mutex before beeping - prevent play melody during beeping.
+ melody_mutex.Lock();
+ // Start play tone
+ Tone(freq);
+ // Delay
+ RtosTick::DelayMs(del);
+ // Stop play tone
+ Tone(0);
+ // If flag is set
+ if(pause_after_play == true)
+ {
+ // Delay with same value as played sound
+ RtosTick::DelayMs(del);
+ }
+ // Give mutex after beeping
+ melody_mutex.Release();
+}
+
+// *****************************************************************************
+// *** Play sound function *************************************************
+// *****************************************************************************
+void SoundDrv::PlaySound(const uint16_t* melody, uint16_t size, uint16_t temp_ms, bool rep)
+{
+ // Parameters: pointer to melody table, size of melody and repetition flag.
+ // Format of sounds: 0x***#, where *** frequency, # - delay in temp_ms intervals
+
+ // If pointer is not nullptr, if size & freq time greater than zero
+ if((melody != nullptr) && (size > 0U) && (temp_ms > 0U))
+ {
+ // If already playing any melody
+ if(IsSoundPlayed() == true)
+ {
+ // Stop it first
+ StopSound();
+ }
+
+ // Take mutex before start playing melody
+ melody_mutex.Lock();
+ // Set repeat flag for melody
+ repeat = rep;
+ // Set time for one frequency
+ delay_ms = temp_ms;
+ // Set initial index for melody
+ sound_table_position = 0;
+ // Set melody size
+ sound_table_size = size;
+ // Set melody pointer
+ sound_table = melody;
+ // Give mutex after start playing melody
+ melody_mutex.Release();
+
+ // Give semaphore for start play melody
+ sound_update.Give();
+ }
+}
+
+// *****************************************************************************
+// *** Stop sound function *************************************************
+// *****************************************************************************
+void SoundDrv::StopSound(void)
+{
+ // Take mutex before stop playing sound
+ melody_mutex.Lock();
+ // Clear sound table pointer
+ sound_table = nullptr;
+ // Clear sound table size
+ sound_table_size = 0;
+ // Clear sound table index
+ sound_table_position = 0;
+ // Set time for one frequency
+ delay_ms = 100U;
+ // Set repeat flag for melody
+ repeat = false;
+ // Stop sound
+ Tone(0);
+ // Give mutex after stop playing sound
+ melody_mutex.Release();
+}
+
+// *****************************************************************************
+// *** Mute sound function *************************************************
+// *****************************************************************************
+void SoundDrv::Mute(bool mute_flag)
+{
+ // Set mute flag
+ mute = mute_flag;
+ // If mute flag is set - call Tone() for stop tone
+ if(mute == true)
+ {
+ Tone(0U);
+ }
+}
+
+// *****************************************************************************
+// *** Is sound played function ********************************************
+// *****************************************************************************
+bool SoundDrv::IsSoundPlayed(void)
+{
+ // Return variable, false by default
+ bool ret = false;
+ // If sound_table is not nullptr - we still playing melody. No sense to use
+ // mutex here - get pointer is atomic operation.
+ if(sound_table != nullptr)
+ {
+ ret = true;
+ }
+ // Return result
+ return ret;
+}
+
+// *****************************************************************************
+// *** Process Button Input function ***************************************
+// *****************************************************************************
+void SoundDrv::Tone(uint16_t freq)
+{
+ // FIX ME: rewrite comment
+ // Òàéìåð çàïóñêàåòñÿ ñ ïàðàìåòðàìè:
+ // Clock source: System Clock
+ // Mode: CTC top = OCR2
+ // OC2 output: Toggle on compare match
+ // È ñ ðàçíûìè äåëèòåëÿìè äëÿ ðàçíûõ ÷àñòîò, ïîòîìó êàê:
+ // ïðè äåëèòåëå 64 íåâîçìîæíî ïîëó÷èòü ÷àñòîòó íèæå ~750Ãö
+ // ïðè äåëèòåëå 256 íà ÷àñòîòàõ > ~1500Ãö âûñîêà ïîãðåøíîñòü ãåíåðàöèè
+ // Äåëåíèå íà 4 àðãóìåíòîâ äëÿ òîãî, ÷òî áû AVR_Clock_Freq/x íå ïðåâûñèëî word
+ // Äåëåíèå íà äâà â êîíöå, ïîòîìó êàê íóæåí ïîëóïåðèîä
+ // Åñëè çâóê îòêëþ÷åí - òàéìåð îñòàíàâëèâàåòñÿ è ñíèìàåòñÿ íàïðÿæåíèå ñ ïèùàëêè
+ if((freq > 11) && (mute == false))
+ {
+ // Calculate prescaler
+ uint32_t prescaler = (HAL_RCC_GetHCLKFreq()/100U) / freq;
+ // Set the Prescaler value
+ htim->Instance->PSC = (uint32_t)prescaler;
+ // Generate an update event to reload the Prescaler and the repetition
+ // counter(only for TIM1 and TIM8) value immediately
+ htim->Instance->EGR = TIM_EGR_UG;
+ // Start timer in Output Compare match mode
+ (void) HAL_TIM_OC_Start(htim, channel);
+ }
+ else
+ {
+ // Stop timer
+ HAL_TIM_OC_Stop(htim, channel);
+ // Clear Speaker output pin for decrease power consumer
+ HAL_GPIO_WritePin(SPEAKER_GPIO_Port, SPEAKER_Pin, GPIO_PIN_RESET);
+ }
+}
diff --git a/Tasks/SoundDrv.h b/Tasks/SoundDrv.h
new file mode 100644
index 0000000..093ff1d
--- /dev/null
+++ b/Tasks/SoundDrv.h
@@ -0,0 +1,155 @@
+//******************************************************************************
+// @file SoundDrv.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: Sound Driver Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef SoundDrv_h
+#define SoundDrv_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "AppTask.h"
+#include "RtosMutex.h"
+#include "RtosSemaphore.h"
+
+// *****************************************************************************
+// *** Sound Driver Class. This class implement work with sound. ***********
+// *****************************************************************************
+class SoundDrv : public AppTask
+{
+ public:
+ // *************************************************************************
+ // *** Get Instance ****************************************************
+ // *************************************************************************
+ // * This class is singleton. For use this class you must call GetInstance()
+ // * to receive reference to Sound Driver class
+ static SoundDrv& GetInstance(void);
+
+ // *************************************************************************
+ // *** Init Sound Driver Task ******************************************
+ // *************************************************************************
+ virtual void InitTask(TIM_HandleTypeDef *htm);
+
+ // *************************************************************************
+ // *** Sound Driver Setup **********************************************
+ // *************************************************************************
+ virtual Result Setup();
+
+ // *************************************************************************
+ // *** Sound Driver Loop ***********************************************
+ // *************************************************************************
+ virtual Result Loop();
+
+ // *************************************************************************
+ // *** Beep function ***************************************************
+ // *************************************************************************
+ void Beep(uint16_t freq, uint16_t del, bool pause_after_play = false);
+
+ // *************************************************************************
+ // *** Play sound function *********************************************
+ // *************************************************************************
+ void PlaySound(const uint16_t* melody, uint16_t size, uint16_t temp_ms = 100U, bool rep = false);
+
+ // *************************************************************************
+ // *** Stop sound function *********************************************
+ // *************************************************************************
+ void StopSound(void);
+
+ // *************************************************************************
+ // *** Mute sound function *********************************************
+ // *************************************************************************
+ void Mute(bool mute_flag);
+
+ // *************************************************************************
+ // *** Is sound played function ****************************************
+ // *************************************************************************
+ bool IsSoundPlayed(void);
+
+ private:
+ // Timer handle
+ TIM_HandleTypeDef* htim = SOUND_HTIM;
+ // Timer channel
+ uint32_t channel = SOUND_CHANNEL;
+
+ // Ticks variable
+ uint32_t last_wake_ticks = 0U;
+
+ // Pointer to table contains melody
+ const uint16_t* sound_table = nullptr;
+ // Size of table
+ uint16_t sound_table_size = 0U;
+ // Current position
+ uint16_t sound_table_position = 0U;
+ // Current frequency delay
+ uint16_t current_delay = 0U;
+ // Time for one frequency in ms
+ uint32_t delay_ms = 100U;
+ // Repeat flag
+ bool repeat = false;
+
+ // Mute flag
+ bool mute = false;
+
+ // Mutex to synchronize when playing melody frames
+ RtosMutex melody_mutex;
+
+ // Semaphore for start play sound
+ RtosSemaphore sound_update;
+
+ // *************************************************************************
+ // *** Process Button Input function ***********************************
+ // *************************************************************************
+ void Tone(uint16_t freq);
+
+ // *************************************************************************
+ // ** Private constructor. Only GetInstance() allow to access this class. **
+ // *************************************************************************
+ SoundDrv() : AppTask(SOUND_DRV_TASK_STACK_SIZE, SOUND_DRV_TASK_PRIORITY,
+ "SoundDrv") {};
+};
+
+#endif
diff --git a/UiEngine/UiButton.cpp b/UiEngine/UiButton.cpp
new file mode 100644
index 0000000..6edd519
--- /dev/null
+++ b/UiEngine/UiButton.cpp
@@ -0,0 +1,129 @@
+//******************************************************************************
+// @file UiButton.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Button Visual Object Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "UiButton.h"
+
+// *****************************************************************************
+// *****************************************************************************
+// *** CheckBox ************************************************************
+// *****************************************************************************
+// *****************************************************************************
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+UiButton::UiButton(const char* str_in, int32_t x, int32_t y, int32_t w, int32_t h,
+ bool is_active)
+{
+ SetParams(str_in, x, y, w, h, is_active);
+}
+
+// *****************************************************************************
+// *** SetParams ***********************************************************
+// *****************************************************************************
+void UiButton::SetParams(const char* str_in, int32_t x, int32_t y, int32_t w, int32_t h,
+ bool is_active)
+{
+ // Clear callback
+ callback = nullptr;
+ // Save string
+ str = str_in;
+ // VisObject variables
+ x_start = x;
+ y_start = y;
+ x_end = x + w;
+ y_end = y + h;
+ width = w;
+ height = h;
+ active = is_active;
+ // Set box params
+ box.SetParams(x, y, w, h, COLOR_WHITE);
+ // Set string params
+ string.SetParams(str, x, y, COLOR_WHITE, String::FONT_8x12);
+ string.Move((w-string.GetWidth())/2, (h-string.GetHeight())/2, true);
+}
+
+// *************************************************************************
+// *** Set callback function *******************************************
+// *************************************************************************
+void UiButton::SetCallback(void (*clbk)(void* ptr, void* param_ptr, uint32_t param),
+ void* clbk_ptr, void* clbk_param_ptr, uint32_t clbk_param)
+{
+ callback = clbk;
+ ptr = clbk_ptr;
+ param_ptr = clbk_param_ptr;
+ param = clbk_param;
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void UiButton::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ box.DrawInBufW(buf, n, line, start_x);
+ string.DrawInBufW(buf, n, line, start_x);
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void UiButton::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ box.DrawInBufH(buf, n, row, start_y);
+ string.DrawInBufH(buf, n, row, start_y);
+}
+
+// *****************************************************************************
+// *** Action **************************************************************
+// *****************************************************************************
+void UiButton::Action(VisObject::ActionType action, int32_t tx, int32_t ty)
+{
+ // Switch for process action
+ switch(action)
+ {
+ // Touch action
+ case VisObject::ACT_TOUCH: // Fall thru
+ case VisObject::ACT_MOVEIN:
+ // Set box params
+ box.SetParams(x_start, y_start, width, height, COLOR_WHITE, true);
+ // Set string params
+ string.SetColor(COLOR_BLACK);
+ break;
+
+ // Untouch action
+ case VisObject::ACT_UNTOUCH:
+ // Call callback
+ if(callback != nullptr)
+ {
+ callback(ptr, param_ptr, param);
+ }
+ // No break here, because other actions the same as Move Out
+ case VisObject::ACT_MOVEOUT:
+ // Set box params
+ box.SetParams(x_start, y_start, width, height, COLOR_WHITE, false);
+ // Set string params
+ string.SetColor(COLOR_WHITE);
+ break;
+
+ case VisObject::ACT_MAX:
+ default:
+ break;
+ }
+}
diff --git a/UiEngine/UiButton.h b/UiEngine/UiButton.h
new file mode 100644
index 0000000..5f768f8
--- /dev/null
+++ b/UiEngine/UiButton.h
@@ -0,0 +1,116 @@
+//******************************************************************************
+// @file UiButton.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Button Visual Object Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef UiButton_h
+#define UiButton_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "DisplayDrv.h"
+#include "VisObject.h"
+
+// *****************************************************************************
+// *** Button Class ********************************************************
+// *****************************************************************************
+class UiButton : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ UiButton() {};
+
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ UiButton(const char* str_in, int32_t x, int32_t y, int32_t w, int32_t h,
+ bool is_active = false);
+
+ // *************************************************************************
+ // *** SetParams *******************************************************
+ // *************************************************************************
+ void SetParams(const char* str_in, int32_t x, int32_t y, int32_t w, int32_t h,
+ bool is_active = false);
+
+ // *************************************************************************
+ // *** Set callback function *******************************************
+ // *************************************************************************
+ void SetCallback(void (*clbk)(void* ptr, void* param_ptr, uint32_t param),
+ void* clbk_ptr, void* clbk_param_ptr, uint32_t clbk_param);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void Action(VisObject::ActionType action, int32_t tx, int32_t ty);
+
+ private:
+ // Callback params
+ void (*callback)(void* ptr, void* param_ptr, uint32_t param) = nullptr;
+ void* ptr = nullptr;
+ void* param_ptr = nullptr;
+ uint32_t param = 0U;
+ // String pointer
+ const char* str = nullptr;
+ // Box for button
+ Box box;
+ // String for button
+ String string;
+};
+
+#endif // UiButton_h
diff --git a/UiEngine/UiCheckbox.cpp b/UiEngine/UiCheckbox.cpp
new file mode 100644
index 0000000..c5bf419
--- /dev/null
+++ b/UiEngine/UiCheckbox.cpp
@@ -0,0 +1,99 @@
+//******************************************************************************
+// @file UiCheckbox.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Checkbox Visual Object Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "UiCheckbox.h"
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+UiCheckbox::UiCheckbox(int32_t x, int32_t y, bool is_checked, bool is_active)
+{
+ x_start = x;
+ y_start = y;
+ x_end = x + 13 - 1;
+ y_end = y + 13 - 1;
+ width = 13;
+ height = 13;
+ active = is_active;
+ checked = is_checked;
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void UiCheckbox::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ uint16_t color;
+ // Draw only if needed
+ if((line >= y_start) && (line <= y_end))
+ {
+ // Find start x position
+ int32_t start = x_start - start_x;
+ // Prevent write in memory before buffer
+ if(start < 0) start = 0;
+ // Find start x position
+ int32_t end = x_end - start_x;
+ // Prevent buffer overflow
+ if(end > n) end = n;
+ if(checked) color = COLOR_YELLOW;
+ else color = COLOR_MAGENTA;
+ // Have sense draw only if end pointer in buffer
+ if(x_end > 0)
+ {
+ // If fill or first/last row - must be solid
+ if(true || line == y_start || line == y_end)
+ {
+ for(int32_t i = start; i <= end; i++) buf[i] = color;
+ }
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void UiCheckbox::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ // FIX ME: implement for Vertical Update Mode too
+}
+
+// *****************************************************************************
+// *** Action **************************************************************
+// *****************************************************************************
+void UiCheckbox::Action(VisObject::ActionType action, int32_t tx, int32_t ty)
+{
+ // Switch for process action
+ switch(action)
+ {
+ // Touch action
+ case VisObject::ACT_TOUCH:
+ // Change checked state
+ checked = !checked;
+ break;
+
+ // Untouch action
+ case VisObject::ACT_UNTOUCH:
+ break;
+
+ case VisObject::ACT_MAX:
+ default:
+ break;
+ }
+}
diff --git a/UiEngine/UiCheckbox.h b/UiEngine/UiCheckbox.h
new file mode 100644
index 0000000..175bd89
--- /dev/null
+++ b/UiEngine/UiCheckbox.h
@@ -0,0 +1,89 @@
+//******************************************************************************
+// @file UiCheckbox.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Checkbox Visual Object Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef UiCheckbox_h
+#define UiCheckbox_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "DisplayDrv.h"
+#include "VisObject.h"
+
+// *****************************************************************************
+// *** Checkbox Class ******************************************************
+// *****************************************************************************
+class UiCheckbox : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ UiCheckbox(int32_t x, int32_t y, bool is_checked = false, bool is_active = false);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void Action(VisObject::ActionType action, int32_t tx, int32_t ty);
+
+ private:
+ // Is box checked ?
+ bool checked = false;
+};
+
+#endif // UiCheckbox_h
diff --git a/UiEngine/UiEngine.h b/UiEngine/UiEngine.h
new file mode 100644
index 0000000..c04a48a
--- /dev/null
+++ b/UiEngine/UiEngine.h
@@ -0,0 +1,64 @@
+//******************************************************************************
+// @file UiEngine.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Engine, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef UiEngine_h
+#define UiEngine_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+
+// User Interface elements
+#include "UiButton.h"
+#include "UiCheckbox.h"
+#include "UiScroll.h"
+
+// High level User Interface elements
+#include "UiMenu.h"
+#include "UiMsgBox.h"
+
+#endif // UiEngine_h
diff --git a/UiEngine/UiMenu.cpp b/UiEngine/UiMenu.cpp
new file mode 100644
index 0000000..d45b4d1
--- /dev/null
+++ b/UiEngine/UiMenu.cpp
@@ -0,0 +1,280 @@
+//******************************************************************************
+// @file UiMenu.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Menu Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "UiMenu.h"
+
+// *****************************************************************************
+// *** Public: Menu constructor ********************************************
+// *****************************************************************************
+UiMenu::UiMenu(const char* header_str_in, MenuItem* items_in, int32_t items_cnt_in,
+ int32_t current_pos_in, String::FontType header_font_in,
+ String::FontType items_font_in, int16_t x, int16_t y, int16_t w, int16_t h)
+{
+ // Save input params
+ header_str = header_str_in; // Header string
+ items = items_in; // Items array
+ items_cnt = items_cnt_in; // Items count
+ current_pos = current_pos_in; // Current position
+ header_font = header_font_in; // Header font
+ items_font = items_font_in; // Items font
+ x_start = x; // X position
+ y_start = y; // Y position
+ // If width is 0 - get width of all screen
+ width = w ? w : DisplayDrv::GetInstance().GetScreenW(); // Menu width
+ // If height is 0 - get width of all screen
+ height = h ? h : DisplayDrv::GetInstance().GetScreenH(); // Menu height
+}
+
+// *****************************************************************************
+// *** Public: Main Menu cycle *********************************************
+// *****************************************************************************
+bool UiMenu::Run(void)
+{
+ bool ret = false;
+ int16_t header_height = 0;
+ int16_t start_pos = 0;
+ int16_t menu_count = 0;
+ int16_t scroll_h = 0;
+ int16_t scroll_w = 0;
+ int16_t str_len = 0;
+
+ char tmp_str[64];
+
+ // Checks
+ if(items == nullptr) return false;
+ if(items_cnt == 0) return false;
+
+ // Get header string height
+ if(header_str != nullptr) header_height = String::GetFontH(header_font);
+ // Menu items count fit on the screen
+ menu_count = (height - header_height - 3) / String::GetFontH(items_font);
+ // If screen fit more items than we have - limit it
+ if(menu_count > items_cnt) menu_count = items_cnt;
+ if(menu_count > (int16_t)MAX_MENU_ITEMS) menu_count = MAX_MENU_ITEMS;
+
+ // Height of the Scroll bar: heigth of the Screen - height of the Header
+ scroll_h = height - (header_height + 2);
+ // Width of the Scroll bar: same as Items font width
+ scroll_w = String::GetFontW(items_font) - 2;
+ // Count of characters in the line plus null-terminator
+ str_len = (width - (scroll_w + 2)) / String::GetFontW(items_font) + 1;
+
+ // Menu border
+ box.SetParams(x_start - 1, x_start - 1, width + 2, height + 2, COLOR_GREEN, false);
+ // Show menu border
+ box.Show(100);
+
+ // Create header String object
+ hdr_str.SetParams(header_str, x_start + String::GetFontW(items_font), y_start, COLOR_YELLOW, header_font);
+ // Create header Line object
+ hdr_line.SetParams(x_start, y_start + header_height, width, header_height, COLOR_MAGENTA);
+ // If have caption string
+ if(header_str != nullptr)
+ {
+ hdr_str.Show(100); // Show caption string
+ hdr_line.Show(100); // Show caption line
+ }
+
+ // Create scroll for menu
+ scroll.SetParams(x_start + 1, y_start + height - scroll_h - 1, scroll_w, scroll_h, items_cnt, menu_count, true, false);
+ // Set position
+ scroll.SetScrollPos(current_pos);
+ // Show scroll
+ scroll.Show(1001);
+
+ // Box for selected item
+ selection_bar.SetParams(x_start + String::GetFontW(items_font),
+ y_start + String::GetFontH(items_font) + header_height + 2,
+ width - String::GetFontW(items_font) - 1, String::GetFontH(items_font) - 1,
+ COLOR_RED, true);
+ // Show selection bar
+ selection_bar.Show(100);
+
+ // Strings for menu items
+ String* menu_str[MAX_MENU_ITEMS];
+ char* menu_txt[MAX_MENU_ITEMS];
+
+ // Allocate memory for menu items
+ for(uint32_t i = 0; i < MAX_MENU_ITEMS; i++)
+ {
+ // Create char array for string
+ menu_txt[i] = new char[str_len];
+ // Clear string - add null-terminator in the first position
+ menu_txt[i][0] = '\0';
+ // Create string for menu item
+ menu_str[i] = new String(menu_txt[i], x_start + String::GetFontW(items_font),
+ y_start + String::GetFontH(items_font) * i + header_height + 2,
+ COLOR_CYAN, items_font);
+ // Show string
+ menu_str[i]->Show(101);
+ }
+
+ // Init user input before run Menu cycle
+ InitUserInput();
+
+ do
+ {
+ do
+ {
+ // Lock display because we will change strings content
+ DisplayDrv::GetInstance().LockDisplay();
+ // Draw menu items
+ for(int32_t i = 0; i < menu_count; i++)
+ {
+ // Fill temporary buffer with spaces
+ memset(menu_txt[i], ' ', str_len);
+
+ // If we have function for additional string generate
+ if(items[i+start_pos].GetStr != nullptr)
+ {
+ // Get additional string in the buffer
+ items[i+start_pos].GetStr(items[current_pos].ptr, tmp_str, sizeof(tmp_str), items[i+start_pos].add_param);
+ // Get additional string size
+ uint32_t buf_len = strlen(tmp_str);
+ // Limit string length
+ if(buf_len >= (uint32_t)str_len) buf_len = str_len - 1;
+ // Copy data with right-alligment
+ strncpy(menu_txt[i] + (str_len - buf_len - 1), tmp_str, buf_len - 1);
+ }
+
+ // Copy item to the screen array
+ snprintf(menu_txt[i], str_len, "%s", items[i+start_pos].str);
+ // Remove null-terminator for stick two strings
+ if(strlen(menu_txt[i]) < (size_t)str_len) menu_txt[i][strlen(menu_txt[i])] = ' ';
+ // Set null-terminator at the end
+ menu_txt[i][str_len] = '\0';
+ }
+ // Move selection bar
+ selection_bar.Move(x_start + String::GetFontW(items_font),
+ y_start + String::GetFontH(items_font) * (current_pos - start_pos) + header_height + 2);
+ // Unlock display
+ display_drv.UnlockDisplay();
+ // Refresh display
+ display_drv.UpdateDisplay();
+ // Delay for update screen
+ RtosTick::DelayTicks(100);
+
+ // Process user input
+ ProcessUserInput();
+
+ // If value the same - scroll wasn't touched
+ if(scroll.GetScrollPos() == current_pos)
+ {
+ // Change cursor position if user press UP or DOWN
+ if((kbd_up) && (current_pos > 0)) current_pos--;
+ if((kbd_down) && (current_pos < items_cnt - 1)) current_pos++;
+ // Update scroll value
+ scroll.SetScrollPos(current_pos);
+ }
+ else
+ {
+ // Update menu position from scroll value
+ current_pos = scroll.GetScrollPos();
+ }
+
+ // If cursor out of screen - scroll menu
+ // "while" used instead "if" because position can be changed more than 1
+ // if scroll will be touched
+ while(current_pos < start_pos) start_pos--;
+ while(current_pos > start_pos + menu_count - 1) start_pos++;
+ }
+ while(!(kbd_right || kbd_left));
+
+ // If user pressed ENTER
+ if(kbd_right)
+ {
+ // And we have callback function
+ if(items[current_pos].Callback != nullptr)
+ {
+ // Call it
+ items[current_pos].Callback(items[current_pos].ptr, items[current_pos].add_param);
+ }
+ else // Otherwise
+ {
+ // Set return flag
+ ret = true;
+ // And break cycle to exit
+ break;
+ }
+ }
+ }
+ while(!(kbd_left));
+
+ // Clear memory
+ for(uint32_t i = 0; i < MAX_MENU_ITEMS; i++)
+ {
+ delete(menu_str[i]);
+ delete(menu_txt[i]);
+ }
+
+ // Hide all objects
+ box.Hide();
+ hdr_str.Hide();
+ hdr_line.Hide();
+ selection_bar.Hide();
+ scroll.Hide();
+
+ // Return result
+ return ret;
+}
+
+// *****************************************************************************
+// *** Private: Init user input ********************************************
+// *****************************************************************************
+void UiMenu::InitUserInput(void)
+{
+ // Init last buttons values
+ (void) input_drv.GetButtonState(InputDrv::EXT_LEFT, InputDrv::BTN_UP, up_btn_val);
+ (void) input_drv.GetButtonState(InputDrv::EXT_LEFT, InputDrv::BTN_RIGHT, right_btn_val);
+ (void) input_drv.GetButtonState(InputDrv::EXT_LEFT, InputDrv::BTN_DOWN, down_btn_val);
+ (void) input_drv.GetButtonState(InputDrv::EXT_LEFT, InputDrv::BTN_LEFT, left_btn_val);
+
+ // Init last encoders & buttons values
+ (void) input_drv.GetEncoderState(InputDrv::EXT_LEFT, last_enc_left_val);
+ (void) input_drv.GetEncoderState(InputDrv::EXT_RIGHT, last_enc_right_val);
+ (void) input_drv.GetEncoderButtonState(InputDrv::EXT_LEFT, InputDrv::ENC_BTN_ENT, enc1_btn_left_val);
+ (void) input_drv.GetEncoderButtonState(InputDrv::EXT_RIGHT, InputDrv::ENC_BTN_ENT, enc2_btn_left_val);
+}
+
+// *****************************************************************************
+// *** Private: Process user input *****************************************
+// *****************************************************************************
+void UiMenu::ProcessUserInput(void)
+{
+ // Variable will be set to true if key status changed and new status
+ // empty - only when key will be released
+ if( (input_drv.GetDeviceType(InputDrv::EXT_LEFT) == InputDrv::EXT_DEV_BTN)
+ || (input_drv.GetDeviceType(InputDrv::EXT_LEFT) == InputDrv::EXT_DEV_JOY) )
+ {
+ kbd_up = input_drv.GetButtonState(InputDrv::EXT_LEFT, InputDrv::BTN_UP, up_btn_val) && !up_btn_val;
+ kbd_right = input_drv.GetButtonState(InputDrv::EXT_LEFT, InputDrv::BTN_RIGHT, right_btn_val) && !right_btn_val;
+ kbd_down = input_drv.GetButtonState(InputDrv::EXT_LEFT, InputDrv::BTN_DOWN, down_btn_val) && !down_btn_val;
+ kbd_left = input_drv.GetButtonState(InputDrv::EXT_LEFT, InputDrv::BTN_LEFT, left_btn_val) && !left_btn_val;
+ }
+ // Handle left encoder
+ if(input_drv.GetDeviceType(InputDrv::EXT_LEFT) == InputDrv::EXT_DEV_ENC)
+ {
+ kbd_left = input_drv.GetEncoderButtonState(InputDrv::EXT_LEFT, InputDrv::ENC_BTN_BACK, left_btn_val) && !left_btn_val;
+ kbd_right = input_drv.GetEncoderButtonState(InputDrv::EXT_LEFT, InputDrv::ENC_BTN_ENT, right_btn_val) && !right_btn_val;
+ int32_t enc_val = input_drv.GetEncoderState(InputDrv::EXT_LEFT, last_enc_left_val);
+ kbd_up = (enc_val < 0);
+ kbd_down = (enc_val > 0);
+ }
+}
diff --git a/UiEngine/UiMenu.h b/UiEngine/UiMenu.h
new file mode 100644
index 0000000..6e57062
--- /dev/null
+++ b/UiEngine/UiMenu.h
@@ -0,0 +1,157 @@
+//******************************************************************************
+// @file UiMenu.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Menu Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef UiMenu_h
+#define UiMenu_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "DisplayDrv.h"
+#include "InputDrv.h"
+#include "SoundDrv.h"
+#include "UiEngine.h"
+
+// *****************************************************************************
+// *** Menu Class **********************************************************
+// *****************************************************************************
+class UiMenu
+{
+ public:
+ // *************************************************************************
+ // *** Menu Item description structure *********************************
+ // *************************************************************************
+ typedef struct typeMenuItem
+ {
+ const char* str; // Menu Item caption
+ void (*Callback)(void* ptr, uint32_t param); // Callback for menu item enter
+ char* (*GetStr) (void* ptr, char* buf, uint32_t n, uint32_t add_param); // Callback for string generation
+ void* ptr; // Pointer for callbacks(pointer to object)
+ uint32_t add_param; // Additional params for callbacks
+ } MenuItem;
+
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ UiMenu(const char* header_str_in, MenuItem* items_in, int32_t items_cnt_in,
+ int32_t current_pos_in = 0,
+ String::FontType header_font_in = String::FONT_12x16,
+ String::FontType items_font_in = String::FONT_8x12,
+ int16_t x = 0, int16_t y = 0, int16_t w = 0, int16_t h = 0);
+
+ // *************************************************************************
+ // *** Public: Run menu ************************************************
+ // *************************************************************************
+ bool Run(void);
+
+ // *************************************************************************
+ // *** Public: GetCurrentPosition **************************************
+ // *************************************************************************
+ inline int32_t GetCurrentPosition(void) {return current_pos;};
+
+ private:
+ // Max allowed menu items on the screen
+ static const uint32_t MAX_MENU_ITEMS = 16U;
+
+ const char* header_str; // Menu header
+ String::FontType header_font; // Header font
+ MenuItem* items; // Pointer to Items array
+ int32_t items_cnt; // Items count
+ int32_t current_pos; // Current position
+ String::FontType items_font; // Menu items font
+ int16_t x_start;
+ int16_t y_start;
+ int16_t width;
+ int16_t height;
+
+ // Box across menu
+ Box box;
+ // Header String object
+ String hdr_str;
+ // Header line
+ Line hdr_line;
+ // Box for selected item
+ Box selection_bar;
+ // Scroll
+ UiScroll scroll;
+
+ // Variables for user input
+ bool kbd_up = false;
+ bool kbd_right = false;
+ bool kbd_down = false;
+ bool kbd_left = false;
+ // Last buttons values
+ bool up_btn_val = false;
+ bool right_btn_val = false;
+ bool down_btn_val = false;
+ bool left_btn_val = false;
+ // Last encoders & buttons values
+ int32_t last_enc_left_val = 0;
+ int32_t last_enc_right_val = 0;
+ bool enc1_btn_left_val = false;
+ bool enc2_btn_left_val = false;
+
+ // Display driver instance
+ DisplayDrv& display_drv = DisplayDrv::GetInstance();
+ // Input driver instance
+ InputDrv& input_drv = InputDrv::GetInstance();
+ // Sound driver instance
+ SoundDrv& sound_drv = SoundDrv::GetInstance();
+
+ // *************************************************************************
+ // *** Private: Init user input ****************************************
+ // *************************************************************************
+ void InitUserInput(void);
+
+ // *************************************************************************
+ // *** Private: Process user input *************************************
+ // *************************************************************************
+ void ProcessUserInput(void);
+};
+
+#endif // UiMenu_h
diff --git a/UiEngine/UiMsgBox.cpp b/UiEngine/UiMsgBox.cpp
new file mode 100644
index 0000000..ed683d1
--- /dev/null
+++ b/UiEngine/UiMsgBox.cpp
@@ -0,0 +1,198 @@
+//******************************************************************************
+// @file UiEngine.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Message Box Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "UiEngine.h"
+
+// *****************************************************************************
+// *** Public: MsgBox constructor ******************************************
+// *****************************************************************************
+UiMsgBox::UiMsgBox(const char* msg_in, const char* hdr_in,
+ String::FontType msg_fnt_in, String::FontType hdr_fnt_in,
+ uint16_t center_x_in, uint16_t center_y_in,
+ uint16_t width_in, uint16_t color_in)
+{
+ // Save input params
+ msg = msg_in; // Message
+ msg_fnt = msg_fnt_in; // Message font
+ hdr = hdr_in; // Header string
+ hdr_fnt = hdr_fnt_in; // Header font
+ center_x = center_x_in; // X position of MsgBox center
+ center_y = center_y_in; // Y position of MsgBox center
+ width = width_in; // MsgBox width in characters
+ color = color_in; // Color
+
+ // Variables for store window dimension
+ int16_t X = 0, Y = 0, W = 0, H = 0, StrW = 0;
+ // Pointers to string array
+ char* line[MAX_MSGBOX_LINES];
+ // Strings length array
+ uint8_t length[MAX_MSGBOX_LINES];
+ // Strings count
+ uint8_t count = 0;
+
+ // Pointer to message should present
+ if(msg != nullptr)
+ {
+ // Set fonts by default if isn't provided
+ if(msg_fnt == String::FONTS_MAX) msg_fnt = String::FONT_8x12;
+ if(hdr_fnt == String::FONTS_MAX) hdr_fnt = String::FONT_4x6;
+
+ // Copy string to buffer for split
+ strcpy(str_buf, msg);
+
+ // Set first string to buffer
+ line[count] = str_buf;
+
+ // Find MsgBox width in pixels
+ W = String::GetFontW(msg_fnt) * width;
+
+ // Split buffer to strings
+ while(count < MAX_MSGBOX_LINES)
+ {
+ // Search pointer to '\n' symbol
+ char* ptr = strchr(line[count], (int)'\n');
+
+ // If not found
+ if(ptr == nullptr)
+ {
+ // Set string length with strlen()
+ length[count] = strlen(line[count]);
+ }
+ else
+ {
+ // Calculate string length by pointers difference
+ length[count] = ptr - line[count];
+ // Replace symbol '\n' to '\0' for terminate string
+ *ptr = '\0';
+ }
+
+ // Calculate string width in pixels
+ StrW = String::GetFontW(msg_fnt) * length[count];
+ // If this string width greater than previous - store it
+ if(W < StrW) W = StrW;
+ // Add sting height
+ H += String::GetFontH(msg_fnt);
+
+ // If symbol '\n' isn't found 0 this is last string - exit from the cycle
+ if(ptr == nullptr) break;
+
+ // Increment string counter
+ count++;
+ // Set pointer to the next string
+ line[count] = ptr + 1;
+ }
+
+ if(hdr != nullptr)
+ {
+ // Calculate header width in pixels
+ StrW = String::GetFontW(hdr_fnt) * strlen(hdr);
+ // If header width is greater than string width - store it
+ if(W < StrW) W = StrW;
+ }
+
+ // Add left and right empty space 1 symbol width
+ W += String::GetFontW(msg_fnt) * 2;
+ // Add up and down empty space 0.5 symbol width
+ H += String::GetFontH(msg_fnt);
+
+ // Calculate window position
+ X = center_x - W / 2;
+ Y = center_y - H / 2;
+
+ // Header if present
+ if(hdr != nullptr)
+ {
+ // Move window down
+ Y += String::GetFontH(hdr_fnt) / 2;
+ // Header border
+ box[box_cnt++].SetParams(X - 1, Y - String::GetFontH(hdr_fnt) - 2, W + 1, String::GetFontH(hdr_fnt) + 3, COLOR_MAGENTA, false);
+ // Header place
+ box[box_cnt++].SetParams(X, Y - String::GetFontH(hdr_fnt) - 1, W, String::GetFontH(hdr_fnt) + 1, COLOR_MAGENTA, true);
+ // Header string
+ string[str_cnt++].SetParams(hdr, X + 1, Y - String::GetFontH(hdr_fnt), COLOR_YELLOW, hdr_fnt);
+ }
+
+ // Message place
+ box[box_cnt++].SetParams(X - 1, Y - 1, W + 2, H + 2, COLOR_BLACK, false);
+ // Message border
+ box[box_cnt++].SetParams(X, Y, W, H, COLOR_MAGENTA, false);
+
+ // Set result strings
+ for(uint8_t i = 0; i < count + 1; i++)
+ {
+ // Calculate sting X position
+ X = center_x - (String::GetFontW(msg_fnt) * length[i]) / 2;
+ // Set string params
+ string[str_cnt++].SetParams(line[i], X, Y + String::GetFontH(msg_fnt)/2 + i * String::GetFontH(msg_fnt), COLOR_YELLOW, msg_fnt);
+ }
+ }
+}
+
+// *************************************************************************
+// *** Public: Destructor **********************************************
+// *************************************************************************
+UiMsgBox::~UiMsgBox()
+{
+ // Hide before destruct for memory clean up
+ Hide();
+}
+
+// *****************************************************************************
+// *** Show MsgBox *********************************************************
+// *****************************************************************************
+void UiMsgBox::Show(uint32_t z)
+{
+ for(uint32_t i = 0; i < box_cnt; i++)
+ {
+ box[i].Show(z);
+ }
+ for(uint32_t i = 0; i < str_cnt; i++)
+ {
+ string[i].Show(z + 1U);
+ }
+}
+
+// *****************************************************************************
+// *** Hide MsgBox *********************************************************
+// *****************************************************************************
+void UiMsgBox::Hide(void)
+{
+ // Delete boxes
+ for(uint32_t i = 0; i < box_cnt; i++)
+ {
+ box[i].Hide();
+ }
+ // Delete strings
+ for(uint32_t i = 0; i < str_cnt; i++)
+ {
+ string[i].Hide();
+ }
+}
+
+// *****************************************************************************
+// *** Show and Hide Msg box after pause ***********************************
+// *****************************************************************************
+void UiMsgBox::Run(uint32_t delay)
+{
+ Show();
+ DisplayDrv::GetInstance().UpdateDisplay();
+ RtosTick::DelayMs(delay);
+ Hide();
+}
diff --git a/UiEngine/UiMsgBox.h b/UiEngine/UiMsgBox.h
new file mode 100644
index 0000000..d54a7a0
--- /dev/null
+++ b/UiEngine/UiMsgBox.h
@@ -0,0 +1,128 @@
+//******************************************************************************
+// @file UiMsgBox.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Message Box Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef UiBox_h
+#define UiBox_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "DisplayDrv.h"
+#include "InputDrv.h"
+#include "SoundDrv.h"
+#include "UiEngine.h"
+
+// *****************************************************************************
+// *** Menu Class **********************************************************
+// *****************************************************************************
+class UiMsgBox
+{
+ public:
+ // *************************************************************************
+ // *** Public: Constructor *********************************************
+ // *************************************************************************
+ UiMsgBox(const char* msg_in, const char* hdr_in,
+ String::FontType msg_fnt_in = String::FONTS_MAX,
+ String::FontType hdr_fnt_in = String::FONTS_MAX,
+ uint16_t center_x_in = DisplayDrv::GetInstance().GetScreenW()/2,
+ uint16_t center_y_in = DisplayDrv::GetInstance().GetScreenH()/2,
+ uint16_t width_in = 0, uint16_t color_in = 0);
+
+ // *************************************************************************
+ // *** Public: Destructor **********************************************
+ // *************************************************************************
+ ~UiMsgBox();
+
+ // *************************************************************************
+ // *** Public: Show MsgBox *********************************************
+ // *************************************************************************
+ void Show(uint32_t z = 0xFFFFFFF0);
+
+ // *************************************************************************
+ // *** Public: Hide MsgBox *********************************************
+ // *************************************************************************
+ void Hide(void);
+
+ // *************************************************************************
+ // *** Public: Run MsgBox **********************************************
+ // *************************************************************************
+ void Run(uint32_t delay);
+
+ private:
+ // Max allowed menu items on the screen
+ static const uint32_t MAX_MSGBOX_LINES = 5U;
+
+ // Pointer to message
+ const char* msg;
+ // Message font
+ String::FontType msg_fnt;
+
+ // Pointer to header
+ const char* hdr;
+ // Header font
+ String::FontType hdr_fnt;
+
+ // Position of MsgBox
+ uint16_t center_x;
+ uint16_t center_y;
+ // Width of MsgBox
+ uint16_t width;
+ // Color of MsgBox
+ uint16_t color;
+
+ // Data
+ Box box[4];
+ uint16_t box_cnt = 0;
+ String string[MAX_MSGBOX_LINES + 1U];
+ uint16_t str_cnt = 0;
+
+ // Buffer for stings
+ char str_buf[128];
+};
+
+#endif // UiEngine_h
diff --git a/UiEngine/UiScroll.cpp b/UiEngine/UiScroll.cpp
new file mode 100644
index 0000000..d830be9
--- /dev/null
+++ b/UiEngine/UiScroll.cpp
@@ -0,0 +1,220 @@
+//******************************************************************************
+// @file UiScroll.cpp
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Scroll Visual Object Class, implementation
+//
+// @copyright Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// All rights reserved.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "UiScroll.h"
+
+// *****************************************************************************
+// *** Constructor *********************************************************
+// *****************************************************************************
+UiScroll::UiScroll(int32_t x, int32_t y, int32_t w, int32_t h, int32_t n, int32_t bar,
+ bool is_vertical, bool is_has_buttons, bool is_active)
+{
+ SetParams(x, y, w, h, n, bar, is_vertical, is_has_buttons, is_active);
+}
+
+// *****************************************************************************
+// *** SetParams *********************************************************
+// *****************************************************************************
+void UiScroll::SetParams(int32_t x, int32_t y, int32_t w, int32_t h, int32_t n, int32_t bar,
+ bool is_vertical, bool is_has_buttons, bool is_active)
+{
+ // General params
+ x_start = x;
+ y_start = y;
+ x_end = x + w - 1;
+ y_end = y + h - 1;
+ width = w;
+ height = h;
+ active = is_active;
+ // Private params
+ cnt = 0;
+ total_cnt = n;
+ bar_cnt = bar;
+ vertical = is_vertical;
+ has_buttons = is_has_buttons;
+ // Calculated data for drawing
+ bar_shift = 1;
+ total_len = (vertical ? height : width) - 2; // Total length for bar
+ // Vertical with buttons
+ if(has_buttons && vertical)
+ {
+ total_len -= width*2;
+ bar_shift = width + 1;
+ }
+ // Horizontal with buttons
+ if(has_buttons && !vertical)
+ {
+ total_len -= height*2;
+ bar_shift = height + 1;
+ }
+ if(bar_cnt > total_cnt) bar_cnt = total_cnt; // Bar can't be greater total len
+ bar_len = (total_len * bar_cnt) / total_cnt; // Bar length
+ if(bar_len == 0) bar_len = 1; // Bar height can't be less than 1
+ empty_len = total_len - bar_len; // Empty length available for bar moving
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void UiScroll::DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t start_x)
+{
+ // FIX ME: TEMPORARY COLOR !!!
+ uint16_t color = COLOR_YELLOW;
+ // Draw only if needed
+ if((line >= y_start) && (line <= y_end))
+ {
+ // Find start x position
+ int32_t start = x_start - start_x;
+ // Prevent write in memory before buffer
+ if(start < 0) start = 0;
+ // Find start x position
+ int32_t end = x_end - start_x;
+ // Prevent buffer overflow
+ if(end > n) end = n;
+
+ // Have sense draw only if end pointer in buffer
+ if(x_end > 0)
+ {
+ // Draw border of scroll
+ if((line == y_start) || (line == y_end))
+ {
+ for(int32_t i = start; i <= end; i++) buf[i] = color;
+ }
+ else if( (has_buttons == true) && (vertical == true)
+ && ((line == y_start + width) || (line == y_end - width + 1)) )
+ {
+ for(int32_t i = start; i <= end; i++) buf[i] = color;
+ }
+ else
+ {
+ if(x_start >= 0) buf[x_start] = color;
+ if(x_end < n) buf[x_end] = color;
+ if(has_buttons && !vertical)
+ {
+ if(x_start + height >= 0) buf[x_start + height] = color;
+ if(x_end - height < n) buf[x_end - height] = color;
+ }
+ }
+ // Find start of bar position
+ int32_t bar_start = bar_shift;
+ // Add bar additional shift
+ bar_start += (empty_len * cnt) / (total_cnt - 1);
+ if(vertical)
+ {
+ bar_start += y_start;
+ // Draw bar line
+ if((line >= bar_start) && (line < bar_start + bar_len))
+ {
+ for(int32_t i = start+1; i <= end-1; i++) buf[i] = COLOR_MAGENTA;
+ }
+ }
+ else
+ {
+ if((line != y_start) && (line != y_end))
+ {
+ bar_start += x_start;
+ // Prevent write in memory before buffer
+ if(bar_start < 0) bar_start = 0;
+ // Find start x position
+ int32_t bar_end = bar_start + bar_len;
+ // Prevent buffer overflow
+ if(bar_end > n) bar_end = n;
+ // Draw line
+ for(int32_t i = bar_start; i < bar_end; i++) buf[i] = COLOR_MAGENTA;
+ }
+ }
+ }
+ }
+}
+
+// *****************************************************************************
+// *** Put line in buffer **************************************************
+// *****************************************************************************
+void UiScroll::DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t start_y)
+{
+ // FIX ME: implement for Vertical Update Mode too
+}
+
+// *****************************************************************************
+// *** Action **************************************************************
+// *****************************************************************************
+void UiScroll::Action(VisObject::ActionType action, int32_t tx, int32_t ty)
+{
+ // Switch for process action
+ switch(action)
+ {
+ // Touch action
+ case VisObject::ACT_TOUCH:
+ // Button touch processing
+ if(has_buttons == true)
+ {
+ // If touched less than start pos plus width/height, we touch in square DEC btn
+ if( ( vertical && (ty < y_start + bar_shift))
+ || (!vertical && (tx < x_start + bar_shift)) )
+ {
+ // Decrease counter
+ cnt--;
+ // If counter less than zero - correct it
+ if(cnt < 0) cnt = 0;
+ }
+ // If touched greater than end pos minus width, we touch in square INC btn
+ if( ( vertical && (ty > y_end - bar_shift))
+ || (!vertical && (tx > x_end - bar_shift)) )
+ {
+ // Increase counter
+ cnt++;
+ // If counter less than total count minus bar count - correct it
+ if(cnt >= total_cnt) cnt = total_cnt-1;
+ }
+ }
+ // Touch directly to bar
+ if(vertical)
+ {
+ // Check touch in bar area
+ if((ty > y_start + bar_shift) && (ty < y_end - bar_shift))
+ {
+ // Find press coordinates from bar start position
+ int32_t press = (ty - y_start - bar_shift);
+ // Calculate new count value
+ cnt = (press * total_cnt) / total_len;
+ }
+ }
+ else
+ {
+ // Check touch in bar area
+ if((tx > x_start + bar_shift) && (tx < x_end - bar_shift))
+ {
+ // Find press coordinates from bar start position
+ int32_t press = (tx - x_start - bar_shift);
+ // Calculate new count value
+ cnt = (press * total_cnt) / total_len;
+ }
+ }
+ break;
+
+ // Untouch action
+ case VisObject::ACT_UNTOUCH:
+ break;
+
+ case VisObject::ACT_MAX:
+ default:
+ break;
+ }
+}
diff --git a/UiEngine/UiScroll.h b/UiEngine/UiScroll.h
new file mode 100644
index 0000000..387060b
--- /dev/null
+++ b/UiEngine/UiScroll.h
@@ -0,0 +1,126 @@
+//******************************************************************************
+// @file UiScroll.h
+// @author Nicolai Shlapunov
+//
+// @details DevCore: UI Scroll Visual Object Class, header
+//
+// @section LICENSE
+//
+// Software License Agreement (Modified BSD License)
+//
+// Copyright (c) 2016, Devtronic & Nicolai Shlapunov
+// 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 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 the Devtronic nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+// 4. Redistribution and use of this software other than as permitted under
+// this license is void and will automatically terminate your rights under
+// this license.
+//
+// THIS SOFTWARE IS PROVIDED BY DEVTRONIC ''AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL DEVTRONIC 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
+// 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.
+//
+// @section SUPPORT
+//
+// Devtronic invests time and resources providing this open source code,
+// please support Devtronic and open-source hardware/software by
+// donations and/or purchasing products from Devtronic.
+//
+//******************************************************************************
+
+#ifndef UiScroll_h
+#define UiScroll_h
+
+// *****************************************************************************
+// *** Includes ************************************************************
+// *****************************************************************************
+#include "DevCfg.h"
+#include "DisplayDrv.h"
+#include "VisObject.h"
+
+// *****************************************************************************
+// *** Scroll Class ********************************************************
+// *****************************************************************************
+class UiScroll : public VisObject
+{
+ public:
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ UiScroll() {};
+
+ // *************************************************************************
+ // *** Constructor *****************************************************
+ // *************************************************************************
+ UiScroll(int32_t x, int32_t y, int32_t w, int32_t h, int32_t n, int32_t bar,
+ bool is_vertical = true, bool is_has_buttons = false, bool is_active = true);
+
+ // *************************************************************************
+ // *** SetParams *******************************************************
+ // *************************************************************************
+ void SetParams(int32_t x, int32_t y, int32_t w, int32_t h, int32_t n,
+ int32_t bar, bool is_vertical = true,
+ bool is_has_buttons = false, bool is_active = true);
+
+ // *************************************************************************
+ // *** Return End X coordinate *****************************************
+ // *************************************************************************
+ int32_t GetScrollPos(void) {return cnt;};
+
+ // *************************************************************************
+ // *** Return End Y coordinate *****************************************
+ // *************************************************************************
+ void SetScrollPos(int32_t pos) {cnt = pos;};
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufH(uint16_t* buf, int32_t n, int32_t row, int32_t y = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void DrawInBufW(uint16_t* buf, int32_t n, int32_t line, int32_t x = 0);
+
+ // *************************************************************************
+ // *** Put line in buffer **********************************************
+ // *************************************************************************
+ virtual void Action(VisObject::ActionType action, int32_t tx, int32_t ty);
+
+ private:
+ // Current position
+ int32_t cnt = 0;
+ // Total count
+ int32_t total_cnt = 0;
+ // number of records "shows" on the screen for properly scale bar
+ int32_t bar_cnt = 0;
+ // Is scroll vertical?
+ bool vertical = false;
+ // Is has buttons
+ bool has_buttons = false;
+
+ // Calculated data
+ int16_t bar_shift = 0; // Bar initial shift for skip button place
+ int16_t total_len = 0; // Total length for bar
+ int16_t bar_len = 0; // Bar length
+ int16_t empty_len = 0; // Empty length available for bar moving
+};
+
+#endif // UiScroll_h