void hmi2d_handle_fw_version(hmi_t *hmi, const unsigned char *msg)
{
    int size = msg[1];
    const unsigned char *data = msg + 2;
    hmi2d_version_request_t *request;
    hmi2d_version_info_t *version;

    if(size != 128) {
        HMI_BAD_DATA("hmi2d_handle_fw_version",
                     "Expected message size of 128 bytes",
                     size, 0);
        return;
    }

#ifdef HMI3D_SYNC_THREADING
    /* Synchronize against hmi2d_query_fw_version calls from application */
    HMI_SYNC_LOCK(hmi->io_sync);
#endif

    request = hmi->version2d_request;
    if(request) {
        version = request->version;
        if(version) {
            version->svn_revision = GET_U16(data + 0);
            version->wc_mixed = GET_U8(data + 2);
            version->wc_modified = GET_U8(data + 3);
            version->build_year = GET_U16(data + 4);
            version->build_month = GET_U8(data + 6);
            version->build_day = GET_U8(data + 7);
            version->build_hour = GET_U8(data + 8);
            version->build_minute = GET_U8(data + 9);
            version->build_second = GET_U8(data + 10);
            HMI_MEMCPY(version->buildBy, data + 11, 9);
            HMI_MEMCPY(version->infoString, data + 20, 76);
            version->checksum = GET_U32(data + 108);
            version->fw_app_id = GET_U32(data + 120);
            HMI_MEMCPY(version->fw_version, data + 124, 4);
        }
        request->received = 1;
    }

#ifdef HMI3D_SYNC_THREADING
    /* Release synchronization against hmi2d_query_fw_version */
    HMI_SYNC_UNLOCK(hmi->io_sync);
#endif
}
/*****************************************************************************
 * FUNCTION
 *  image_bmp_get_dimension
 * DESCRIPTION
 *  get dimension of a bmp from file
 * PARAMETERS
 *  filename    [IN]
 *  width       [OUT]
 *  height      [OUT]
 * RETURNS
 *  MMI_BOOL	MMI_TRUE or MMI_FALSE
 *****************************************************************************/
static MMI_BOOL image_bmp_get_dimension(S8 *filename, U32 *width, U32 *height)
{
    /*----------------------------------------------------------------*/
    /* Local Variables                                                */
    /*----------------------------------------------------------------*/
    FILE *fp;
	U8	buf[BMP_INFO_SIZE];
	U8	*src;
	U16	bfType;
	U32	bfSize;
	U32	biWidth;
	U32	biHeight;
	U32	biSize;

    /*----------------------------------------------------------------*/
    /* Code Body                                                      */
    /*----------------------------------------------------------------*/
	/* open file and read header to buffer */
    fp = fopen((char *)filename, "rb");
	if (fp == NULL)
	{
		printf("Open file error:%s\n", filename);
		return MMI_FALSE;
	}
	if (fread(buf, sizeof(char), BMP_INFO_SIZE, fp) != BMP_INFO_SIZE)
	{
		printf("Read file error:%s\n", filename);
		return MMI_FALSE;
	}
	src = buf;
    fclose(fp);

	/* read file header */
	GET_U16(src, bfType);
	GET_U32(src, bfSize);
	FLUSH(src, 8);

	/* read info header */
    GET_U32(src, biSize);
	if (biSize == 12)
	{
		GET_U16(src, biWidth);
		GET_U16(src, biHeight);
	}
	else
	{
		GET_U32(src, biWidth);
		GET_U32(src, biHeight);
	}

	*width = biWidth;
	*height = biHeight;

	/* test if it is BMP file */
	if (bfType != 0x4d42)	/* BM */
	{
		printf("Non-standard file error:%s\n", filename);
		return MMI_FALSE;
	}
	/* core info header, currently not support */
	if (bfSize == BMP_INFO_SIZE)
	{
		printf("Non-standard file error:%s\n", filename);
		return MMI_FALSE;
	}

    return MMI_TRUE;
}
void gestic_handle_data_output(gestic_t *gestic,
                               const unsigned char *data)
{
    int dataOutputConfig = GET_U16(data + 4);
    unsigned char timestamp = GET_U8(data + 6);
    int systemInfo = GET_U8(data + 7);
    const unsigned char *cursor = data + 8;
    int systemMode = (dataOutputConfig & gestic_DataOutConfigMask_ElectrodeConfiguration) >> 8;
    int electrodeCount = systemModeElectrodes[systemMode];
    int increment;

    gestic_input_data_t *dest = &gestic->internal;

    int airWheelActive = (systemInfo & gestic_SystemInfo_AirWheelValid) ? 1 : 0;

#ifdef GESTIC_SYNC_THREADING
    /* Synchronize against interaction with the internal buffer
     * from the Application-Layer
     */
    GESTIC_SYNC_LOCK(gestic->io_sync);
#endif

    /* NOTE Overflows should not be a problem as long as more
     * than one message per 256 samples is received.
     * Otherwise this algorithm will loose precision but should
     * still work as counts are only compared for equality
     * or via substraction.
     */
    increment = (unsigned char)(timestamp -
                                gestic->last_time_stamp);
    dest->frame_counter += increment ? increment : 1;
    gestic->last_time_stamp = timestamp;

    if(dataOutputConfig & gestic_DataOutConfigMask_DSPStatus) {
        int calibration = GET_U8(cursor);
        int frequency = GET_U8(cursor + 1);
        if(calibration != 0) {
            dest->calib.reason = calibration;
            dest->calib.last_event = dest->frame_counter;
        }
        if(frequency != dest->frequency.frequency) {
            dest->frequency.frequency = frequency;
            dest->frequency.freq_changed = 1;
            dest->frequency.last_event = dest->frame_counter;
        }
        cursor += 2;
    }
    if(dataOutputConfig & gestic_DataOutConfigMask_GestureInfo) {
        int gestureInfo = GET_U32(cursor);
        int raw = gestureInfo & 0xFF;
        int gesture = raw > 1 ? raw - 1 : 0;
        if(gesture) {
            dest->gesture.gesture = gesture;
            dest->gesture.flags = gestureInfo & gestic_gesture_flags_mask;
            dest->gesture.last_event = dest->frame_counter;
        }
        cursor += 4;
    }
    if(dataOutputConfig & gestic_DataOutConfigMask_TouchInfo) {
        int info = GET_U32(cursor);
        int touch = info & gestic_touch_mask;
        int tap = info & gestic_tap_mask;
        if((gestic_touch_flags_t)touch != dest->touch.flags) {
            dest->touch.flags = touch;
            dest->touch.last_event = dest->frame_counter;
            dest->touch.last_touch_event_start = dest->frame_counter - ((info & 0xFF0000) >> 16);
        }