//----------------------------------------------------------------------------
///
/// \file   touch_tsc2007.cpp
/// \brief  Touch controller for TFT displays
///
///         https://www.ti.com/lit/ds/symlink/tsc2007.pdf
///
/// \date   20220823
/// \author Maximilian Seesslen
///
//----------------------------------------------------------------------------


//---Includes-----------------------------------------------------------------


#include <biwak/touch_tsc2007.h>
#include <arpa/inet.h>
#include <lepto/log.h>


//---Forward declarations-----------------------------------------------------


//---Implementation-----------------------------------------------------------


void CTouchTsc2007::readTouch( int &xRaw, int &yRaw, int &z1Raw, int &z2Raw )
{
   int sta=0;
   uint16_t x=0, y=0, z1=0, z2=0;

   // The readout of the values causes interrupts. We just disable them-
   m_input.enableInterrupt(false);
   sta=m_device.i2cReadData(CMD_READ_X, &x, sizeof(x));
   if(sta)
   {
      printf("Error: Could not read touch I2C\n");
      return;
   }
   //int NO_IRQ=1<<2;
   int NO_IRQ=0;
   m_device.i2cReadData( CMD_READ_Y | NO_IRQ, &y, sizeof(y));
   m_device.i2cReadData( CMD_READ_Z1| NO_IRQ, &z1, sizeof(z1));
   m_device.i2cReadData( CMD_READ_Z2| NO_IRQ, &z2, sizeof(z2));
   m_input.enableInterrupt(true);

   xRaw = ntohs(x)>>4;
   yRaw = ntohs(y)>>4;
   z1Raw = ntohs(z1)>>4;
   z2Raw = ntohs(z2)>>4;

   // int force=0xFFF-(m_z2Raw-m_z1Raw);
   //lWarning("Force: 0x%X", force);
   m_timerReadout=lrNow();

   return;
}


void CTouchTsc2007::slotTouchPressed(bool value)
{
   // An unpressed display had high value
   // [#333]
   eventLoop(value, true /* override */);
   return;
   switch( m_state )
   {
      case eIdle:
      {
         if(!value)
         {
         }
         else
         {
            lWarning("Touch: unplausible transition in idle to high");
         }
         break;
      }
      case eReleaseDebounce:
      case eReleased:
      {
         if(!value)
         {
            m_state = ePressed;
         }
         break;
      }
      case ePressed:
      {
         if(value)
         {
            m_state = eEnterReleaseDebounce;
         }
         break;
      }
      default:
      {
         break;
      }
   }

   return;
}


void CTouchTsc2007::eventLoop(bool value /*=false*/, bool override /*=false*/ )
{
   // An unpressed display had high value
   // [#333]

   if(!override)
   {
      value=m_input.getValue();
   }

   switch(m_state)
   {
      case eIdle:
      {
         if( ! value )
         {
            if(override)
            {
               lInfo("Touch: probably lost interrupt");
            }
            //slotTouchPressed(false);
            // STate is changed in slot.
            readTouch();
            m_state = eHit;
         }
         else
         {
            break;
         }
         break;
      }
      case eHit:
      {
         if( ! value )
         {
            readTouch();
         }
         m_debounceTimer=lrNow();
         m_state=eHitEvent;
         // Fall-through on purpose
      }
      case eHitEvent:
      {
         if( override )
         {
            break;
         }
         CTouch::SEvent event{
               m_calibration.getX(m_xRaw), m_calibration.getY(m_yRaw),
                     CTouch::EEventType::pressed };
         signalEvent.emitSignal( event );
         m_state=ePressed;
         break;
      }
      case ePressed:
      {
         if( value )
         {
            //lWarning("Touch: probably lost interrupt");
            m_state=eEnterReleaseDebounce;
         }
         else
         {
            #if 1
            // 1/6 sec recognizable
            if( ! override )
            {
               if( lrElapsedMSeconds( m_timerReadout ) > 1000/12 )
               {
                  // [#337] Only emit signal when touch was actually moved
                  int xRaw, yRaw, z1Raw, z2Raw;
                  readTouch( xRaw, yRaw, z1Raw, z2Raw );
                  int diffX = abs( m_calibration.getX(m_xRaw)
                                   - m_calibration.getX(xRaw) );
                  int diffY = abs( m_calibration.getY(m_yRaw)
                                   - m_calibration.getY(yRaw) );
                  // Need at least 2 pixels difference
                  if( ( diffX > 1 ) || ( diffY > 1 ) )
                  {
                     setTouch( xRaw, yRaw, z1Raw, z2Raw );
                     CTouch::SEvent event{
                           m_calibration.getX(m_xRaw), m_calibration.getY(m_yRaw),
                                 CTouch::EEventType::moved };
                     signalEvent.emitSignal( event );
                  }
               }
            }
            #endif
         }
         break;
      }
      case eEnterReleaseDebounce:
      {
         m_debounceTimer=lrNow();
         m_state=eReleaseDebounce;
         break;
      }
      case eReleaseDebounce:
      {
         if( lrElapsedMSeconds(m_debounceTimer) > DEBOUNCE_MSEC)
         {
            m_state=eReleased;
         }
         if( !m_input.getValue() )
         {
            m_state=ePressed;
         }
         break;
      }
      case eReleased:
      {
         if( !override )
         {
            CTouch::SEvent event{
                  m_calibration.getX(m_xRaw), m_calibration.getY(m_yRaw),
                        CTouch::EEventType::released };
            signalEvent.emitSignal( event );
            m_state=eIdle;
         }
         break;
      }
      default:
      {
         break;
      }
   }
}

//---fin----------------------------------------------------------------------
