Jan Visser / DMSupport

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

Fork of DMSupport by Embedded Artists

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BiosTouch.cpp Source File

BiosTouch.cpp

00001 /*
00002  *  Copyright 2014 Embedded Artists AB
00003  *
00004  *  Licensed under the Apache License, Version 2.0 (the "License");
00005  *  you may not use this file except in compliance with the License.
00006  *  You may obtain a copy of the License at
00007  *
00008  *    http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  *  Unless required by applicable law or agreed to in writing, software
00011  *  distributed under the License is distributed on an "AS IS" BASIS,
00012  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *  See the License for the specific language governing permissions and
00014  *  limitations under the License.
00015  */
00016 
00017 #include "mbed.h"
00018 #include "BiosTouch.h"
00019 #include "BiosLoader.h"
00020 #include "DMBoard.h"
00021 #include "bios.h"
00022 #include "meas.h"
00023 
00024 /******************************************************************************
00025  * Defines and typedefs
00026  *****************************************************************************/
00027 
00028 #define NUM_COORDS  5
00029 #define NUM_MAILS   10
00030 typedef struct {
00031   touch_coordinate_t touch[NUM_COORDS];
00032   int num;
00033 } touch_mail_t;
00034 
00035 #define SIG_NEW_DATA 0x1
00036 class TouchHandler {
00037     public:
00038         TouchHandler(bios_header_t* bios, void* biosData, int num) :
00039            _latest(NULL), _touchIRQ(P2_25), _bios(bios), 
00040            _biosData(biosData), _points(num),
00041            _listener(NULL), _lostData(0),
00042            _dbgAdded(0), _dbgRemoved(0) {}
00043         void handleTouchInterrupt();
00044         void handleNewData(touch_coordinate_t* coord, int num);
00045         void changeTouchInterrupt(bool enable, touch_irq_trigger_t trigger);
00046         TouchPanel::TouchError read(touch_coordinate_t* coord, int num);
00047         void run();
00048         FunctionPointer* setListener(FunctionPointer* listener);
00049     private:
00050         Mail<touch_mail_t, NUM_MAILS> _mailbox;
00051         Mutex _mutex;
00052         touch_coordinate_t* _latest;
00053         InterruptIn _touchIRQ;
00054         bios_header_t* _bios;
00055         void* _biosData;
00056         int _points;
00057         FunctionPointer* _listener;
00058         uint32_t _lostData;
00059         uint32_t _dbgAdded;
00060         uint32_t _dbgRemoved;
00061 };
00062 
00063 /******************************************************************************
00064  * Local variables
00065  *****************************************************************************/
00066 
00067 /******************************************************************************
00068  * Private Functions
00069  *****************************************************************************/
00070 
00071 BiosTouch::BiosTouch() : 
00072     _initialized(false),
00073     _haveInfo(false),
00074     _poweredOn(false),
00075     //_touchIRQ(P2_25),
00076     _bios(NULL),
00077     _biosData(NULL),
00078     _handlerThread(NULL),
00079     _handler(NULL),
00080     _supportsTouch(false)
00081 {
00082 }
00083 
00084 BiosTouch::~BiosTouch()
00085 {
00086   // _bios and _biosData are deallocated by BiosLoader
00087     
00088   if (_handlerThread != NULL) {
00089     delete _handlerThread;
00090     _handlerThread = NULL;
00091   }
00092   if (_handler != NULL) {
00093     delete _handler;
00094     _handler = NULL;
00095   }
00096 }
00097 
00098 // Function called from the BIOS
00099 static void touchIrqEnabler(uint32_t arg, bool enable, touch_irq_trigger_t trigger)
00100 {
00101   ((TouchHandler*)arg)->changeTouchInterrupt(enable, trigger);
00102 }
00103 
00104 // Function called from the BIOS
00105 static void touchNewData(uint32_t arg, touch_coordinate_t* coords, int num)
00106 {
00107   ((TouchHandler*)arg)->handleNewData(coords, num);
00108 }
00109 
00110 static void touchTask(void const* args)
00111 {
00112   ((TouchHandler*)args)->run();
00113 }
00114 
00115 
00116 void TouchHandler::run()
00117 {
00118   RtosLog* log = DMBoard::instance().logger();
00119       
00120   _latest = (touch_coordinate_t*)malloc(_points*sizeof(touch_coordinate_t));
00121   if (_latest == NULL) {
00122     log->printf("Failed to allocate memory for touch events\n");
00123     mbed_die();
00124   }
00125   memset(_latest, 0, _points*sizeof(touch_coordinate_t));
00126   if (_points > 1) {
00127     // multitouch - inject end event if missing
00128     uint32_t maxDelay = osWaitForever;
00129     while(true) {
00130       osEvent evt = _mailbox.get(maxDelay);
00131       if (evt.status == osEventMail) {
00132         touch_mail_t* mail = (touch_mail_t*)evt.value.p;
00133         memcpy(_latest, mail->touch, mail->num * sizeof(touch_coordinate_t));
00134         _mailbox.free(mail);
00135         _dbgRemoved++;
00136         maxDelay = 25; // wait up to 25ms for next event before injecting a "pen up" event
00137       } else if (evt.status == osEventTimeout) {
00138         int numNonZero = 0;
00139         for (int i = 0; i < _points; i++) {
00140           if (_latest[i].z > 0) {
00141             numNonZero++;
00142           }
00143           _latest[i].z = 0;    
00144         }
00145         maxDelay = osWaitForever;
00146         if (numNonZero == 0) {
00147           // last event was a pen-up event so no need to inject one
00148           //log->printf("skip penup\n");
00149           continue;            
00150         }
00151         //log->printf("inject penup\n");
00152       } else {
00153         log->printf("got non-mail event: 0x%x\n", evt.status);
00154         continue;
00155       }
00156       _mutex.lock();
00157       FunctionPointer* fp = _listener;
00158       _mutex.unlock();
00159     
00160       if (fp != NULL) {
00161         fp->call();
00162       }
00163     }
00164   } else {
00165     // normal singe-touch
00166     while(true) {
00167       osEvent evt = _mailbox.get(osWaitForever);
00168       if (evt.status == osEventMail) {
00169         touch_mail_t* mail = (touch_mail_t*)evt.value.p;
00170         memcpy(_latest, mail->touch, mail->num * sizeof(touch_coordinate_t));
00171         _mailbox.free(mail);
00172         _dbgRemoved++;
00173       } else {
00174         log->printf("got non-mail event: 0x%x\n", evt.status);
00175         continue;
00176       }
00177       _mutex.lock();
00178       FunctionPointer* fp = _listener;
00179       _mutex.unlock();
00180   
00181       if (fp != NULL) {
00182         fp->call();
00183       }
00184     }
00185   }
00186 }
00187 
00188 TouchPanel::TouchError TouchHandler::read(touch_coordinate_t* coord, int num)
00189 {
00190   if (num > _points || num < 1) {
00191     return TouchPanel::TouchError_InvalidParam;
00192   }
00193   _mutex.lock();
00194   memcpy(coord, _latest, num*sizeof(touch_coordinate_t));
00195   _mutex.unlock();
00196   
00197   return TouchPanel::TouchError_Ok;
00198 }
00199 
00200 void TouchHandler::handleTouchInterrupt()
00201 {
00202   _bios->touchIrqHandler(_biosData);
00203 }
00204 
00205 void TouchHandler::handleNewData(touch_coordinate_t* coord, int num)
00206 {
00207   touch_mail_t* mail = _mailbox.alloc(0);
00208   if (mail == NULL) {
00209     //DMBoard::instance().logger()->printf("Lost touch event\n");
00210     _lostData++;
00211   } else {
00212     _dbgAdded++;
00213     mail->num = (num < NUM_COORDS) ? num : NUM_COORDS;
00214     memcpy(&mail->touch, coord, mail->num*sizeof(touch_coordinate_t));
00215     _mailbox.put(mail);
00216   }
00217 }
00218 
00219 void TouchHandler::changeTouchInterrupt(bool enable, touch_irq_trigger_t trigger)
00220 {
00221   switch (trigger) {
00222     case TOUCH_IRQ_RISING_EDGE:
00223       if (enable) {
00224         _touchIRQ.rise(this, &TouchHandler::handleTouchInterrupt);
00225       } else {
00226         _touchIRQ.rise(NULL);
00227       }
00228       break;
00229 
00230     case TOUCH_IRQ_FALLING_EDGE:
00231       if (enable) {
00232         _touchIRQ.fall(this, &TouchHandler::handleTouchInterrupt);
00233       } else {
00234         _touchIRQ.fall(NULL);
00235       }
00236       break;
00237           
00238     case TOUCH_IRQ_HIGH_LEVEL:
00239     case TOUCH_IRQ_LOW_LEVEL:
00240     default:
00241       DMBoard::instance().logger()->printf("BIOS requests unknown trigger type %d\n", trigger);
00242       break;
00243   }
00244 }
00245 
00246 FunctionPointer* TouchHandler::setListener(FunctionPointer* listener)
00247 {
00248   _mutex.lock();
00249   FunctionPointer* old = _listener;
00250   _listener = listener;
00251   _mutex.unlock();
00252   return old;
00253 }
00254 
00255 
00256 /******************************************************************************
00257  * Public Functions
00258  *****************************************************************************/
00259 
00260 BiosTouch::TouchError BiosTouch::init()
00261 {
00262   TouchError result = TouchError_Ok;
00263   if (!_initialized) {
00264     do {
00265       if (BiosLoader::instance().params(&_bios, &_biosData) != DMBoard::Ok) {
00266         result = TouchError_ConfigError;
00267         break;
00268       }
00269       
00270       result = (TouchError)_bios->touchInformation(_biosData, &_supportsTouch, &_supportsTouchCalibration, &_touchNumFingers);
00271       if (result != TouchError_Ok) {
00272         break;
00273       }
00274       _haveInfo = true;
00275       
00276       // is it supported at all?
00277       if (!_supportsTouch) {
00278         result = TouchError_TouchNotSupported;
00279         break;
00280       }
00281       
00282       _handler = new TouchHandler(_bios, _biosData, _touchNumFingers);
00283           
00284       result = (TouchError)_bios->touchInit(_biosData, touchIrqEnabler, (uint32_t)_handler, touchNewData, (uint32_t)_handler);
00285       if (result != TouchError_Ok) {
00286         break;
00287       }
00288       
00289       result = (TouchError)_bios->touchPowerUp(_biosData);
00290       if (result != TouchError_Ok) {
00291         break;
00292       }
00293 
00294       _handlerThread = new Thread(touchTask, _handler);
00295 
00296       _initialized = true;
00297     } while(0);
00298     
00299     if (!_initialized) {
00300       if (_handler != NULL) {
00301         delete _handler;
00302         _handler = NULL;
00303       }
00304     }
00305   }
00306   return result;
00307 }
00308 
00309 BiosTouch::TouchError BiosTouch::read(touch_coordinate_t &coord)
00310 {
00311   TouchError err = TouchError_Ok;
00312   if (!_initialized) {
00313       err = TouchError_NoInit;
00314   } else {
00315     err = _handler->read(&coord, 1);
00316   }      
00317   return err;
00318 }
00319 
00320 BiosTouch::TouchError BiosTouch::read(touch_coordinate_t* coord, int num)
00321 {
00322   TouchError err = TouchError_Ok;
00323   if (!_initialized) {
00324       err = TouchError_NoInit;
00325   } else {
00326     err = _handler->read(coord, num);
00327   }      
00328   return err;
00329 }
00330 
00331 BiosTouch::TouchError BiosTouch::info(bool* resistive, int* maxPoints, bool* calibrated)
00332 {
00333   TouchError err = TouchError_Ok;
00334   if (!_haveInfo) {
00335       err = TouchError_NoInit;
00336   } else {
00337     *maxPoints = _touchNumFingers;
00338     *calibrated = _supportsTouchCalibration;
00339   }      
00340   return err;
00341 }
00342 
00343 bool BiosTouch::isTouchSupported()
00344 {
00345 #if defined(DM_BOARD_USE_TOUCH)
00346   if (_haveInfo) {
00347     return _supportsTouch;
00348   }
00349 #endif
00350   return false;
00351 }
00352 
00353 BiosTouch::TouchError BiosTouch::calibrateStart()
00354 {
00355   TouchError err = TouchError_Ok;
00356   if (!_initialized) {
00357       err = TouchError_NoInit;
00358   } else {
00359     err = (TouchError)_bios->touchCalibrateStart(_biosData);
00360   }      
00361   return err;
00362 }
00363 
00364 BiosTouch::TouchError BiosTouch::getNextCalibratePoint(uint16_t* x, uint16_t* y, bool* last)
00365 {
00366   TouchError err = TouchError_Ok;
00367   if (!_initialized) {
00368       err = TouchError_NoInit;
00369   } else {
00370     err = (TouchError)_bios->touchGetNextCalibPoint(_biosData, x, y, last);
00371   }      
00372   return err;
00373 }
00374 
00375 BiosTouch::TouchError BiosTouch::waitForCalibratePoint(bool* morePoints, uint32_t timeout)
00376 {
00377   TouchError err = TouchError_Ok;
00378   if (!_initialized) {
00379       err = TouchError_NoInit;
00380   } else {
00381     err = (TouchError)_bios->touchWaitForCalibratePoint(_biosData, morePoints, timeout);
00382   }      
00383   return err;
00384 }
00385 
00386 FunctionPointer* BiosTouch::setListener(FunctionPointer* listener)
00387 {
00388   if (_initialized) {
00389     return _handler->setListener(listener);
00390   }
00391   return NULL;
00392 }