A board support package for the LPC4088 Display Module.

Dependencies:   DM_HttpServer DM_USBHost

Dependents:   lpc4088_displaymodule_emwin lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI ... more

Fork of DMSupport by EmbeddedArtists AB

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         void setListener(Callback<void()> 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         Callback<void()> _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     
00157       if (_listener) {
00158         _listener();
00159       }
00160     }
00161   } else {
00162     // normal singe-touch
00163     while(true) {
00164       osEvent evt = _mailbox.get(osWaitForever);
00165       if (evt.status == osEventMail) {
00166         touch_mail_t* mail = (touch_mail_t*)evt.value.p;
00167         memcpy(_latest, mail->touch, mail->num * sizeof(touch_coordinate_t));
00168         _mailbox.free(mail);
00169         _dbgRemoved++;
00170       } else {
00171         log->printf("got non-mail event: 0x%x\n", evt.status);
00172         continue;
00173       }
00174   
00175       if (_listener) {
00176         _listener();
00177       }
00178     }
00179   }
00180 }
00181 
00182 TouchPanel::TouchError TouchHandler::read(touch_coordinate_t* coord, int num)
00183 {
00184   if (num > _points || num < 1) {
00185     return TouchPanel::TouchError_InvalidParam;
00186   }
00187   _mutex.lock();
00188   memcpy(coord, _latest, num*sizeof(touch_coordinate_t));
00189   _mutex.unlock();
00190   
00191   return TouchPanel::TouchError_Ok;
00192 }
00193 
00194 void TouchHandler::handleTouchInterrupt()
00195 {
00196   _bios->touchIrqHandler(_biosData);
00197 }
00198 
00199 void TouchHandler::handleNewData(touch_coordinate_t* coord, int num)
00200 {
00201   touch_mail_t* mail = _mailbox.alloc(0);
00202   if (mail == NULL) {
00203     //DMBoard::instance().logger()->printf("Lost touch event\n");
00204     _lostData++;
00205   } else {
00206     _dbgAdded++;
00207     mail->num = (num < NUM_COORDS) ? num : NUM_COORDS;
00208     memcpy(&mail->touch, coord, mail->num*sizeof(touch_coordinate_t));
00209     _mailbox.put(mail);
00210   }
00211 }
00212 
00213 void TouchHandler::changeTouchInterrupt(bool enable, touch_irq_trigger_t trigger)
00214 {
00215   switch (trigger) {
00216     case TOUCH_IRQ_RISING_EDGE:
00217       if (enable) {
00218         _touchIRQ.rise(callback(this, &TouchHandler::handleTouchInterrupt));
00219       } else {
00220         _touchIRQ.rise(NULL);
00221       }
00222       break;
00223 
00224     case TOUCH_IRQ_FALLING_EDGE:
00225       if (enable) {
00226         _touchIRQ.fall(callback(this, &TouchHandler::handleTouchInterrupt));
00227       } else {
00228         _touchIRQ.fall(NULL);
00229       }
00230       break;
00231           
00232     case TOUCH_IRQ_HIGH_LEVEL:
00233     case TOUCH_IRQ_LOW_LEVEL:
00234     default:
00235       DMBoard::instance().logger()->printf("BIOS requests unknown trigger type %d\n", trigger);
00236       break;
00237   }
00238 }
00239 
00240 void TouchHandler::setListener(Callback<void()> listener)
00241 {
00242   _mutex.lock();
00243   _listener = listener;
00244   _mutex.unlock();
00245 }
00246 
00247 
00248 /******************************************************************************
00249  * Public Functions
00250  *****************************************************************************/
00251 
00252 BiosTouch::TouchError BiosTouch::init()
00253 {
00254   TouchError result = TouchError_Ok;
00255   if (!_initialized) {
00256     do {
00257       if (BiosLoader::instance().params(&_bios, &_biosData) != DMBoard::Ok) {
00258         result = TouchError_ConfigError;
00259         break;
00260       }
00261       
00262       result = (TouchError)_bios->touchInformation(_biosData, &_supportsTouch, &_supportsTouchCalibration, &_touchNumFingers);
00263       if (result != TouchError_Ok) {
00264         break;
00265       }
00266       _haveInfo = true;
00267       
00268       // is it supported at all?
00269       if (!_supportsTouch) {
00270         result = TouchError_TouchNotSupported;
00271         break;
00272       }
00273       
00274       _handler = new TouchHandler(_bios, _biosData, _touchNumFingers);
00275           
00276       result = (TouchError)_bios->touchInit(_biosData, touchIrqEnabler, (uint32_t)_handler, touchNewData, (uint32_t)_handler);
00277       if (result != TouchError_Ok) {
00278         break;
00279       }
00280       
00281       result = (TouchError)_bios->touchPowerUp(_biosData);
00282       if (result != TouchError_Ok) {
00283         break;
00284       }
00285 
00286       _handlerThread = new Thread();
00287       _handlerThread->start(callback(touchTask, _handler));
00288 
00289       _initialized = true;
00290     } while(0);
00291     
00292     if (!_initialized) {
00293       if (_handler != NULL) {
00294         delete _handler;
00295         _handler = NULL;
00296       }
00297     }
00298   }
00299   return result;
00300 }
00301 
00302 BiosTouch::TouchError BiosTouch::read(touch_coordinate_t &coord)
00303 {
00304   TouchError err = TouchError_Ok;
00305   if (!_initialized) {
00306       err = TouchError_NoInit;
00307   } else {
00308     err = _handler->read(&coord, 1);
00309   }      
00310   return err;
00311 }
00312 
00313 BiosTouch::TouchError BiosTouch::read(touch_coordinate_t* coord, int num)
00314 {
00315   TouchError err = TouchError_Ok;
00316   if (!_initialized) {
00317       err = TouchError_NoInit;
00318   } else {
00319     err = _handler->read(coord, num);
00320   }      
00321   return err;
00322 }
00323 
00324 BiosTouch::TouchError BiosTouch::info(bool* resistive, int* maxPoints, bool* calibrated)
00325 {
00326   TouchError err = TouchError_Ok;
00327   if (!_haveInfo) {
00328       err = TouchError_NoInit;
00329   } else {
00330     *maxPoints = _touchNumFingers;
00331     *calibrated = _supportsTouchCalibration;
00332   }      
00333   return err;
00334 }
00335 
00336 bool BiosTouch::isTouchSupported()
00337 {
00338 #if defined(DM_BOARD_USE_TOUCH)
00339   if (_haveInfo) {
00340     return _supportsTouch;
00341   }
00342 #endif
00343   return false;
00344 }
00345 
00346 BiosTouch::TouchError BiosTouch::calibrateStart()
00347 {
00348   TouchError err = TouchError_Ok;
00349   if (!_initialized) {
00350       err = TouchError_NoInit;
00351   } else {
00352     err = (TouchError)_bios->touchCalibrateStart(_biosData);
00353   }      
00354   return err;
00355 }
00356 
00357 BiosTouch::TouchError BiosTouch::getNextCalibratePoint(uint16_t* x, uint16_t* y, bool* last)
00358 {
00359   TouchError err = TouchError_Ok;
00360   if (!_initialized) {
00361       err = TouchError_NoInit;
00362   } else {
00363     err = (TouchError)_bios->touchGetNextCalibPoint(_biosData, x, y, last);
00364   }      
00365   return err;
00366 }
00367 
00368 BiosTouch::TouchError BiosTouch::waitForCalibratePoint(bool* morePoints, uint32_t timeout)
00369 {
00370   TouchError err = TouchError_Ok;
00371   if (!_initialized) {
00372       err = TouchError_NoInit;
00373   } else {
00374     err = (TouchError)_bios->touchWaitForCalibratePoint(_biosData, morePoints, timeout);
00375   }      
00376   return err;
00377 }
00378 
00379 void BiosTouch::setListener(Callback<void()> listener)
00380 {
00381   if (_initialized) {
00382     _handler->setListener(listener);
00383   }
00384 }