Support for the emWin GUI library from Segger.

Dependents:   lpc4088_displaymodule_emwin

This library contains the porting layer needed to start working with emWin from Segger. Details about emWin can be found both segger.com as well as lpcware.com.

The high performance emWin embedded graphics library developed by SEGGER Microcontroller is now offered by NXP Semiconductors in library form for free commercial use with NXP microcontrollers.

For a better description of what is included and the limitations, see emWin Graphics Library.

Note

The emWin library and PNG support files must be downloaded as the downloaders contains the license info. The steps are described in the readme.h file.

EwHAL.cpp

Committer:
embeddedartists
Date:
2015-03-27
Revision:
1:2847cc35a84f
Parent:
0:582739e02e4d

File content as of revision 1:2847cc35a84f:

/*
 *  Copyright 2014 Embedded Artists AB
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
#include "EwHAL.h"
#include "GUI.h"
#include "GUIDRV_Lin.h"
#include "rtos.h"


/******************************************************************************
 * Defines and typedefs
 *****************************************************************************/

/* This value is not important but the same value must be used by both the
   GUI_X_WaitEvent() and the GUI_X_SignalEvent() functions. */
#define EMWIN_TASK_SIGNAL   (0x2)

/******************************************************************************
 * Local variables
 *****************************************************************************/

static EwHAL* _hal = NULL;
static int _gettimeoffset = 0;
static Semaphore* _emSem;

static Timer _ewTimer;
static osThreadId _emTask = 0;

/******************************************************************************
 * Private Functions
 *****************************************************************************/

void EwHAL::handleTouchEvent() {
	GUI_PID_STATE ewCoord = {0};

    if (_touch->read(_coord) == TouchPanel::TouchError_Ok) {
		ewCoord.x = _coord.x;
		ewCoord.y = _coord.y;
		ewCoord.Pressed = (_coord.z == 0) ? 0 : 1;
		GUI_PID_StoreState(&ewCoord);
    }
}

/******************************************************************************
 * Public Functions
 *****************************************************************************/

EwHAL::EwHAL(int numFB, uint32_t extraMem) {

    RtosLog* log = DMBoard::instance().logger();
    _display = DMBoard::instance().display();
    _touch = DMBoard::instance().touchPanel();
    
    _width = _display->width();
    _height = _display->height();
    _fbSz = _display->fbSize();
	_numFB = numFB;
	
    do {
		if (numFB < 1) {
            log->printf("Failed. Must have at least one frame buffer, wanted %d\n", numFB);
            break;
		}

        _fb = (uint32_t)_display->allocateFramebuffers(numFB);
        if (_fb == 0) {
            log->printf("Failed to allocate memory for %d framebuffer(s)\n", numFB);
            break;
        }
        memset((void*)_fb, 0x0, _fbSz * numFB);
        
        _display->setFramebuffer((void*)_fb);
    
        _memSz = extraMem;
        _mem = (uint32_t)malloc(_memSz);
        if (_mem == 0) {
            log->printf("Failed to allocate memory block for emwin (wanted %u bytes)\n", _memSz);
            break;
        }
        memset((void*)_mem, 0x0, _memSz);
        
        _fp = new FunctionPointer(this, &EwHAL::handleTouchEvent);
		_touch->setListener(_fp);
		
		_hal = this;
    } while(false);	
}

EwHAL::~EwHAL() {
	_hal = NULL;
	if (_mem != 0) {
		free((void*)_mem);
		_mem = NULL;
	}
	if (_fb != 0) {
		free((void*)_fb);
		_fb = NULL;
	}
	if (_fp != NULL) {
		_touch->setListener(NULL);
		delete(_fp);
	}
}

void EwHAL::showFrameBuffer(int id) {
    if (id >= 0 && id < getNumFrameBuffers()) {
        _display->setFramebuffer((void*)(_fb + id * _fbSz));
    }
}

/******************************************************************************
 * emWin HAL functions
 *****************************************************************************/

/*********************************************************************
 *
 *       GUI_X_Config
 *
 * Purpose:
 *   Called during the initialization process in order to set up the
 *   available memory for the GUI.
 */
void GUI_X_Config(void) {

    if (_hal == NULL) return;

    //
    // Assign memory to emWin
    //

    GUI_ALLOC_AssignMemory(_hal->getMemoryBlockAddress(), _hal->getMemoryBlockSize());
    GUI_ALLOC_SetAvBlockSize(0x80);
    
    _emTask = Thread::gettid();

    GUI_SetSignalEventFunc(GUI_X_SignalEvent);
    GUI_SetWaitEventFunc(GUI_X_WaitEvent);
    GUI_SetWaitEventTimedFunc(GUI_X_WaitEventTimed);
}

