Rebuild logic -> use 'cacheMemLcd' array which is depicted with UpdateScreen function

This commit is contained in:
matiasus 2021-07-20 10:59:08 +02:00
parent 88c5722b37
commit 4443ee380d
5 changed files with 143 additions and 632 deletions

View File

@ -16,7 +16,7 @@
#include "font.h"
/** @array Charset */
const uint8_t FONTS[][5] PROGMEM = {
const uint8_t FONTS[][CHARS_COLS_LENGTH] PROGMEM = {
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // 20 space
{ 0x81, 0x81, 0x18, 0x81, 0x81 }, // 21 !
{ 0x00, 0x07, 0x00, 0x07, 0x00 }, // 22 "

View File

@ -9,12 +9,13 @@
* @datum 06.10.2020
* @update 19.07.2021
* @file ssd1306.c
* @version 2.0
* @tested AVR Atmega328
*
* @depend font.h, twi.h
* ---------------------------------------------------------------+
* @descr Version 1.0 -> applicable for 1 display
* Version 2.0 -> applicable for more than 1 display
* Version 2.0 -> rebuild to 'cacheMemLcd' array
* ---------------------------------------------------------------+
* @usage Basic Setup for OLED Display
*/
@ -159,10 +160,6 @@ static char cacheMemLcd[CACHE_SIZE_MEM];
// @var global - set area
unsigned int set_area = (END_PAGE_ADDR - START_PAGE_ADDR + 1) * (END_COLUMN_ADDR - START_COLUMN_ADDR + 1);
// @var global - cache index column
unsigned short int indexCol = START_COLUMN_ADDR;
// @var global - cache index page
unsigned short int indexPage = START_PAGE_ADDR;
/**
* @desc SSD1306 Init
@ -274,7 +271,7 @@ uint8_t SSD1306_Send_StartAndSLAW (uint8_t address)
/**
* @desc SSD1306 Send command
*
* @param uint8_t
* @param uint8_t command
*
* @return uint8_t
*/
@ -306,7 +303,7 @@ uint8_t SSD1306_Send_Command (uint8_t command)
}
/**
* @desc SSD1306 Normal Colors
* @desc SSD1306 Normal colors
*
* @param uint8_t address
*
@ -340,7 +337,7 @@ uint8_t SSD1306_NormalScreen (uint8_t address)
}
/**
* @desc SSD1306 Inverse Colors
* @desc SSD1306 Inverse colors
*
* @param uint8_t address
*
@ -374,7 +371,7 @@ uint8_t SSD1306_InverseScreen (uint8_t address)
}
/**
* @desc SSD1306 Update Screen On
* @desc SSD1306 Update screen
*
* @param uint8_t address
*
@ -429,294 +426,56 @@ uint8_t SSD1306_UpdateScreen (uint8_t address)
/**
* @desc SSD1306 Send Command
*
* @param uint8_t address
* @param void
*
* @return void
*/
void SSD1306_ClearScreen (uint8_t address)
void SSD1306_ClearScreen (void)
{
// init status
uint8_t status = INIT_STATUS;
//short int i = 0;
// null cache memory lcd
memset (cacheMemLcd, 0x00, CACHE_SIZE_MEM);
/*
// update - null col, increment page
status = SSD1306_SetPosition (address, 0, 0);
// request
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// TWI: start & SLAW
// -------------------------
status = SSD1306_Send_StartAndSLAW (address);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// control byte data stream
// -------------------------
status = TWI_MT_Send_Data (SSD1306_DATA_STREAM);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// erase whole area
// -------------------------
while (i < set_area) {
// send null data
status = TWI_MT_Send_Data (0x00);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// increment
i++;
}
// stop TWI
TWI_Stop ();
*/
// success
return SSD1306_SUCCESS;
}
/**
* @desc SSD1306 Set Poisition
* @desc SSD1306 Set position
*
* @param uint8_t address
* @param uint8_t
* @param uint8_t
* @param uint8_t column -> 0 ... 127
* @param uint8_t page -> 0 ... 7
*
* @return uint8_t
* @return void
*/
uint8_t SSD1306_SetPosition (uint8_t address, uint8_t x, uint8_t y)
void SSD1306_SetPosition (uint8_t x, uint8_t y)
{
// variables
uint8_t status = INIT_STATUS;
// TWI: start & SLAW
// -------------------------
status = SSD1306_Send_StartAndSLAW (address);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// SET COLUMN address
// ***************************************************
// set column addr
// -------------------------
status = SSD1306_Send_Command (SSD1306_SET_COLUMN_ADDR);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// start COLUMN
// -------------------------
status = SSD1306_Send_Command (x);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// end COLUMN
// -------------------------
status = SSD1306_Send_Command (END_COLUMN_ADDR);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// update column index
indexCol = x;
// SET PAGE address
// ***************************************************
// set page addr
// -------------------------
status = SSD1306_Send_Command (SSD1306_SET_PAGE_ADDR);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// start PAGE
// -------------------------
status = SSD1306_Send_Command (y);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// end PAGE
// -------------------------
status = SSD1306_Send_Command (END_PAGE_ADDR);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// update column index
indexPage = y;
// stop TWI
TWI_Stop ();
// success
return SSD1306_SUCCESS;
// counter
_counter = x + (y << 7);
}
/**
* @desc SSD1306 Check Text Poisition
*
* @param uint8_t address
* @param void
*
* @return uint8_t
*/
uint8_t SSD1306_UpdTxtPosition (uint8_t address)
uint8_t SSD1306_UpdTxtPosition (void)
{
// init status
uint8_t status = INIT_STATUS;
// check end column position
unsigned short int x = indexCol + CHARS_COLS_LENGTH + 1;
uint8_t y = _counter >> 7;
uint8_t x = _counter - (y << 7);
uint8_t x_new = x + CHARS_COLS_LENGTH + 1;
// check position
if ((x > END_COLUMN_ADDR) && (indexPage > (END_PAGE_ADDR - 1))) {
// return out of range
return SSD1306_ERROR;
// if x out reach end but page in range
} else if ((x > END_COLUMN_ADDR) && (indexPage < END_PAGE_ADDR)) {
// update - column
indexCol = 0;
// update - page
indexPage = indexPage + 1;
// update - null col, increment page
status = SSD1306_SetPosition (address, indexCol, indexPage);
// request
if (SSD1306_SUCCESS != status) {
// error
return status;
}
}
// success
return SSD1306_SUCCESS;
}
/**
* @desc Send 1 Byte of data
*
* @param uint8_t address
* @param uint8_t data
*
* @return void
*/
uint8_t SSD1306_SendByte (uint8_t address, uint8_t data)
{
// init status
uint8_t status = INIT_STATUS;
// TWI: start & SLAW
// -------------------------
status = SSD1306_Send_StartAndSLAW (address);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// control byte data stream
// -------------------------
status = TWI_MT_Send_Data (SSD1306_DATA_STREAM);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// send byte of data
// -------------------------
status = TWI_MT_Send_Data (data);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// increment global index col
indexCol = indexCol + 1;
// stop TWI
TWI_Stop ();
// success
return SSD1306_SUCCESS;
}
/**
* @desc Send same bytes
*
* @param uint8_t address
* @param uint8_t data
* @param uint8_t length
*
* @return void
*/
uint8_t SSD1306_SendSameBytes (uint8_t address, uint8_t data, uint8_t length)
{
// index
unsigned short int i = 0;
// init status
uint8_t status = INIT_STATUS;
// TWI: start & SLAW
// -------------------------
status = SSD1306_Send_StartAndSLAW (address);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// control byte data stream
// -------------------------
status = TWI_MT_Send_Data (SSD1306_DATA_STREAM);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// loop through data
while (i++ < length) {
// draw line only within 1 page
if (indexCol < MAX_X) {
// send byte of data
// -------------------------
status = TWI_MT_Send_Data (data);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// increment global index col
indexCol = indexCol + 1;
} else {
// end loop
break;
if (x_new > END_COLUMN_ADDR) {
// if more than numbre of pages
if (y > END_PAGE_ADDR) {
// return out of range
return SSD1306_ERROR;
// if x out reach end but page in range
} else if (y < (END_PAGE_ADDR-1)) {
// update
_counter = ((++y) << 7);
}
}
// stop TWI
TWI_Stop ();
// success
return SSD1306_SUCCESS;
}
@ -724,70 +483,29 @@ uint8_t SSD1306_SendSameBytes (uint8_t address, uint8_t data, uint8_t length)
/**
* @desc Draw character
*
* @param uint8_t address
* @param char character
*
* @return uint8_t
*/
uint8_t SSD1306_DrawChar (uint8_t address, char character)
uint8_t SSD1306_DrawChar (char character)
{
// variables
uint8_t idxCol = 0;
// init status
uint8_t status = INIT_STATUS;
uint8_t i = 0;
// update text position
if (SSD1306_UpdTxtPosition (address) != SSD1306_SUCCESS) {
if (SSD1306_UpdTxtPosition () == SSD1306_ERROR) {
// error
return SSD1306_ERROR;
}
// TWI: start & SLAW
// -------------------------
status = SSD1306_Send_StartAndSLAW (address);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// control byte data stream
// -------------------------
status = TWI_MT_Send_Data (SSD1306_DATA_STREAM);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// loop through 5 bits
while (idxCol < CHARS_COLS_LENGTH) {
// send control byte data
// -------------------------
status = TWI_MT_Send_Data (pgm_read_byte(&FONTS[character-32][idxCol]));
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// increment
idxCol++;
while (i < CHARS_COLS_LENGTH) {
// read byte
cacheMemLcd[_counter++] = pgm_read_byte(&FONTS[character-32][i++]);
}
// empty column
// -------------------------
status = TWI_MT_Send_Data (CLEAR_COLOR);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// increment global index col
indexCol = indexCol + CHARS_COLS_LENGTH + 1;
// stop TWI
TWI_Stop ();
// update position
_counter++;
// success
return SSD1306_SUCCESS;
@ -796,46 +514,31 @@ uint8_t SSD1306_DrawChar (uint8_t address, char character)
/**
* @desc SSD1306 Draw String
*
* @param uint8_t address
* @param char * string
*
* @return void
*/
uint8_t SSD1306_DrawString (uint8_t address, char *str)
void SSD1306_DrawString (char *str)
{
// init status
uint8_t status = INIT_STATUS;
// init
int i = 0;
// loop through character of string
while (str[i] != '\0') {
// draw string
status = SSD1306_DrawChar (address, str[i++]);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
SSD1306_DrawChar (str[i++]);
}
// success
return SSD1306_SUCCESS;
}
/**
* @desc Draw pixel
*
* @param uint8_t
* @param uint8_t
* @param uint8_t
* @param uint8_t x -> 0 ... MAX_X
* @param uint8_t y -> 0 ... MAX_Y
*
* @return void
* @return uint8_t
*/
uint8_t SSD1306_DrawPixel (uint8_t address, uint8_t x, uint8_t y)
uint8_t SSD1306_DrawPixel (uint8_t x, uint8_t y)
{
// variables
uint8_t status = INIT_STATUS;
uint8_t page = 0;
uint8_t pixel = 0;
@ -848,96 +551,10 @@ uint8_t SSD1306_DrawPixel (uint8_t address, uint8_t x, uint8_t y)
page = y >> 3;
// which pixel (y % 8)
pixel = 1 << (y - (page << 3));
// TWI: start & SLAW
// -------------------------
status = SSD1306_Send_StartAndSLAW (address);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// SET COLUMN address
// ***************************************************
// set column addr
// -------------------------
status = SSD1306_Send_Command (SSD1306_SET_COLUMN_ADDR);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// start COLUMN
// -------------------------
status = SSD1306_Send_Command (x);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// end COLUMN
// -------------------------
status = SSD1306_Send_Command (END_COLUMN_ADDR);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// update column index
indexCol = x;
// SET PAGE address
// ***************************************************
// set page addr
// -------------------------
status = SSD1306_Send_Command (SSD1306_SET_PAGE_ADDR);
// request - start TWI
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// start PAGE
// -------------------------
status = SSD1306_Send_Command (page);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// end PAGE
// -------------------------
status = SSD1306_Send_Command (END_PAGE_ADDR);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// update column index
indexPage = y;
// ------------------------------------------------------
// control byte data stream
status = TWI_MT_Send_Data (SSD1306_DATA_STREAM);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// send byte of data
status = TWI_MT_Send_Data (pixel);
// request success
if (SSD1306_SUCCESS != status) {
// error
return status;
}
// increment global index col
indexCol = indexCol + 1;
// ------------------------------------------------------
// stop TWI
TWI_Stop ();
// update counter
_counter = x + (page << 7);
// save pixel
cacheMemLcd[_counter++] |= pixel;
// success
return SSD1306_SUCCESS;
@ -947,7 +564,6 @@ uint8_t SSD1306_DrawPixel (uint8_t address, uint8_t x, uint8_t y)
* @desc Draw line by Bresenham algoritm
* @surce https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
*
* @param uint8_t address
* @param uint8_t x start position / 0 <= cols <= MAX_X-1
* @param uint8_t x end position / 0 <= cols <= MAX_X-1
* @param uint8_t y start position / 0 <= rows <= MAX_Y-1
@ -955,7 +571,7 @@ uint8_t SSD1306_DrawPixel (uint8_t address, uint8_t x, uint8_t y)
*
* @return uint8_t
*/
uint8_t SSD1306_DrawLine (uint8_t address, uint8_t x1, uint8_t x2, uint8_t y1, uint8_t y2)
uint8_t SSD1306_DrawLine (uint8_t x1, uint8_t x2, uint8_t y1, uint8_t y2)
{
// determinant
int16_t D;
@ -990,7 +606,7 @@ uint8_t SSD1306_DrawLine (uint8_t address, uint8_t x1, uint8_t x2, uint8_t y1, u
// calculate determinant
D = (delta_y << 1) - delta_x;
// draw first pixel
SSD1306_DrawPixel (address, x1, y1);
SSD1306_DrawPixel (x1, y1);
// check if x1 equal x2
while (x1 != x2) {
// update x1
@ -1005,14 +621,14 @@ uint8_t SSD1306_DrawLine (uint8_t address, uint8_t x1, uint8_t x2, uint8_t y1, u
// update deteminant
D += 2*delta_y;
// draw next pixel
SSD1306_DrawPixel (address, x1, y1);
SSD1306_DrawPixel (x1, y1);
}
// for m > 1 (dy > dx)
} else {
// calculate determinant
D = delta_y - (delta_x << 1);
// draw first pixel
SSD1306_DrawPixel (address, x1, y1);
SSD1306_DrawPixel (x1, y1);
// check if y2 equal y1
while (y1 != y2) {
// update y1
@ -1027,44 +643,9 @@ uint8_t SSD1306_DrawLine (uint8_t address, uint8_t x1, uint8_t x2, uint8_t y1, u
// update deteminant
D -= 2*delta_x;
// draw next pixel
SSD1306_DrawPixel (address, x1, y1);
SSD1306_DrawPixel (x1, y1);
}
}
// success return
return SSD1306_SUCCESS;
}
/**
* @desc Draw horizontal line
*
* @param uint8_t address
* @param uint8_t
* @param uint8_t
* @param uint8_t
*
* @return void
*/
uint8_t SSD1306_DrawLineHorizontal (uint8_t address, uint8_t x, uint8_t y, uint8_t len)
{
uint8_t page = 0;
uint8_t pixel = 0;
// if out of range
if ((x > MAX_X) && (y > MAX_Y)) {
// out of range
return SSD1306_ERROR;
}
// find page (y / 8)
page = y >> 3;
// which pixel (y % 8)
pixel |= 1 << (y - (page << 3));
// send position
SSD1306_SetPosition (address, x, page);
// draw pixel
SSD1306_SendSameBytes (address, pixel, len);
// success
return SSD1306_SUCCESS;
}

View File

@ -9,12 +9,13 @@
* @datum 06.10.2020
* @update 19.07.2021
* @file ssd1306.h
* @version 2.0
* @tested AVR Atmega328
*
* @depend font.h, twi.h
* ---------------------------------------------------------------+
* @descr Version 1.0 -> applicable for 1 display
* Version 2.0 -> applicable for more than 1 display
* Version 2.0 -> rebuild to 'cacheMemLcd' array
* ---------------------------------------------------------------+
* @usage Basic Setup for OLED Display
*/
@ -86,12 +87,11 @@
#define MAX_X END_COLUMN_ADDR
#define MAX_Y (END_PAGE_ADDR+1)*8
// @var set area
unsigned int _counter;
// @var set area
unsigned int set_area;
// @var cache index column
unsigned short int indexCol;
// @var cache index page
unsigned short int indexPage;
/**
* @desc SSD1306 Init - set frequency
@ -123,11 +123,11 @@
/**
* @desc SSD1306 Clear Screen
*
* @param uint8_t
* @param void
*
* @return uint8_t
* @return void
*/
uint8_t SSD1306_ClearScreen (uint8_t);
void SSD1306_ClearScreen (void);
/**
* @desc SSD1306 Normal Colors
@ -148,47 +148,44 @@
uint8_t SSD1306_InverseScreen (uint8_t);
/**
* @desc SSD1306 Check Text Position
* @desc SSD1306 Update text position
*
* @param uint8_t
* @param void
*
* @return uint8_t
*/
uint8_t SSD1306_UpdTxtPosition (uint8_t);
uint8_t SSD1306_UpdTxtPosition (void);
/**
* @desc SSD1306 Set Position
* @desc SSD1306 Set position
*
* @param uint8_t
* @param uint8_t
* @param uint8_t
*
* @return char
* @return void
*/
uint8_t SSD1306_SetPosition (uint8_t, uint8_t, uint8_t);
void SSD1306_SetPosition (uint8_t, uint8_t);
/**
* @desc SSD1306 Draw Character
* @desc SSD1306 Draw character
*
* @param uint8_t
* @param char
*
* @return uint8_t
*/
uint8_t SSD1306_DrawChar (uint8_t, char);
uint8_t SSD1306_DrawChar (char);
/**
* @desc SSD1306 Draw String
* @desc SSD1306 Draw string
*
* @param uint8_t
* @param char *
*
* @return uint8_t
* @return void
*/
uint8_t SSD1306_DrawString (uint8_t, char *);
void SSD1306_DrawString (char *);
/**
* @desc SSD1306 Update Screen On
* @desc SSD1306 Update screen
*
* @param uint8_t
*
@ -210,11 +207,10 @@
*
* @param uint8_t
* @param uint8_t
* @param uint8_t
*
* @return void
* @return uint8_t
*/
uint8_t SSD1306_DrawPixel (uint8_t, uint8_t, uint8_t);
uint8_t SSD1306_DrawPixel (uint8_t, uint8_t);
/**
* @desc Draw line
@ -223,43 +219,9 @@
* @param uint8_t
* @param uint8_t
* @param uint8_t
* @param uint8_t
*
* @return uint8_t
*/
uint8_t SSD1306_DrawLine (uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
/**
* @desc SSD1306 Draw line horizontal
*
* @param uint8_t
* @param uint8_t
* @param uint8_t
* @param uint8_t
*
* @return void
*/
uint8_t SSD1306_DrawLineHorizontal (uint8_t, uint8_t, uint8_t, uint8_t);
/**
* @desc SSD1306 Send byte
*
* @param uint8_t
* @param uint8_t
*
* @return void
*/
uint8_t SSD1306_SendByte (uint8_t, uint8_t);
/**
* @desc SSD1306 Send same bytes
*
* @param uint8_t
* @param uint8_t
* @param uint8_t
*
* @return uint8_t
*/
uint8_t SSD1306_SendSameBytes (uint8_t, uint8_t, uint8_t);
uint8_t SSD1306_DrawLine (uint8_t, uint8_t, uint8_t, uint8_t);
#endif

38
main.c
View File

@ -14,7 +14,7 @@
* @depend ssd1306.h
* ---------------------------------------------------------------+
* @descr Version 1.0 -> applicable for 1 display
* Version 2.0 -> applicable for more than 1 display
* Version 2.0 -> rebuild to 'cacheMemLcd' array
* ---------------------------------------------------------------+
*/
@ -37,29 +37,27 @@ int main(void)
SSD1306_Init (addr);
// clear screen
SSD1306_ClearScreen (addr);
SSD1306_ClearScreen ();
// clear screen
SSD1306_ClearScreen ();
// draw line
//SSD1306_DrawLineHorizontal (addr, 4, 4, 115);
// set position x, y
//SSD1306_SetPosition (addr, 1, 1);
//for (char i = 1; i < MAX_Y; i++) {
SSD1306_DrawPixel (addr, 0, 0);
SSD1306_DrawPixel (addr, 0, 1);
SSD1306_DrawPixel (addr, 0, 2);
SSD1306_DrawPixel (addr, 1, 1);
SSD1306_DrawPixel (addr, 2, 2);
SSD1306_DrawPixel (addr, 3, 3);
SSD1306_DrawPixel (addr, 4, 4);
//SSD1306_DrawLine (addr, 0, MAX_X-1, MAX_Y-1, MAX_Y-1);
//}
SSD1306_DrawLine (0, MAX_X, 4, 4);
// set position
SSD1306_SetPosition (7, 1);
// draw string
//SSD1306_DrawString (addr, "SSD1306 OLED DRIVER");
SSD1306_DrawString ("SSD1306 OLED DRIVER");
// draw line
//SSD1306_DrawLineHorizontal (addr, 4, 18, 115);
SSD1306_DrawLine (0, MAX_X, 18, 18);
// set position
SSD1306_SetPosition (40, 3);
// draw string
SSD1306_DrawString ("MATIASUS");
// set position
SSD1306_SetPosition (53, 5);
// draw string
SSD1306_DrawString ("2021");
// update
//SSD1306_UpdateScreen (addr);
SSD1306_UpdateScreen (addr);
// return value
return 0;

126
main.hex
View File

@ -38,10 +38,10 @@
:10025000000221007F02220007004001D30000A11C
:1002600000C801DA1201817F00A400A601D5800137
:10027000D9C201DB20018D1400AF11241FBECFEFC6
:10028000D8E0DEBFCDBF11E0A0E0B1E0E6EEF8E0DF
:1002900002C005900D92A230B107D9F725E0A2E087
:1002A000B1E001C01D92A630B207E1F70E944504FB
:1002B0000C9471040C94000083E08093B800E9EB87
:10028000D8E0DEBFCDBF11E0A0E0B1E0EAEEF6E0DD
:1002900002C005900D92A432B107D9F725E0A4E27F
:1002A000B1E001C01D92A632B207E1F70E944203FD
:1002B0000C9473030C94000083E08093B800E9EB86
:1002C000F0E08081908182708160892B8083089525
:1002D0008091B90087758093B90084EA8093BC004F
:1002E0008091BC0087FFFCCF8091B900887F883067
@ -68,78 +68,48 @@
:10043000811103C086EA0C94D40108950E94C8017A
:10044000811103C087EA0C94D4010895CF93DF9300
:100450000E94C801811113C080E40E94990181119A
:100460000EC0C6E0D1E089910E949901811107C0B8
:1004700085E0C630D807B9F70E94C40180E0DF915B
:10048000CF91089580E094E0E6E0F1E0DF019C0187
:100490001D9221503040E1F780E00895CF93DF9323
:1004A000D62FC42F0E94C80181112DC081E20E9465
:1004B000D401811128C08D2F0E94D401811123C045
:1004C0008FE70E94D40181111EC06D2F70E07093E0
:1004D00005016093040182E20E94D401811113C0DE
:1004E0008C2F0E94D40181110EC087E00E94D4019C
:1004F000811109C04C2F50E0509303014093020139
:100500000E94C40180E0DF91CF9108952091040101
:10051000309105012A5F3F4F20383105A0F040910E
:100520000201509103014730510578F41092050102
:10053000109204014F5F5F4F5093030140930201FB
:1005400060E00C944E0280E0089581E00895CF931E
:10055000C62F0E94C801811116C080E40E94990133
:10056000811111C08C2F0E94990181110CC08091C2
:100570000401909105010196909305018093040177
:100580000E94C40180E0CF910895FF920F931F93C2
:10059000CF93DF93F62EC42F0E94C801811126C08D
:1005A00080E40E949901811121C000E010E0D0E0B8
:1005B0000C171D07C0F480910401909105018F373D
:1005C000910588F48F2D0E9499010F5F1F4F8111B3
:1005D0000DC0809104019091050101969093050151
:1005E00080930401E5CF0E94C40180E0DF91CF91A8
:1005F0001F910F91FF9008950F931F93CF93DF9357
:10060000D82FC62F0E948602811132C08D2F0E94E2
:10061000C80181112EC080E40E949901811129C076
:1006200085E0C802E001112400E010E0C05AD109C1
:10063000FE01E00FF11FE859FF4F84910E949901DC
:10064000811117C00F5F1F4F0530110589F70E94F8
:10065000990181110EC080910401909105010696C7
:1006600090930501809304010E94C40180E001C0C1
:1006700081E0DF91CF911F910F9108951F93CF9348
:10068000DF93182FEB016991662331F0812F0E94CF
:10069000FC028823C1F301C080E0DF91CF911F915C
:1006A00008951F93CF93DF9367FF03C0413408F091
:1006B00053C0C42FD62F0E94C80181114EC081E2C1
:1006C0000E94D401811149C08D2F0E94D401811153
:1006D00044C08FE70E94D40181113FC06D2F70E0AC
:1006E000709305016093040182E20E94D40181119C
:1006F00034C01C2F169516951695812F0E94D40193
:1007000081112BC087E00E94D401811126C0D0E066
:10071000D0930301C093020180E40E9499018111EA
:100720001CC088E0189FC019D109112481E001C0C4
:10073000880FCA95EAF70E94990181110EC0809135
:1007400004019091050101969093050180930401A5
:100750000E94C40180E001C081E0DF91CF911F9130
:1007600008957F928F929F92AF92BF92CF92DF9225
:10077000EF92FF920F931F93CF93DF93E82EF62E05
:10078000742E122F802E242F30E0261B3109802F4B
:1007900090E0811B910937FF05C031952195310902
:1007A0000FEF01C001E097FF06C091958195910977
:1007B00099249A9402C0992493946C01CC0CDD1C6A
:1007C0005901AA0CBB1C821793079CF4E601C21BBB
:1007D000D30B412F6F2D8E2D0E945103F714D9F0AA
:1007E000F00ED7FD03C0190DCA19DB09CC0DDD1DB4
:1007F000F0CFEC01CA19DB09412F6F2D8E2D0E941D
:100800005103181541F0190D1C161D069CF3F00E2E
:10081000CC0DDD1DEFCF80E0DF91CF911F910F91C7
:10082000FF90EF90DF90CF90BF90AF909F908F9010
:100830007F9008950F931F93CF93DF9367FF02C0BC
:100840004134E8F4122FC42FD82F042F06950695B3
:100850000695402F0E944E024C2F50E088E0089FE2
:1008600040195109112461E070E001C0660F4A95FA
:10087000EAF7412F8D2F0E94C50280E001C081E080
:10088000DF91CF911F910F9108958CE30E94E101B8
:100890008CE30E94420240E060E08CE30E9451033E
:1008A00041E060E08CE30E94510342E060E08CE3B1
:1008B0000E94510341E061E08CE30E94510342E059
:1008C00062E08CE30E94510343E063E08CE30E940A
:1008D000510344E064E08CE30E94510380E090E027
:0608E0000895F894FFCF1B
:0208E60000040C
:100460000EC0C4E2D1E089910E949901811107C0B8
:1004700085E0C432D807B9F70E94C40180E0DF915B
:10048000CF91089580E094E0E4E2F1E0DF019C0187
:100490001D9221503040E1F7089590E020E8629FDE
:1004A000800D911D112490932505809324050895B6
:1004B0002091240530912505C901880F892F881FB7
:1004C000990B91952A5F482F479544274795241B00
:1004D00027FF10C0883060F4863060F48F5F20E81A
:1004E000829FC0011124909325058093240502C0AA
:1004F00081E0089580E00895CF93C82F0E945802AC
:10050000813011F12091240530912505D901AC5D90
:10051000BE4F45E0C402C001112440E050E0805AC3
:100520009109FC01E40FF51FE859FF4FE491ED93A9
:100530004F5F5F4F45305105A1F72A5F3F4F309322
:1005400025052093240580E0CF910895CF93DF9374
:10055000EC018991882319F00E947C02FACFDF9187
:10056000CF91089587FF02C0613420F5262F26958C
:100570002695269530E0F901F695FE2FEE27F795A2
:10058000E795E80FF11DCF01019690932505809323
:100590002405EC5DFE4F88E0289F6019112481E05E
:1005A00090E001C0880F6A95EAF79081892B8083DB
:1005B00080E0089581E008958F929F92AF92BF925C
:1005C000CF92DF92EF92FF920F931F93CF93DF931F
:1005D000082FA62E142FB22E262F30E0281B31090B
:1005E0008B2D90E0841B910937FF06C03195219532
:1005F000310999249A9402C09924939497FF06C0D4
:1006000091958195910988248A9402C088248394C5
:100610007C01EE0CFF1C6901CC0CDD1C82179307DA
:1006200094F4E701C21BD30B612F802F0E94B2020A
:100630000A15D1F0090DD7FD03C0180DCC19DD093D
:10064000CE0DDF1DF1CFEC01CC19DD09612F802F1C
:100650000E94B2021B1541F0180D1C161D06A4F3D2
:10066000090DCE0DDF1DF0CF80E0DF91CF911F91FE
:100670000F91FF90EF90DF90CF90BF90AF909F9041
:100680008F9008958CE30E94E1010E9442020E9433
:10069000420224E044E06FE780E00E94DC0261E077
:1006A00087E00E944D0282E091E00E94A60222E1D2
:1006B00042E16FE780E00E94DC0263E088E20E9492
:1006C0004D0286E191E00E94A60265E085E30E946A
:1006D0004D028FE191E00E94A6028CE30E94260267
:0A06E00080E090E00895F894FFCF49
:1006EA00000453534431333036204F4C45442044A0
:1006FA005249564552004D415449415355530032CF
:04070A003032310058
:00000001FF