Hexiwear OLED Display Driver
Dependents: Hexi_OLED_TextImage_Example Hexi_OLED_Text_Example Hexi_OLED_Image_Example security-console-app ... more
Diff: Hexi_OLED_SSD1351.cpp
- Revision:
- 1:3b5be0ee5f0c
- Child:
- 2:fc06b5b5bf6a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Hexi_OLED_SSD1351.cpp Thu Aug 18 23:01:06 2016 +0000 @@ -0,0 +1,1531 @@ +#include "OLED_types.h" +#include "OLED_info.h" +#include "mbed.h" +#include "Hexi_OLED_SSD1351.h" +#include "OLED_fonts.h" + +/* oled_init arrays*/ +const uint32_t oled_init_cmd[] = { + OLED_CMD_SET_CMD_LOCK, + OLED_UNLOCK, + OLED_CMD_SET_CMD_LOCK, + OLED_ACC_TO_CMD_YES, + OLED_CMD_DISPLAYOFF, + OLED_CMD_SET_OSC_FREQ_AND_CLOCKDIV, + 0xF1, + OLED_CMD_SET_MUX_RATIO, + 0x5F, + OLED_CMD_SET_REMAP, + OLED_REMAP_SETTINGS, + OLED_CMD_SET_COLUMN, + 0x00, + 0x5F, + OLED_CMD_SET_ROW, + 0x00, + 0x5F, + OLED_CMD_STARTLINE, + 0x80, + OLED_CMD_DISPLAYOFFSET, + 0x60, + OLED_CMD_PRECHARGE, + 0x32, + OLED_CMD_VCOMH, + 0x05, + OLED_CMD_NORMALDISPLAY, + OLED_CMD_CONTRASTABC, + 0x8A, + 0x51, + 0x8A, + OLED_CMD_CONTRASTMASTER, + 0xCF, + OLED_CMD_SETVSL, + 0xA0, + 0xB5, + 0x55, + OLED_CMD_PRECHARGE2, + 0x01, + OLED_CMD_DISPLAYON }; + + +const uint8_t oled_init_isFirst[] = { + FIRST_BYTE, + OTHER_BYTE, + FIRST_BYTE, + OTHER_BYTE, + FIRST_BYTE, + FIRST_BYTE, + OTHER_BYTE, + FIRST_BYTE, + OTHER_BYTE, + FIRST_BYTE, + OTHER_BYTE, + FIRST_BYTE, + OTHER_BYTE, + OTHER_BYTE, + FIRST_BYTE, + OTHER_BYTE, + OTHER_BYTE, + FIRST_BYTE, + OTHER_BYTE, + FIRST_BYTE, + OTHER_BYTE, + FIRST_BYTE, + FIRST_BYTE, + FIRST_BYTE, + FIRST_BYTE, + FIRST_BYTE, + FIRST_BYTE, + OTHER_BYTE, + OTHER_BYTE, + OTHER_BYTE, + FIRST_BYTE, + OTHER_BYTE, + FIRST_BYTE, + OTHER_BYTE, + OTHER_BYTE, + OTHER_BYTE, + FIRST_BYTE, + OTHER_BYTE, + FIRST_BYTE}; + + + + +SSD1351::SSD1351(PinName mosiPin,PinName sclkPin,PinName pwrPin, PinName csPin,PinName rstPin, PinName dcPin): spi(mosiPin,NC,sclkPin) , power(pwrPin), cs(csPin),rst(rstPin),dc(dcPin) +{ + + spi.frequency(8000000); + + + dc =0; + PowerOFF(); + wait_ms(1); + rst = 0 ; + wait_ms(1); + rst = 1 ; + wait_ms(1); + PowerON(); + + isFontInitialized = 0 ; + currentChar_width = 0, + currentChar_height = 0; + colorMask = COLOR_WHITE; + + oled_text_properties.alignParam = OLED_TEXT_ALIGN_CENTER; + oled_text_properties.background = NULL; + oled_text_properties.font = oledFont_Tahoma_8_Regular; + oled_text_properties.fontColor = COLOR_RED; + + oled_dynamic_area.areaBuffer = NULL; + oled_dynamic_area.height = 0; + oled_dynamic_area.width = 0; + oled_dynamic_area.xCrd = 0; + oled_dynamic_area.yCrd = 0; + + + + for (int i=0;i<39;i++) + { + SendCmd(oled_init_cmd[i],oled_init_isFirst[i]); + } + + + +} + + +SSD1351::~SSD1351(void) +{ + + //Run Free and zero pointers. +} + + + + +void SSD1351::SendCmd(uint32_t cmd, + uint8_t isFirst) +{ + + + + uint8_t + txSize = 1, + txBuf[4]; + + memcpy((void*)txBuf, (void*)&cmd, txSize ); + + if (isFirst ) + { + dc = 0; + } + else + { + dc = 1; + } + + cs = 0; + spi.write(*txBuf); + cs = 1; + +} + + + +void SSD1351::SendData ( const uint8_t* dataToSend, + uint32_t dataSize) + +{ + + + uint16_t* arrayPtr = (uint16_t*)dataToSend; + + for( uint32_t i = 0; i < dataSize/2; i++ ) + { + arrayPtr[i] &= colorMask; + } + + + this->SendCmd( OLED_CMD_WRITERAM, FIRST_BYTE ); + + + // sending data -> set DC pin + + dc = 1; + cs = 0 ; + + + const uint8_t* + // traversing pointer + bufPtr = dataToSend; + + + for ( uint32_t i = 0; i < dataSize; i++) + { + spi.write(*bufPtr); + bufPtr += 1; + } + + + cs = 1; + +} + + +oled_status_t SSD1351::DrawBox ( + uint16_t xCrd, + uint16_t yCrd, + uint16_t width, + uint16_t height, + uint16_t color + ) +{ + + oled_status_t status; + oled_dynamic_area_t boxArea; + + boxArea.xCrd = xCrd; + boxArea.yCrd = yCrd; + boxArea.width = width; + boxArea.height = height; + + uint32_t + boxSize = width*height; + + SetDynamicArea( &boxArea ); + + // helper pointer + uint8_t* + boxBuf = (uint8_t*)oled_dynamic_area.areaBuffer; + + if ( NULL == boxBuf ) + { + + return OLED_STATUS_ERROR; + } + + // check the bounds + if AreCoordsNotValid( xCrd, yCrd, width, height ) + { + status = OLED_STATUS_INIT_ERROR; + } + + else + { + /** fill the buffer with color */ + + for ( uint16_t i = 0; i < boxSize; i++ ) + { + boxBuf[ 2*i ] = color >> 8; + boxBuf[ 2*i + 1 ] = color; + } + + /** set the locations */ + + // adjust for the offset + OLED_AdjustColumnOffset(xCrd); + OLED_AdjustRowOffset(yCrd); + + SendCmd( OLED_CMD_SET_COLUMN, FIRST_BYTE); + SendCmd( xCrd, OTHER_BYTE ); + SendCmd( xCrd + (width-1), OTHER_BYTE ); + SendCmd( OLED_CMD_SET_ROW, FIRST_BYTE ); + SendCmd( yCrd, OTHER_BYTE ); + SendCmd( yCrd + (height-1), OTHER_BYTE ); + + + // fill the GRAM + SendData( (uint8_t*)boxBuf, boxSize*OLED_BYTES_PER_PIXEL ); + + DestroyDynamicArea(); + + } + + return status; +} + +/** + * fill the entire screen + * @param color color to fill with + * @return status flag + */ +void SSD1351::FillScreen( uint16_t color ) +{ + /** fill the screen buffer with color */ + for ( uint16_t i = 0; i < ( OLED_SCREEN_WIDTH * OLED_SCREEN_HEIGHT ); i++ ) + { + screenBuf[ 2*i ] = color >> 8; + screenBuf[ 2*i + 1 ] = color; + } + + /** set the locations */ + SetBorders( 0, 0, OLED_SCREEN_WIDTH, OLED_SCREEN_HEIGHT ); + + /** fill GRAM */ + SendData( (uint8_t*)screenBuf, OLED_SCREEN_WIDTH * OLED_SCREEN_HEIGHT * OLED_BYTES_PER_PIXEL ); + +} + + + +oled_status_t SSD1351::DrawPixel ( + int16_t xCrd, + int16_t yCrd, + uint16_t color + ) +{ + // check the bounds + if AreCoordsNotValid( xCrd, yCrd, 1, 1 ) + { + return OLED_STATUS_INIT_ERROR; + } + + else + { + // set directions + SetBorders( xCrd, yCrd, OLED_SCREEN_WIDTH, OLED_SCREEN_HEIGHT); + + uint16_t + // swap bytes + dot = color; + + OLED_SwapMe(dot); + + // fill the GRAM + SendData( (uint8_t*)&dot, 2 ); + + return OLED_STATUS_SUCCESS; + } +} + + +oled_status_t SSD1351::DrawScreen ( + const uint8_t* image, + uint8_t xCrd, + uint8_t yCrd, + uint8_t width, + uint8_t height, + oled_transition_t transition + ) +{ + oled_status_t + status = OLED_STATUS_SUCCESS; + + if AreCoordsNotValid( xCrd, yCrd, width, height ) + { + return OLED_STATUS_INIT_ERROR; + } + + switch ( transition ) + { + case OLED_TRANSITION_NONE: { + /** set the locations */ + SetBorders( xCrd, yCrd, width, height); + + // fill the GRAM + SendData( (const uint8_t*)image, width * height * OLED_BYTES_PER_PIXEL ); + break; + } + + case OLED_TRANSITION_TOP_DOWN: { + TopDown( image, xCrd, yCrd, width, height ); + break; + } + + case OLED_TRANSITION_DOWN_TOP: { + DownTop( image, xCrd, yCrd, width, height ); + break; + } + + case OLED_TRANSITION_LEFT_RIGHT: { + LeftRight( image, xCrd, yCrd, width, height ); + break; + } + + case OLED_TRANSITION_RIGHT_LEFT: { + RightLeft( image, xCrd, yCrd, width, height ); + break; + } + + default: {} + } + + return status; +} + + +oled_status_t SSD1351::SetFont( + const uint8_t* newFont, + uint16_t newColor + ) +{ + /** save the new values in intern variables */ + + selectedFont = newFont; + // selectedFont_firstChar = newFont[2] + (newFont[3] << 8); + selectedFont_firstChar = newFont[2] | ( (uint16_t)newFont[3] << 8 ); + // selectedFont_lastChar = newFont[4] + (newFont[5] << 8); + selectedFont_lastChar = newFont[4] | ( (uint16_t)newFont[5] << 8 ); + selectedFont_height = newFont[6]; + selectedFont_color = newColor; + + OLED_SwapMe( selectedFont_color ); + + isFontInitialized = 1; + return OLED_STATUS_SUCCESS; +} + + +void SSD1351::SetDynamicArea(oled_dynamic_area_t *dynamic_area) +{ + + if( NULL == oled_dynamic_area.areaBuffer ) + { + oled_dynamic_area.areaBuffer = (oled_pixel_t)AllocateDynamicArea( dynamic_area->width * dynamic_area->height ); + } + else if( + ( dynamic_area->height != oled_dynamic_area.height ) || + ( dynamic_area->width != oled_dynamic_area.width ) + ) + { + DestroyDynamicArea(); + oled_dynamic_area.areaBuffer = (oled_pixel_t)AllocateDynamicArea( dynamic_area->width * dynamic_area->height ); + } + + oled_dynamic_area.xCrd = dynamic_area->xCrd; + oled_dynamic_area.yCrd = dynamic_area->yCrd; + oled_dynamic_area.width = dynamic_area->width; + oled_dynamic_area.height = dynamic_area->height; +} + + +void SSD1351::DestroyDynamicArea() +{ + if ( NULL != oled_dynamic_area.areaBuffer ) + { + DestroyDynamicArea( oled_dynamic_area.areaBuffer ); + oled_dynamic_area.areaBuffer = NULL; + } +} + + +void SSD1351::SetTextProperties(oled_text_properties_t *textProperties) +{ + oled_text_properties.font = textProperties->font; + oled_text_properties.fontColor = textProperties->fontColor; + oled_text_properties.alignParam = textProperties->alignParam; + oled_text_properties.background = textProperties->background; + + SetFont( oled_text_properties.font, oled_text_properties.fontColor ); +} + + + + +uint8_t SSD1351::GetTextWidth(const uint8_t* text) +{ + uint8_t chrCnt = 0; + uint8_t text_width = 0; + + while ( 0 != text[chrCnt] ) + { + text_width += *( selectedFont + 8 + (uint16_t)( ( text[chrCnt++] - selectedFont_firstChar ) << 2 ) ); + // make 1px space between chars + text_width++; + } + // remove the final space + text_width--; + + return text_width; +} + + + +uint8_t SSD1351::CharCount(uint8_t width, const uint8_t* font, const uint8_t* text, uint8_t length) +{ + uint8_t chrCnt = 0; + uint8_t text_width = 0; + uint16_t firstChar; + + firstChar = font[2] | ( (uint16_t)font[3] << 8 ); + + while ( chrCnt < length ) + { + text_width += *( font + 8 + (uint16_t)( ( text[chrCnt++] - firstChar ) << 2 ) ); + if(text_width > width) + { + chrCnt--; + break; + } + // make 1px space between chars + text_width++; + } + + return chrCnt; +} + + + + +oled_status_t SSD1351::AddText( const uint8_t* text,uint8_t xCrd, uint8_t yCrd ) +{ + uint16_t + chrCnt = 0; + oled_pixel_t + chrBuf = NULL; + + uint8_t + currentChar_x = 0, + currentChar_y = 0; + + uint8_t + text_height = 0, + text_width = 0; + + text_width = GetTextWidth(text); + + /** + * set default values, if necessary + */ + + text_height = selectedFont_height; + oled_dynamic_area_t textArea; + + + textArea.width = text_width; + textArea.height = text_height; + textArea.xCrd = xCrd; + textArea.yCrd = yCrd; + SetDynamicArea(&textArea); + + + currentChar_y = ( oled_dynamic_area.height - text_height ) >> 1; + + switch ( oled_text_properties.alignParam & OLED_TEXT_HALIGN_MASK ) + { + case OLED_TEXT_ALIGN_LEFT: + { + currentChar_x = 0; + break; + } + + case OLED_TEXT_ALIGN_RIGHT: + { + currentChar_x = ( oled_dynamic_area.width - text_width ); + break; + } + + case OLED_TEXT_ALIGN_CENTER: + { + currentChar_x += ( oled_dynamic_area.width - text_width ) >> 1 ; + break; + } + + case OLED_TEXT_ALIGN_NONE: + { + break; + } + + default: {} + } + + if ( CreateTextBackground() != OLED_STATUS_SUCCESS ) + { + return OLED_STATUS_ERROR; + } + + /** + * write the characters into designated space, one by one + */ + + chrCnt = 0; + while ( 0 != text[chrCnt] ) + { + WriteCharToBuf( text[chrCnt++], &chrBuf ); + + if ( NULL == chrBuf ) + { + return OLED_STATUS_INIT_ERROR; + } + + else + { + if ( + ( ( currentChar_x + currentChar_width ) > oled_dynamic_area.width ) + || ( ( currentChar_y + currentChar_height ) > oled_dynamic_area.height ) + ) + { + DestroyDynamicArea( chrBuf ); + chrBuf = NULL; + return OLED_STATUS_ERROR; + } + + // copy data + oled_pixel_t + copyAddr = oled_dynamic_area.areaBuffer + ( currentChar_y * oled_dynamic_area.width + currentChar_x ); + + AddCharToTextArea( chrBuf, currentChar_width, currentChar_height, copyAddr, oled_dynamic_area.width ); + + currentChar_x += ( currentChar_width+1 ); + currentChar_y += 0; + + DestroyDynamicArea( chrBuf ); + chrBuf = NULL; + } + } + + UpdateBuffer( + oled_dynamic_area.xCrd, + oled_dynamic_area.yCrd, + oled_dynamic_area.width, + oled_dynamic_area.height, + (const uint8_t*)oled_dynamic_area.areaBuffer + ); + + return OLED_STATUS_SUCCESS; +} + + +oled_status_t SSD1351::AddText( const uint8_t* text) +{ + uint16_t + chrCnt = 0; + oled_pixel_t + chrBuf = NULL; + + uint8_t + currentChar_x = 0, + currentChar_y = 0; + + uint8_t + text_height = 0, + text_width = 0; + + text_width = GetTextWidth(text); + + /** + * set default values, if necessary + */ + + text_height = selectedFont_height; + + + if (( oled_dynamic_area.width < text_width )||( oled_dynamic_area.height < text_height )) + { + oled_dynamic_area_t textArea; + textArea.width = text_width; + textArea.height = text_height; + SetDynamicArea(&textArea); + } + + currentChar_y = ( oled_dynamic_area.height - text_height ) >> 1; + + switch ( oled_text_properties.alignParam & OLED_TEXT_HALIGN_MASK ) + { + case OLED_TEXT_ALIGN_LEFT: + { + currentChar_x = 0; + break; + } + + case OLED_TEXT_ALIGN_RIGHT: + { + currentChar_x = ( oled_dynamic_area.width - text_width ); + break; + } + + case OLED_TEXT_ALIGN_CENTER: + { + currentChar_x += ( oled_dynamic_area.width - text_width ) >> 1 ; + break; + } + + case OLED_TEXT_ALIGN_NONE: + { + break; + } + + default: {} + } + + if ( CreateTextBackground() != OLED_STATUS_SUCCESS ) + { + return OLED_STATUS_ERROR; + } + + /** + * write the characters into designated space, one by one + */ + + chrCnt = 0; + while ( 0 != text[chrCnt] ) + { + WriteCharToBuf( text[chrCnt++], &chrBuf ); + + if ( NULL == chrBuf ) + { + return OLED_STATUS_INIT_ERROR; + } + + else + { + if ( + ( ( currentChar_x + currentChar_width ) > oled_dynamic_area.width ) + || ( ( currentChar_y + currentChar_height ) > oled_dynamic_area.height ) + ) + { + DestroyDynamicArea( chrBuf ); + chrBuf = NULL; + return OLED_STATUS_ERROR; + } + + // copy data + oled_pixel_t + copyAddr = oled_dynamic_area.areaBuffer + ( currentChar_y * oled_dynamic_area.width + currentChar_x ); + + AddCharToTextArea( chrBuf, currentChar_width, currentChar_height, copyAddr, oled_dynamic_area.width ); + + currentChar_x += ( currentChar_width+1 ); + currentChar_y += 0; + + DestroyDynamicArea( chrBuf ); + chrBuf = NULL; + } + } + + UpdateBuffer( + oled_dynamic_area.xCrd, + oled_dynamic_area.yCrd, + oled_dynamic_area.width, + oled_dynamic_area.height, + (const uint8_t*)oled_dynamic_area.areaBuffer + ); + + return OLED_STATUS_SUCCESS; +} + + + +oled_status_t SSD1351::DrawText ( const uint8_t* text,uint8_t xCrd, uint8_t yCrd ) +{ + + if ( NULL == text ) + { + return OLED_STATUS_ERROR; + } + + AddText(text,xCrd,yCrd); + + // set the locations + SetBorders( oled_dynamic_area.xCrd, oled_dynamic_area.yCrd, oled_dynamic_area.width, oled_dynamic_area.height ); + + // fill the GRAM + SendData( (const uint8_t*)oled_dynamic_area.areaBuffer, oled_dynamic_area.width * oled_dynamic_area.height * OLED_BYTES_PER_PIXEL ); + + +// free( currentTextAreaImage ); + return OLED_STATUS_SUCCESS; +} + + +oled_status_t SSD1351::DrawText( const uint8_t* text) +{ + + if ( NULL == text ) + { + return OLED_STATUS_ERROR; + } + + AddText(text); + // set the locations + SetBorders( oled_dynamic_area.xCrd, oled_dynamic_area.yCrd, oled_dynamic_area.width, oled_dynamic_area.height ); + // fill the GRAM + SendData( (const uint8_t*)oled_dynamic_area.areaBuffer, oled_dynamic_area.width * oled_dynamic_area.height * OLED_BYTES_PER_PIXEL ); + +// free( currentTextAreaImage ); + return OLED_STATUS_SUCCESS; +} + + + + + + + + +void SSD1351::GetImageDimensions(uint8_t *width, uint8_t *height, const uint8_t* image) +{ + *height = image[2] + (image[3] << 8); + *width = image[4] + (image[5] << 8); +} + + +oled_status_t SSD1351::AddImage ( const uint8_t* image ) +{ + oled_status_t + status = OLED_STATUS_SUCCESS; + + // check the bounds + if AreCoordsNotValid( oled_dynamic_area.xCrd, oled_dynamic_area.yCrd, oled_dynamic_area.width, oled_dynamic_area.height ) + { + status = OLED_STATUS_INIT_ERROR; + } + + else + { + Swap( (oled_pixel_t)oled_dynamic_area.areaBuffer, BMP_SkipHeader(image), oled_dynamic_area.width*oled_dynamic_area.height ); + + // update the main screen buffer + UpdateBuffer( oled_dynamic_area.xCrd, oled_dynamic_area.yCrd, oled_dynamic_area.width, oled_dynamic_area.height, (const uint8_t *)oled_dynamic_area.areaBuffer ); + } + + return status; +} + + +oled_status_t SSD1351::AddImage ( const uint8_t* image, uint8_t xCrd, uint8_t yCrd ) +{ + oled_status_t + status = OLED_STATUS_SUCCESS; + + oled_dynamic_area_t image_dynamicArea; + + image_dynamicArea.xCrd = xCrd; + image_dynamicArea.yCrd = yCrd; + + GetImageDimensions(&image_dynamicArea.width, &image_dynamicArea.height, image); + SetDynamicArea(&image_dynamicArea); + + // check the bounds + if AreCoordsNotValid( oled_dynamic_area.xCrd, oled_dynamic_area.yCrd, oled_dynamic_area.width, oled_dynamic_area.height ) + { + status = OLED_STATUS_INIT_ERROR; + } + + else + { + Swap( (oled_pixel_t)oled_dynamic_area.areaBuffer, BMP_SkipHeader(image), oled_dynamic_area.width*oled_dynamic_area.height ); + + // update the main screen buffer + UpdateBuffer( oled_dynamic_area.xCrd, oled_dynamic_area.yCrd, oled_dynamic_area.width, oled_dynamic_area.height, (const uint8_t *)oled_dynamic_area.areaBuffer ); + } + + return status; +} + + + +oled_status_t SSD1351::DrawImage ( const uint8_t* image ) +{ + + oled_status_t + status = OLED_STATUS_SUCCESS; + + status = AddImage( image ); + + // set the locations + SetBorders( oled_dynamic_area.xCrd, oled_dynamic_area.yCrd, oled_dynamic_area.width, oled_dynamic_area.height ); + + // fill the GRAM + SendData( (const uint8_t*)oled_dynamic_area.areaBuffer, oled_dynamic_area.width * oled_dynamic_area.height * OLED_BYTES_PER_PIXEL ); + + + return status; +} + +oled_status_t SSD1351::DrawImage ( const uint8_t* image, uint8_t xCrd, uint8_t yCrd ) +{ + + oled_status_t + status = OLED_STATUS_SUCCESS; + + status = AddImage( image,xCrd,yCrd); + + // set the locations + SetBorders( oled_dynamic_area.xCrd, oled_dynamic_area.yCrd, oled_dynamic_area.width, oled_dynamic_area.height ); + + // fill the GRAM + SendData( (const uint8_t*)oled_dynamic_area.areaBuffer, oled_dynamic_area.width * oled_dynamic_area.height * OLED_BYTES_PER_PIXEL ); + + + return status; +} + + + +void SSD1351::DimScreenON() +{ + for ( int i = 0; i < 16; i++ ) + { + SendCmd( OLED_CMD_CONTRASTMASTER, FIRST_BYTE ); + SendCmd( 0xC0 | (0xF-i), OTHER_BYTE ); + wait_ms(20); + //OSA_TimeDelay( 20 ); + } +} + + +void SSD1351::DimScreenOFF() +{ + SendCmd( OLED_CMD_CONTRASTMASTER, FIRST_BYTE ); + SendCmd( 0xC0 | 0xF, OTHER_BYTE ); +} + + + +void SSD1351::Swap( + oled_pixel_t imgDst, + const uint8_t* imgSrc, + uint16_t imgSize + ) +{ + for ( int var = 0; var < imgSize; var++ ) + { + *imgDst = *imgSrc << 8; + imgSrc++; + *imgDst |= *imgSrc; + imgDst++; + imgSrc++; + } +} + + +void SSD1351::PowerON() +{ + power = 1; +} + +void SSD1351::PowerOFF() +{ + power = 0; +} + + + + //Formerly Known as GuiDriver_UpdateScreen +void SSD1351::UpdateBuffer ( + uint8_t xCrd, + uint8_t yCrd, + uint8_t width, + uint8_t height, + const uint8_t* image + ) +{ + // copy data + oled_pixel_t + copyAddr = (oled_pixel_t)screenBuf + ( yCrd*OLED_SCREEN_WIDTH + xCrd ); + + for ( uint8_t i = 0; i < height; i++ ) + { + memcpy( (void*)copyAddr, (void*)image, width*OLED_BYTES_PER_PIXEL ); + copyAddr += OLED_SCREEN_WIDTH; + image += width*OLED_BYTES_PER_PIXEL; + } +} + +/* Internal Functions */ + +/** + * [transpose description] + * @param transImage Transposed Image + * @param image Source Image + * @param width Width to Transpose + * @param height Height to Transpose + */ +void SSD1351::Transpose( + oled_pixel_t transImage, + const oled_pixel_t image, + uint8_t width, + uint8_t height + ) +{ + for ( uint8_t i = 0; i < height; i++ ) + { + for ( uint8_t j = 0; j < width ; j++ ) + { + transImage[ j*height + i ] = image[ i*width + j ]; + } + } +} + + + +/** + * TopDown Transition Effect for Image + * @param image image to be transitioned + * @param xCrd x coordinate of image + * @param yCrd y coordinate of image + * @param width width of image + * @param height height of image + * @return status flag + */ +oled_status_t SSD1351::TopDown( + const uint8_t* image, + uint8_t xCrd, + uint8_t yCrd, + uint8_t width, + uint8_t height + ) +{ + uint16_t + transStep = OLED_TRANSITION_STEP; + + uint16_t + partImgSize = width*transStep; + + oled_status_t + status = OLED_STATUS_SUCCESS; + + uint8_t* + partImgPtr = (uint8_t*)image + ( height - transStep ) * ( width * OLED_BYTES_PER_PIXEL ); + + /** + * set locations + */ + + while (1) + { + SetBorders( xCrd, yCrd, width, height ); + + if ( partImgSize > width*height ) + { + SendData( (const uint8_t*)image, width*height*OLED_BYTES_PER_PIXEL ); + break; + } + else + { + SendData( (const uint8_t*)partImgPtr, partImgSize * OLED_BYTES_PER_PIXEL ); + } + + + /** + * update variables + */ + + partImgPtr -= ( width * transStep ) * OLED_BYTES_PER_PIXEL; + partImgSize += ( width * transStep ); + transStep++; + } + + return status; +} + +/** + * DownTop Transition Effect for Image + * @param image image to be transitioned + * @param xCrd x coordinate of image + * @param yCrd y coordinate of image + * @param width width of image + * @param height height of image + * @return status flag + */ + +oled_status_t SSD1351::DownTop( + const uint8_t* image, + uint8_t xCrd, + uint8_t yCrd, + uint8_t width, + uint8_t height + ) +{ + uint16_t + transStep = OLED_TRANSITION_STEP; + + uint16_t + partImgSize = width*transStep; + + oled_status_t + status = OLED_STATUS_SUCCESS; + + uint8_t* + partImgPtr = (uint8_t*)image; + + uint8_t + yCrd_moving = ( yCrd + height ) - 1; + + /** + * set locations + */ + + while (1) + { + if ( + ( partImgSize > OLED_SCREEN_SIZE ) + || ( yCrd_moving < yCrd ) + ) + { + // draw full image + SetBorders( xCrd, yCrd, width, height ); + SendData( (const uint8_t*)image, width * height * OLED_BYTES_PER_PIXEL ); + break; + } + + else + { + SetBorders( xCrd, yCrd_moving, width, ( yCrd + height ) - yCrd_moving ); + SendData( (const uint8_t*)partImgPtr, partImgSize * OLED_BYTES_PER_PIXEL ); + } + + /** + * update variables + */ + + yCrd_moving -= transStep; + partImgSize += ( width * transStep ); + transStep++; + } + + return status; +} + + +/** + * LeftRight Transition Effect for Image + * @param image image to be transitioned + * @param xCrd x coordinate of image + * @param yCrd y coordinate of image + * @param width width of image + * @param height height of image + * @return status flag + */ + +oled_status_t SSD1351::LeftRight( + const uint8_t* image, + uint8_t xCrd, + uint8_t yCrd, + uint8_t width, + uint8_t height + ) +{ + oled_status_t + status = OLED_STATUS_SUCCESS; + + oled_dynamic_area_t + transImageArea = + { + .xCrd = 0, + .yCrd = 0, + + .width = 96, + .height= 96 + }; + + SetDynamicArea( &transImageArea ); + + // helper pointer + oled_pixel_t + transImage = (oled_pixel_t)oled_dynamic_area.areaBuffer; + + if ( NULL == transImage ) + { + return OLED_STATUS_INIT_ERROR; + } + + Transpose( (oled_pixel_t)transImage, (const oled_pixel_t)image, width, height ); + + SendCmd( OLED_CMD_SET_REMAP, FIRST_BYTE ); + SendCmd( OLED_REMAP_SETTINGS | REMAP_VERTICAL_INCREMENT, OTHER_BYTE ); + + uint16_t + transStep = OLED_TRANSITION_STEP; + + uint16_t + partImgSize = height*transStep; + + uint8_t* + partImgPtr = (uint8_t*)transImage + ( width - transStep ) * ( height * OLED_BYTES_PER_PIXEL ); + + /** + * set locations + */ + + while (1) + { + SetBorders( xCrd, yCrd, width, height ); + + if ( partImgSize > width*height ) + { + SendData((const uint8_t*)transImage, width * height * OLED_BYTES_PER_PIXEL ); + break; + } + else + { + SendData( (const uint8_t*)partImgPtr, partImgSize * OLED_BYTES_PER_PIXEL ); + } + + + partImgPtr -= ( transStep * height ) * OLED_BYTES_PER_PIXEL; + partImgSize += ( transStep * height ); + transStep++; + + } + + SendCmd( OLED_CMD_SET_REMAP, FIRST_BYTE ); + SendCmd( OLED_REMAP_SETTINGS, OTHER_BYTE ); + + DestroyDynamicArea(); + return status; +} + + +/** + * RightLeft Transition Effect for Image + * @param image image to be transitioned + * @param xCrd x coordinate of image + * @param yCrd y coordinate of image + * @param width width of image + * @param height height of image + * @return status flag + */ +oled_status_t SSD1351::RightLeft( + const uint8_t* image, + uint8_t xCrd, + uint8_t yCrd, + uint8_t width, + uint8_t height + ) +{ + oled_dynamic_area_t + transImageArea = + { + .xCrd = 0, + .yCrd = 0, + + .width = 96, + .height= 96 + }; + + SetDynamicArea( &transImageArea ); + + // helper pointer + oled_pixel_t + transImage = oled_dynamic_area.areaBuffer; + + if ( NULL == transImage ) + { + return OLED_STATUS_INIT_ERROR; + } + + Transpose( (oled_pixel_t)transImage, (const oled_pixel_t)image, width, height ); + + SendCmd( OLED_CMD_SET_REMAP, FIRST_BYTE ); + SendCmd( OLED_REMAP_SETTINGS | REMAP_VERTICAL_INCREMENT, OTHER_BYTE ); + + + uint16_t + transStep = OLED_TRANSITION_STEP; + + uint16_t + partImgSize = height * transStep; + + uint8_t* + partImgPtr = (uint8_t*)transImage; + + uint8_t + xCrd_moving = ( xCrd + width ) - 1; + + /** set locations */ + + while (1) + { + if (( partImgSize > width*height )|| ( xCrd_moving < xCrd )) + { + SetBorders( xCrd, yCrd, width, height ); + SendData( (const uint8_t*)transImage, height * width * OLED_BYTES_PER_PIXEL ); + break; + } + else + { + SetBorders( xCrd_moving, yCrd, ( xCrd + width ) - xCrd_moving, height ); + SendData( (const uint8_t*)partImgPtr, partImgSize * OLED_BYTES_PER_PIXEL ); + } + + /** update variables*/ + + xCrd_moving -= transStep; + partImgSize += ( height * transStep ); + transStep++; + } + + SendCmd( OLED_CMD_SET_REMAP, FIRST_BYTE ); + SendCmd( OLED_REMAP_SETTINGS, OTHER_BYTE ); + + DestroyDynamicArea(); + + return OLED_STATUS_SUCCESS; +} + + +/** + * [setDirection description] + * @param self [description] + * @param xCrd [description] + * @param yCrd [description] + * @return [description] + */ +void SSD1351::SetBorders( + uint8_t xCrd, + uint8_t yCrd, + uint8_t width, + uint8_t height + ) +{ + + // adjust for the offset + OLED_AdjustColumnOffset(xCrd); + OLED_AdjustRowOffset(yCrd); + + SendCmd( OLED_CMD_SET_COLUMN, FIRST_BYTE ); + SendCmd( xCrd, OTHER_BYTE ); + SendCmd( xCrd + (width-1), OTHER_BYTE ); + SendCmd( OLED_CMD_SET_ROW, FIRST_BYTE ); + SendCmd( yCrd, OTHER_BYTE ); + SendCmd( yCrd + (height-1), OTHER_BYTE ); + +} + +/** + * create the buffer for a partial image + * @param imgBuf [description] + * @param width [description] + * @param height [description] + * @return [description] + */ +oled_status_t SSD1351::CreateTextBackground() +{ + uint8_t + xCrd = oled_dynamic_area.xCrd, + yCrd = oled_dynamic_area.yCrd, + width = oled_dynamic_area.width, + height = oled_dynamic_area.height; + + oled_pixel_t + imgBuf = oled_dynamic_area.areaBuffer, + copyAddr; + + const uint8_t* + background = oled_text_properties.background; + + /** copy data */ + + if ( + ( NULL == imgBuf ) + || ( ( xCrd + width ) > OLED_SCREEN_WIDTH ) + || ( ( yCrd + height ) > OLED_SCREEN_HEIGHT ) + ) + { + return OLED_STATUS_INIT_ERROR; + } + + if ( NULL == background ) + { + for ( uint8_t i = 0; i < height; i++ ) + { + memset( (void*)imgBuf, 0, width*OLED_BYTES_PER_PIXEL ); + imgBuf += width; + } + } + + else + { + copyAddr = (oled_pixel_t)( BMP_SkipHeader( background ) ) + ( yCrd*OLED_SCREEN_WIDTH + xCrd ); + for ( uint8_t i = 0; i < height; i++ ) + { + Swap( (oled_pixel_t)imgBuf, (const uint8_t*)copyAddr, width ); + imgBuf += width; + copyAddr += OLED_SCREEN_WIDTH; + } + } + + return OLED_STATUS_SUCCESS; +} + + +/** + * Write the character to Buffer + * @param charToWrite character to be written + * @param chrBuf given pointer for buffer for the character + */ +void SSD1351::WriteCharToBuf( + uint16_t charToWrite, + oled_pixel_t* chrBuf + ) +{ + uint8_t + foo = 0, + mask; + + const uint8_t* + pChTable = selectedFont + 8 + (uint16_t)( ( charToWrite - selectedFont_firstChar ) << 2 ); + + currentChar_width = *pChTable, + currentChar_height = selectedFont_height; + + uint32_t + offset = (uint32_t)pChTable[1] + | ( (uint32_t)pChTable[2] << 8 ) + | ( (uint32_t)pChTable[3] << 16 ); + + const uint8_t* + pChBitMap = selectedFont + offset; + + if ( 0 == isFontInitialized ) + { + // default font + SetFont( oledFont_Tahoma_8_Regular, COLOR_WHITE ); + } + + // allocate space for char image + *chrBuf = (oled_pixel_t)AllocateDynamicArea( currentChar_height * currentChar_width ); + + if ( NULL == *chrBuf ) + { + return; + } + + for ( uint8_t yCnt = 0; yCnt < currentChar_height; yCnt++ ) + { + mask = 0; + + for ( uint8_t xCnt = 0; xCnt < currentChar_width; xCnt++ ) + { + if ( 0 == mask ) + { + mask = 1; + foo = *pChBitMap++; + } + + if ( 0 != ( foo & mask ) ) + { + *( *chrBuf + yCnt*currentChar_width + xCnt ) = selectedFont_color; + } + + else + { + *( *chrBuf + yCnt*currentChar_width + xCnt ) = 0; + } + + mask <<= 1; + } + } +} + + + +/** + * Add subimage/character to the active image buffer + * @param xOffset offset for the x-coordinate + * @param yOffset offset for the y-coordinate + * @param width desired width + * @param height desired height + * @return status flag + */ +oled_status_t SSD1351::AddCharToTextArea( + oled_pixel_t chrPtr, + uint8_t chrWidth, + uint8_t chrHeight, + oled_pixel_t copyAddr, + uint8_t imgWidth + ) +{ + if ( NULL == copyAddr ) + { + return OLED_STATUS_INIT_ERROR; + } + + for ( uint8_t i = 0; i < chrHeight; i++ ) + { + for ( uint8_t j = 0; j < chrWidth; j++ ) + { + if ( 0 != chrPtr[j] ) + { + copyAddr[j] = chrPtr[j]; + } + } + copyAddr += imgWidth; + chrPtr += chrWidth; + } + return OLED_STATUS_SUCCESS; +} + + +/** + * Allocate memory for the desired image/character + * @param area desired area dimensions + */ +void* SSD1351::AllocateDynamicArea( uint32_t area ) +{ + void* + ptr = malloc( area * OLED_BYTES_PER_PIXEL ); + + if ( NULL == ptr ) + { + return NULL; + } + + return ptr; +} + + +/** + * Deallocate current area + * @param area pointer to current area + */ +oled_status_t SSD1351::DestroyDynamicArea( void* ptr ) +{ + if ( NULL == ptr ) + { + return OLED_STATUS_INIT_ERROR; + } + + free(ptr); + + return OLED_STATUS_SUCCESS; +} + + + + + + +