/*********************************************************************
 *
 *       LCD_X_Config
 *
 * Purpose:
 *   Called during the initialization process in order to set up the
 *   display driver configuration.
 */
void LCD_X_Config(void) {

    if (_hal == NULL) return;
    
    //
    // Initialize MultiBuffering
    //
	if (_hal->getNumFrameBuffers() > 1) {
		GUI_MULTIBUF_Config(_hal->getNumFrameBuffers());
	}
     

    GUI_DEVICE_CreateAndLink(&GUIDRV_Lin_16_API, GUICC_M565, 0, 0);

    //
    // Display driver configuration, required for Lin-driver
    //
    LCD_SetPosEx(0, 0, 0);
    if (LCD_GetSwapXYEx(0)) {
        LCD_SetSizeEx  (0, _hal->getDisplayHeight(), _hal->getDisplayWidth());
        LCD_SetVSizeEx (0, _hal->getDisplayHeight(), _hal->getDisplayWidth());
    } else {
        LCD_SetSizeEx  (0, _hal->getDisplayWidth(), _hal->getDisplayHeight());
        LCD_SetVSizeEx (0, _hal->getDisplayWidth(), _hal->getDisplayHeight());
    }
    LCD_SetVRAMAddrEx(0, (void*)0);
    
    // TODO: Add Custom callback routine (DMA) for copying the buffers
    //       Explained in the emWin User Manual rev 5.26 section 21.4.1
}

/*********************************************************************
 *
 *       LCD_X_DisplayDriver
 *
 * Purpose:
 *   This function is called by the display driver for several purposes.
 *   To support the according task the routine needs to be adapted to
 *   the display controller. Please note that the commands marked with
 *   'optional' are not cogently required and should only be adapted if
 *   the display controller supports these features.
 *
 * Parameter:
 *   LayerIndex - Index of layer to be configured
 *   Cmd        - Please refer to the details in the switch statement below
 *   pData      - Pointer to a LCD_X_DATA structure
 *
 * Return Value:
 *   < -1 - Error
 *     -1 - Command not handled
 *      0 - Ok
 */
int LCD_X_DisplayDriver(unsigned LayerIndex, unsigned Cmd, void * pData) {
    //	LCD_X_SETORG_INFO * pSetOrg;
    int r;
    U32 TouchOrientation;

    if (_hal == NULL) return -1;

    switch (Cmd) {
    //
    // Required
    //
    case LCD_X_INITCONTROLLER:
        //
        // Called during the initialization process in order to set up the
        // display controller and put it into operation. If the display
        // controller is not initialized by any external routine this needs
        // to be adapted by the customer...
        //
        // ...

        //
        // Set display size and video-RAM address
        //
        //		LCD_SetSizeEx (800, 480, 0);
        //		LCD_SetVSizeEx(800, 480, 0);
        LCD_SetVRAMAddrEx(0, (void*)_hal->getFrameBufferAddress());

        TouchOrientation = (GUI_MIRROR_X * LCD_GetMirrorXEx(0)) |
							(GUI_MIRROR_Y * LCD_GetMirrorYEx(0)) |
							(GUI_SWAP_XY  * LCD_GetSwapXYEx (0)) ;
        GUI_TOUCH_SetOrientation(TouchOrientation);

        return 0;
    case LCD_X_SETORG:
        //
        // Required for setting the display origin which is passed in the 'xPos' and 'yPos' element of p
        //

        // pSetOrg = (LCD_X_SETORG_INFO *)pData;
        //        LPC_LCD->UPBASE = VRAM_ADDR_PHYS +
        //                (pSetOrg->yPos * YSIZE_PHYS * /*PIXEL_WIDTH*/ 2);  // Needs to be set, before LCDC is enabled

        return 0;
    case LCD_X_SHOWBUFFER:
        {
            LCD_X_SHOWBUFFER_INFO * p = (LCD_X_SHOWBUFFER_INFO *)pData;
            //
            // Calculate address of the given buffer
            //
            //unsigned long BufferSize = (XSIZE * YSIZE * BITSPERPIXEL) / 8;
            //unsigned long Addr = _VRamBaseAddr + ewGui->getFrameBufferSize() * pData->Index;
            //
            // Make the given buffer visible
            //
            _hal->showFrameBuffer(p->Index);
            //
            // Send a confirmation that the buffer is visible now
            //
            GUI_MULTIBUF_Confirm(p->Index);
        }
        return 0;
    default:
        r = -1;
    }

    return r;
}



