t

Dependencies:   DM_FATFileSystem DM_HttpServer DM_USBHost EthernetInterface USBDevice mbed-rpc mbed-rtos

Fork of DMSupport by Embedded Artists

Display/BiosTouch.cpp

Committer:
embeddedartists
Date:
2015-01-16
Revision:
23:6afd6a716e80
Parent:
22:1a58a518435c
Child:
24:9a677afc86f1

File content as of revision 23:6afd6a716e80:

/*
 *  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 "mbed.h"
#include "BiosTouch.h"
#include "BiosLoader.h"
#include "DMBoard.h"
#include "bios.h"
#include "meas.h"

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

#define SIG_NEW_DATA 0x1
class TouchHandler {
    public:
        TouchHandler(bios_header_t* bios, void* biosData, int num) :
           _latest(NULL), _touchIRQ(P2_25), _bios(bios), 
           _biosData(biosData), _haveData(false), _points(num),
           _thread(NULL), _listener(NULL) {}
        void handleTouchInterrupt();
        void changeTouchInterrupt(bool enable, bool rising);
        TouchPanel::TouchError read(touch_coordinate_t* coord, int num);
        void run();
        void setThread(Thread* t) { _thread = t; }
        FunctionPointer* setListener(FunctionPointer* listener);
    private:
        Mutex _mutex;
        touch_coordinate_t* _latest;
        InterruptIn _touchIRQ;
        bios_header_t* _bios;
        void* _biosData;
        bool _haveData; //TODO: improve
        int _points;
        Thread* _thread;
        FunctionPointer* _listener;
};

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

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

BiosTouch::BiosTouch() : 
    _initialized(false),
    _haveInfo(false),
    _poweredOn(false),
    //_touchIRQ(P2_25),
    _bios(NULL),
    _biosData(NULL),
    _handlerThread(NULL),
    _handler(NULL),
    _supportsTouch(false)
{
}

BiosTouch::~BiosTouch()
{
  // _bios and _biosData are deallocated by BiosLoader
    
  if (_handlerThread != NULL) {
    delete _handlerThread;
    _handlerThread = NULL;
  }
  if (_handler != NULL) {
    delete _handler;
    _handler = NULL;
  }
}

// Function called from the BIOS
static void touchIrqEnabler(uint32_t arg, bool enable, bool rising)
{
  ((TouchHandler*)arg)->changeTouchInterrupt(enable, rising);
#if defined(DM_BOARD_ENABLE_MEASSURING_PINS)
  if (enable) {
    SET_MEAS_PIN_1();
  } else {
    CLR_MEAS_PIN_1();
  }
#endif
}

static void touchTask(void const* args)
{
  ((TouchHandler*)args)->run();
}


void TouchHandler::run()
{
  RtosLog* log = DMBoard::instance().logger();
  BiosError_t err;
  
  _latest = (touch_coordinate_t*)malloc(_points*sizeof(touch_coordinate_t));
  if (_latest == NULL) {
    log->printf("Failed to allocate memory for touch events\n");
    mbed_die();
  }
  memset(_latest, 0, _points*sizeof(touch_coordinate_t));
  while(true) {
      Thread::signal_wait(SIG_NEW_DATA);
//    if (_haveData) {
//      _haveData = false;
      SET_MEAS_PIN_3();
      _bios->touchIrqHandler(_biosData);
      CLR_MEAS_PIN_3();
      //read
      _mutex.lock();
      err = _bios->touchRead(_biosData, _latest, _points);
      FunctionPointer* fp = _listener;
      _mutex.unlock();
      if (err == BiosError_Ok) {
        //notify registered callbacks
        if (fp != NULL) {
      SET_MEAS_PIN_4();
          fp->call();
      SET_MEAS_PIN_4();
        }
      } else {
        log->printf("Failed to read touch event, err = %d\n", err);
      }
//    }
  }
  //if (_latest != NULL) {
  //  free(_latest);
  //  _latest = NULL;
  //}
}

TouchPanel::TouchError TouchHandler::read(touch_coordinate_t* coord, int num)
{
  if (num > _points || num < 1) {
    return TouchPanel::TouchError_InvalidParam;
  }
  _mutex.lock();
  memcpy(coord, _latest, num*sizeof(touch_coordinate_t));
  _mutex.unlock();
  
  return TouchPanel::TouchError_Ok;
}

void TouchHandler::handleTouchInterrupt()
{
  SET_MEAS_PIN_2();
  //_haveData = true;
  if (_thread != NULL) {
    _thread->signal_set(SIG_NEW_DATA);
  }
  CLR_MEAS_PIN_2();
}

void TouchHandler::changeTouchInterrupt(bool enable, bool rising)
{
  if (enable) {
    if (rising) {
      _touchIRQ.rise(this, &TouchHandler::handleTouchInterrupt);
    } else {
      _touchIRQ.fall(this, &TouchHandler::handleTouchInterrupt);
    }
  } else {
    if (rising) {
      _touchIRQ.rise(NULL);
    } else {
      _touchIRQ.fall(NULL);
    }
  }
}

FunctionPointer* TouchHandler::setListener(FunctionPointer* listener)
{
  _mutex.lock();
  FunctionPointer* old = _listener;
  _listener = listener;
  _mutex.unlock();
  return old;
}


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

BiosTouch::TouchError BiosTouch::init()
{
  TouchError result = TouchError_Ok;
  if (!_initialized) {
    do {
      if (BiosLoader::instance().params(&_bios, &_biosData) != DMBoard::Ok) {
        result = TouchError_ConfigError;
        break;
      }
      
      result = (TouchError)_bios->touchInformation(_biosData, &_supportsTouch, &_supportsTouchCalibration, &_touchIsResistive, &_touchNumFingers);
      if (result != TouchError_Ok) {
        break;
      }
      _haveInfo = true;
      
      // is it supported at all?
      if (!_supportsTouch) {
        result = TouchError_TouchNotSupported;
        break;
      }
      
      _handler = new TouchHandler(_bios, _biosData, _touchNumFingers);
          
      result = (TouchError)_bios->touchInit(_biosData, touchIrqEnabler, (uint32_t)_handler);
      if (result != TouchError_Ok) {
        break;
      }
      
      result = (TouchError)_bios->touchPowerUp(_biosData);
      if (result != TouchError_Ok) {
        break;
      }

      _handlerThread = new Thread(touchTask, _handler);
      _handler->setThread(_handlerThread);

      _initialized = true;
    } while(0);
    
    if (!_initialized) {
      if (_handler != NULL) {
        delete _handler;
        _handler = NULL;
      }
    }
  }
  return result;
}

BiosTouch::TouchError BiosTouch::read(touch_coordinate_t &coord)
{
  TouchError err = TouchError_Ok;
  if (!_initialized) {
      err = TouchError_NoInit;
  } else {
    err = _handler->read(&coord, 1);
  }      
  return err;
}

BiosTouch::TouchError BiosTouch::read(touch_coordinate_t* coord, int num)
{
  TouchError err = TouchError_Ok;
  if (!_initialized) {
      err = TouchError_NoInit;
  } else {
    err = _handler->read(coord, num);
  }      
  return err;
}

BiosTouch::TouchError BiosTouch::info(bool* resistive, int* maxPoints, bool* calibrated)
{
  TouchError err = TouchError_Ok;
  if (!_haveInfo) {
      err = TouchError_NoInit;
  } else {
    *resistive = _touchIsResistive;
    *maxPoints = _touchNumFingers;
    *calibrated = _supportsTouchCalibration;
  }      
  return err;
}

bool BiosTouch::isTouchSupported()
{
#if defined(DM_BOARD_USE_TOUCH)
  if (_haveInfo) {
    return _supportsTouch;
  }
#endif
  return false;
}

BiosTouch::TouchError BiosTouch::calibrateStart()
{
  TouchError err = TouchError_Ok;
  if (!_initialized) {
      err = TouchError_NoInit;
  } else {
    err = (TouchError)_bios->touchCalibrateStart(_biosData);
  }      
  return err;
}

BiosTouch::TouchError BiosTouch::getNextCalibratePoint(uint16_t* x, uint16_t* y, bool* last)
{
  TouchError err = TouchError_Ok;
  if (!_initialized) {
      err = TouchError_NoInit;
  } else {
    err = (TouchError)_bios->touchGetNextCalibPoint(_biosData, x, y, last);
  }      
  return err;
}

BiosTouch::TouchError BiosTouch::waitForCalibratePoint(bool* morePoints, uint32_t timeout)
{
  TouchError err = TouchError_Ok;
  if (!_initialized) {
      err = TouchError_NoInit;
  } else {
    err = (TouchError)_bios->touchWaitForCalibratePoint(_biosData, morePoints, timeout);
  }      
  return err;
}

FunctionPointer* BiosTouch::setListener(FunctionPointer* listener)
{
  if (_initialized) {
    return _handler->setListener(listener);
  }
  return NULL;
}