Hexiwear OLED
Fork of Hexi_OLED_SSD1351 by
Hexi_OLED_SSD1351.cpp
- Committer:
- khuang
- Date:
- 2016-08-26
- Revision:
- 5:a5b4b36a1aed
- Parent:
- 4:38086393d75b
- Child:
- 6:0060ffa3f4dc
File content as of revision 5:a5b4b36a1aed:
/** OLED Display Driver for Hexiwear * This file contains OLED driver functionality for drawing images and text * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * 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. * * Neither the name of NXP, 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * visit: http://www.mikroe.com and http://www.nxp.com * * get support at: http://www.mikroe.com/forum and https://community.nxp.com * * Project HEXIWEAR, 2015 */ #include "OLED_types.h" #include "OLED_info.h" #include "mbed.h" #include "Hexi_OLED_SSD1351.h" #include "OpenSans_Font.h" const init_cmd_t seq[] = { OLED_CMD_SET_CMD_LOCK, CMD_BYTE, OLED_UNLOCK, DATA_BYTE, OLED_CMD_SET_CMD_LOCK, CMD_BYTE, OLED_ACC_TO_CMD_YES, DATA_BYTE, OLED_CMD_DISPLAYOFF, CMD_BYTE, OLED_CMD_SET_OSC_FREQ_AND_CLOCKDIV, CMD_BYTE, 0xF1, DATA_BYTE, OLED_CMD_SET_MUX_RATIO, CMD_BYTE, 0x5F, DATA_BYTE, OLED_CMD_SET_REMAP, CMD_BYTE, OLED_REMAP_SETTINGS, DATA_BYTE, OLED_CMD_SET_COLUMN, CMD_BYTE, 0x00, DATA_BYTE, 0x5F, DATA_BYTE, OLED_CMD_SET_ROW, CMD_BYTE, 0x00, DATA_BYTE, 0x5F, DATA_BYTE, OLED_CMD_STARTLINE, CMD_BYTE, 0x80, DATA_BYTE, OLED_CMD_DISPLAYOFFSET, CMD_BYTE, 0x60, DATA_BYTE, OLED_CMD_PRECHARGE, CMD_BYTE, 0x32, CMD_BYTE, OLED_CMD_VCOMH, CMD_BYTE, 0x05, CMD_BYTE, OLED_CMD_NORMALDISPLAY, CMD_BYTE, OLED_CMD_CONTRASTABC, CMD_BYTE, 0x8A, DATA_BYTE, 0x51, DATA_BYTE, 0x8A, DATA_BYTE, OLED_CMD_CONTRASTMASTER, CMD_BYTE, 0xCF, DATA_BYTE, OLED_CMD_SETVSL, CMD_BYTE, 0xA0, DATA_BYTE, 0xB5, DATA_BYTE, 0x55, DATA_BYTE, OLED_CMD_PRECHARGE2, CMD_BYTE, 0x01, DATA_BYTE, OLED_CMD_DISPLAYON, CMD_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 = OpenSans_10x15_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(seq[i].cmd, seq[i].type); } } 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, CMD_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, CMD_BYTE); SendCmd( xCrd, DATA_BYTE ); SendCmd( xCrd + (width-1), DATA_BYTE ); SendCmd( OLED_CMD_SET_ROW, CMD_BYTE ); SendCmd( yCrd, DATA_BYTE ); SendCmd( yCrd + (height-1), DATA_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) { 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, CMD_BYTE ); SendCmd( 0xC0 | (0xF-i), DATA_BYTE ); wait_ms(20); //OSA_TimeDelay( 20 ); } } void SSD1351::DimScreenOFF() { SendCmd( OLED_CMD_CONTRASTMASTER, CMD_BYTE ); SendCmd( 0xC0 | 0xF, DATA_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; } } oled_status_t SSD1351::Label ( 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::TextBox(const uint8_t* text,uint8_t xCrd, uint8_t yCrd,uint8_t width,uint8_t height) { if ( NULL == text ) { return OLED_STATUS_ERROR; } oled_dynamic_area_t textArea; textArea.width = width; textArea.height = height; textArea.xCrd = xCrd; textArea.yCrd = yCrd; SetDynamicArea(&textArea); DrawText(text); return OLED_STATUS_SUCCESS; } /* 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, CMD_BYTE ); SendCmd( OLED_REMAP_SETTINGS | REMAP_VERTICAL_INCREMENT, DATA_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, CMD_BYTE ); SendCmd( OLED_REMAP_SETTINGS, DATA_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, CMD_BYTE ); SendCmd( OLED_REMAP_SETTINGS | REMAP_VERTICAL_INCREMENT, DATA_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, CMD_BYTE ); SendCmd( OLED_REMAP_SETTINGS, DATA_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, CMD_BYTE ); SendCmd( xCrd, DATA_BYTE ); SendCmd( xCrd + (width-1), DATA_BYTE ); SendCmd( OLED_CMD_SET_ROW, CMD_BYTE ); SendCmd( yCrd, DATA_BYTE ); SendCmd( yCrd + (height-1), DATA_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( OpenSans_10x15_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; }