/*********************************************************************
 *
 *      Timing:
 *                 GUI_X_GetTime()
 *                 GUI_X_Delay(int)
 *
 * Some timing dependent routines require a GetTime and delay function. 
 * Default time unit (tick), normally is 1 ms.
 */

int GUI_X_GetTime(void) {
    int t = _ewTimer.read_ms();
    if (t > 3600000) {
        // reset once per hour
        _ewTimer.reset();
        _gettimeoffset += t;
        t = 0;
    }
    return t + _gettimeoffset;
}

void GUI_X_Delay(int ms) {
    Thread::wait(ms);
}

/*********************************************************************
 *
 *       GUI_X_Init()
 *
 * Note:
 *     GUI_X_Init() is called from GUI_Init is a possibility to init
 *     some hardware which needs to be up and running before the GUI.
 *     If not required, leave this routine blank.
 */
void GUI_X_Init(void) {
    _ewTimer.start();
}


/*********************************************************************
 *
 *       GUI_X_ExecIdle
 *
 * Note:
 *  Called if WM is in idle state
 */

void GUI_X_ExecIdle(void) {}

/*********************************************************************
 *
 *      Multitasking:
 *
 *                 GUI_X_InitOS()
 *                 GUI_X_GetTaskId()
 *                 GUI_X_Lock()
 *                 GUI_X_Unlock()
 *
 * Note:
 *   The following routines are required only if emWin is used in a
 *   true multi task environment, which means you have more than one
 *   thread using the emWin API.
 *   In this case the
 *                       #define GUI_OS 1
 *  needs to be in GUIConf.h
 */

   
static void emTimeout(void const* args) {
	GUI_X_SignalEvent();
}

void GUI_X_InitOS(void) {
	_emSem = new Semaphore(1); 
}

void GUI_X_Unlock(void) {
	_emSem->release();
}

void GUI_X_Lock(void) {
	_emSem->wait();
}

U32  GUI_X_GetTaskId(void) {
	return (U32)Thread::gettid();
}

void GUI_X_WaitEvent(void) {
    Thread::signal_wait(EMWIN_TASK_SIGNAL); //wait forever
}

void GUI_X_SignalEvent(void) {
	if (_emTask) {
		osSignalSet(_emTask, EMWIN_TASK_SIGNAL);
	}
}

void GUI_X_WaitEventTimed(int Period) {
    static RtosTimer _emTim(emTimeout, osTimerOnce);
    if (Period > 0) {
        
        //wait no more than Period milliseconds
        _emTim.start(Period);
        Thread::signal_wait(EMWIN_TASK_SIGNAL);
        _emTim.stop();
    }
}

/*********************************************************************
 *
 *      Logging: OS dependent

Note:
  Logging is used in higher debug levels only. The typical target
  build does not use logging and does therefor not require any of
  the logging routines below. For a release build without logging
  the routines below may be eliminated to save some space.
  (If the linker is not function aware and eliminates unreferenced
  functions automatically)

 */

void GUI_X_Log     (const char *s) { DMBoard::instance().logger()->printf("emWin[Log] %s\n", s); }
void GUI_X_Warn    (const char *s) { DMBoard::instance().logger()->printf("emWin[Log] %s\n", s); }
void GUI_X_ErrorOut(const char *s) { DMBoard::instance().logger()->printf("emWin[Log] %s\n", s); }



/*********************************************************************
 *
 *       GUI_TOUCH_X_ActivateX()
 *
 * Function decription:
 *   Called from GUI, if touch support is enabled.
 *   Switches on voltage on X-axis,
 *   prepares measurement for Y-axis.
 *   Voltage on Y-axis is switched off.
 */
void GUI_TOUCH_X_ActivateX(void) {
}

/*********************************************************************
 *
 *       GUI_TOUCH_X_ActivateY()
 *
 * Function decription:
 *   Called from GUI, if touch support is enabled.
 *   Switches on voltage on Y-axis,
 *   prepares measurement for X-axis.
 *   Voltage on X-axis is switched off.
 */
void GUI_TOUCH_X_ActivateY(void) {
}

/*********************************************************************
 *
 *       GUI_TOUCH_X_MeasureX()
 *
 * Function decription:
 *   Called from GUI, if touch support is enabled.
 *   Measures voltage of X-axis.
 */
int  GUI_TOUCH_X_MeasureX(void) {
    if (_hal == NULL) return 0;

    return _hal->getTouchX();
}

/*********************************************************************
 *
 *       GUI_TOUCH_X_MeasureY()
 *
 * Function decription:
 *   Called from GUI, if touch support is enabled.
 *   Measures voltage of Y-axis.
 */
int  GUI_TOUCH_X_MeasureY(void) {
    if (_hal == NULL) return 0;

    return _hal->getTouchY();
}