#include <includes.h>
#include "keyboard.h"
#include "app_serv.h"
#include "data.h"
#include "datadesc.h"
#include "mode.h"

#define   KBRD_QUERY_LEN      4

OS_STK  KbrdTaskStk[KBRD_TASK_STK_SIZE];
OS_EVENT  *KbrdQuery = NULL;
void     *KbrdTbl[KBRD_QUERY_LEN];

#if defined(BOARD_SOLARIUM_WEB)
    #define KBRD_SCAN_LINE1()  {FIO0CLR_bit.P0_28 = 1; FIO0SET_bit.P0_27 = 1; FIO3SET_bit.P3_26 = 1; FIO3SET_bit.P3_25 = 1;}
    #define KBRD_SCAN_LINE2()  {FIO0SET_bit.P0_28 = 1; FIO0CLR_bit.P0_27 = 1; FIO3SET_bit.P3_26 = 1; FIO3SET_bit.P3_25 = 1;}
    #define KBRD_SCAN_LINE3()  {FIO0SET_bit.P0_28 = 1; FIO0SET_bit.P0_27 = 1; FIO3CLR_bit.P3_26 = 1; FIO3SET_bit.P3_25 = 1;}
    #define KBRD_SCAN_LINE4()  {FIO0SET_bit.P0_28 = 1; FIO0SET_bit.P0_27 = 1; FIO3SET_bit.P3_26 = 1; FIO3CLR_bit.P3_25 = 1;}
#elif defined(BOARD_SOLARIUM_VLAD)
    #define KBRD_SCAN_LINE1()  {FIO2CLR_bit.P2_3 = 1; FIO1SET_bit.P1_29 = 1; FIO2SET_bit.P2_13 = 1;}
    #define KBRD_SCAN_LINE2()  {FIO2SET_bit.P2_3 = 1; FIO1CLR_bit.P1_29 = 1; FIO2SET_bit.P2_13 = 1;}
    #define KBRD_SCAN_LINE3()  {FIO2SET_bit.P2_3 = 1; FIO1SET_bit.P1_29 = 1; FIO2CLR_bit.P2_13 = 1;}
#endif

void  KbrdTask(void *p_arg);

unsigned long kbrd_state;

void KbrdPost(unsigned long key)
{
    OSQPost(KbrdQuery, (void *)key);
}

void InitKbrd()
{
#if defined(BOARD_SOLARIUM_WEB)
  
  // сканирующие линии
  PINSEL1_bit.P0_28 = 0x0;
  PINMODE1_bit.P0_28 = 0;
  FIO0DIR_bit.P0_28 = 1;
  FIO0MASK_bit.P0_28 = 0;

  PINSEL1_bit.P0_27 = 0x0;
  PINMODE1_bit.P0_27 = 0;
  FIO0DIR_bit.P0_27 = 1;
  FIO0MASK_bit.P0_27 = 0;
  
  PINSEL7_bit.P3_26 = 0x0;
  PINMODE7_bit.P3_26 = 0;
  FIO3DIR_bit.P3_26 = 1;
  FIO3MASK_bit.P3_26 = 0;

  PINSEL7_bit.P3_25 = 0x0;
  PINMODE7_bit.P3_25 = 0;
  FIO3DIR_bit.P3_25 = 1;
  FIO3MASK_bit.P3_25 = 0;
  
  // входные линии
  PINSEL3_bit.P1_18 = 0x0;
  PINMODE3_bit.P1_18 = 0;
  FIO1DIR_bit.P1_18 = 0;
  FIO1MASK_bit.P1_18 = 0;
  
  PINSEL3_bit.P1_19 = 0x0;
  PINMODE3_bit.P1_19 = 0;
  FIO1DIR_bit.P1_19 = 0;
  FIO1MASK_bit.P1_19 = 0;

  PINSEL3_bit.P1_20 = 0x0;
  PINMODE3_bit.P1_20 = 0;
  FIO1DIR_bit.P1_20 = 0;
  FIO1MASK_bit.P1_20 = 0;

#endif

#if defined(BOARD_SOLARIUM_VLAD)
  PINSEL4_bit.P2_3 = 0x0;
  PINMODE4_bit.P2_3 = 0;
  FIO2DIR_bit.P2_3 = 1;
  FIO2MASK_bit.P2_3 = 0;
  FIO2SET_bit.P2_3 = 1;
   
  PINSEL3_bit.P1_29 = 0x0;
  PINMODE3_bit.P1_29 = 0;
  FIO1DIR_bit.P1_29 = 1;
  FIO1MASK_bit.P1_29 = 0;
  FIO1SET_bit.P1_29 = 1;

  PINSEL4_bit.P2_13 = 0x0;
  PINMODE4_bit.P2_13 = 0;
  FIO2DIR_bit.P2_13 = 1;
  FIO2MASK_bit.P2_13 = 0;
  FIO2SET_bit.P2_13 = 1;

  PINSEL3_bit.P1_23 = 0x0;
  PINMODE3_bit.P1_23 = 0;
  FIO1DIR_bit.P1_23 = 0;
  FIO1MASK_bit.P1_23 = 0;

  PINSEL3_bit.P1_25 = 0x0;
  PINMODE3_bit.P1_25 = 0;
  FIO1DIR_bit.P1_25 = 0;
  FIO1MASK_bit.P1_25 = 0;

  PINSEL3_bit.P1_24 = 0x0;
  PINMODE3_bit.P1_24 = 0;
  FIO1DIR_bit.P1_24 = 0;
  FIO1MASK_bit.P1_24 = 0;

  PINSEL7_bit.P3_26 = 0x0;
  PINMODE7_bit.P3_26 = 0;
  FIO3DIR_bit.P3_26 = 0;
  FIO3MASK_bit.P3_26 = 0;

  PINSEL3_bit.P1_18 = 0x0;
  PINMODE3_bit.P1_18 = 0;
  FIO1DIR_bit.P1_18 = 0;
  FIO1MASK_bit.P1_18 = 0;

  PINSEL0_bit.P0_5 = 0x0;
  PINMODE0_bit.P0_5 = 0;
  FIO0DIR_bit.P0_5 = 0;
  FIO0MASK_bit.P0_5 = 0;

  PINSEL9_bit.P4_28 = 0x0;
  PINMODE9_bit.P4_28 = 0;
  FIO4DIR_bit.P4_28 = 0;
  FIO4MASK_bit.P4_28 = 0;

  PINSEL3_bit.P1_28 = 0x0;
  PINMODE3_bit.P1_28 = 0;
  FIO1DIR_bit.P1_28 = 0;
  FIO1MASK_bit.P1_28 = 0;

  PINSEL3_bit.P1_26 = 0x0;
  PINMODE3_bit.P1_26 = 0;
  FIO1DIR_bit.P1_26 = 0;
  FIO1MASK_bit.P1_26 = 0;
      
#endif
  
#if defined(BOARD_CENTRAL_CARWASH) || defined(BOARD_POST_CARWASH) || defined(BOARD_SOLARIUM_VLAD)
  // кнопка OK
  PINSEL3_bit.P1_20 = 0x0;
  PINMODE3_bit.P1_20 = 0;
  FIO1DIR_bit.P1_20 = 0;
  FIO1MASK_bit.P1_20 = 0;
#endif
  
#if defined(BOARD_CENTRAL_CARWASH) || defined(BOARD_SOLARIUM_VLAD)
  // подсветка кнопки OK
  PINSEL3_bit.P1_21 = 0x0;
  PINMODE3_bit.P1_21 = 0;
  FIO1DIR_bit.P1_21 = 1;
  FIO1MASK_bit.P1_21 = 0;
  FIO1CLR_bit.P1_21 = 1;
#endif
  
#if defined(BOARD_CENTRAL_CARWASH)
  // кнопка 1
  PINSEL3_bit.P1_18 = 0x0;
  PINMODE3_bit.P1_18 = 0;
  FIO1DIR_bit.P1_18 = 0;
  FIO1MASK_bit.P1_18 = 0;

  // подсветка кнопки 1
  PINSEL3_bit.P1_19 = 0x0;
  PINMODE3_bit.P1_19 = 0;
  FIO1DIR_bit.P1_19 = 1;
  FIO1MASK_bit.P1_19 = 0;
  FIO1CLR_bit.P1_19 = 1;
    
  // кнопка 2
  PINSEL7_bit.P3_26 = 0x0;
  PINMODE7_bit.P3_26 = 0;
  FIO3DIR_bit.P3_26 = 0;
  FIO3MASK_bit.P3_26 = 0;

  // подсветка кнопки 2
  PINSEL7_bit.P3_25 = 0x0;
  PINMODE7_bit.P3_25 = 0;
  FIO3DIR_bit.P3_25 = 1;
  FIO3MASK_bit.P3_25 = 0;
  FIO3CLR_bit.P3_25 = 1;

  // кнопка 3
  PINSEL1_bit.P0_26 = 0x0;
  PINMODE1_bit.P0_26 = 0;
  FIO0DIR_bit.P0_26 = 0;
  FIO0MASK_bit.P0_26 = 0;

  // подсветка кнопки 3
  PINSEL1_bit.P0_25 = 0x0;
  PINMODE1_bit.P0_25 = 0;
  FIO0DIR_bit.P0_25 = 1;
  FIO0MASK_bit.P0_25 = 0;
  FIO0CLR_bit.P0_25 = 1;
  
  // кнопка 4
  PINSEL0_bit.P0_9 = 0x0;
  PINMODE0_bit.P0_9 = 0;
  FIO0DIR_bit.P0_9 = 0;
  FIO0MASK_bit.P0_9 = 0;

  // подсветка кнопки 4
  PINSEL4_bit.P2_2 = 0x0;
  PINMODE4_bit.P2_2 = 0;
  FIO2DIR_bit.P2_2 = 1;
  FIO2MASK_bit.P2_2 = 0;
  FIO2CLR_bit.P2_2 = 1;

  // кнопка 5
  PINSEL0_bit.P0_7 = 0x0;
  PINMODE0_bit.P0_7 = 0;
  FIO0DIR_bit.P0_7 = 0;
  FIO0MASK_bit.P0_7 = 0;

  // подсветка кнопки 5
  PINSEL0_bit.P0_8 = 0x0;
  PINMODE0_bit.P0_8 = 0;
  FIO0DIR_bit.P0_8 = 1;
  FIO0MASK_bit.P0_8 = 0;
  FIO0CLR_bit.P0_8 = 1;

  // кнопка 6
  PINSEL0_bit.P0_5 = 0x0;
  PINMODE0_bit.P0_5 = 0;
  FIO0DIR_bit.P0_5 = 0;
  FIO0MASK_bit.P0_5 = 0;

  // подсветка кнопки 6
  PINSEL0_bit.P0_6 = 0x0;
  PINMODE0_bit.P0_6 = 0;
  FIO0DIR_bit.P0_6 = 1;
  FIO0MASK_bit.P0_6 = 0;
  FIO0CLR_bit.P0_6 = 1;

  // кнопка 7
  PINSEL3_bit.P1_28 = 0x0;
  PINMODE3_bit.P1_28 = 0;
  FIO1DIR_bit.P1_28 = 0;
  FIO1MASK_bit.P1_28 = 0;

  // подсветка кнопки 7
  PINSEL3_bit.P1_27 = 0x0;
  PINMODE3_bit.P1_27 = 0;
  FIO1DIR_bit.P1_27 = 1;
  FIO1MASK_bit.P1_27 = 0;
  FIO1CLR_bit.P1_27 = 1;

  // кнопка 8
  PINSEL3_bit.P1_26 = 0x0;
  PINMODE3_bit.P1_26 = 0;
  FIO1DIR_bit.P1_26 = 0;
  FIO1MASK_bit.P1_26 = 0;

  // подсветка кнопки 8
  PINSEL0_bit.P0_0 = 0x0;
  PINMODE0_bit.P0_0 = 0;
  FIO0DIR_bit.P0_0 = 1;
  FIO0MASK_bit.P0_0 = 0;
  FIO0CLR_bit.P0_0 = 1;

  // кнопка Отмена
  PINSEL9_bit.P4_28 = 0x0;
  PINMODE9_bit.P4_28 = 0;
  FIO4DIR_bit.P4_28 = 0;
  FIO4MASK_bit.P4_28 = 0;

  // подсветка кнопки Отмена
  PINSEL0_bit.P0_4 = 0x0;
  PINMODE0_bit.P0_4 = 0;
  FIO0DIR_bit.P0_4 = 1;
  FIO0MASK_bit.P0_4 = 0;
  FIO0CLR_bit.P0_4 = 1;
  
#endif
  
  kbrd_state = 0;
  
  // создадим очередь событий клавиатуры и задачу опроса клавиатуры
  if (KbrdQuery == NULL)
  {
      KbrdQuery = OSQCreate(&KbrdTbl[0], KBRD_QUERY_LEN);
      OSTaskCreate(KbrdTask, (void *)0, (OS_STK *)&KbrdTaskStk[KBRD_TASK_STK_SIZE-1], KBRD_TASK_PRIO);
  }
}

void SetBacklight(CPU_INT08U led, CPU_INT08U state)
{
#if defined(BOARD_SOLARIUM_VLAD)
    if (led == LED_OK)
    {
        if (state) FIO1SET_bit.P1_21 = 1;
        else FIO1CLR_bit.P1_21 = 1;
    }
#endif
        
#if defined(BOARD_CENTRAL_CARWASH)
    switch (led)
    {
        case LED_POST1:
            if (state) FIO1SET_bit.P1_19 = 1;
            else FIO1CLR_bit.P1_19 = 1;
            break;
        case LED_POST2:
            if (state) FIO3SET_bit.P3_25 = 1;
            else FIO3CLR_bit.P3_25 = 1;
            break;
        case LED_POST3:
            if (state) FIO0SET_bit.P0_25 = 1;
            else FIO0CLR_bit.P0_25 = 1;
            break;
        case LED_POST4:
            if (state) FIO2SET_bit.P2_2 = 1;
            else FIO2CLR_bit.P2_2 = 1;
            break;
        case LED_POST5:
            if (state) FIO0SET_bit.P0_8 = 1;
            else FIO0CLR_bit.P0_8 = 1;
            break;
        case LED_POST6:
            if (state) FIO0SET_bit.P0_6 = 1;
            else FIO0CLR_bit.P0_6 = 1;
            break;
        case LED_POST7:
            if (state) FIO1SET_bit.P1_27 = 1;
            else FIO1CLR_bit.P1_27 = 1;
            break;
        case LED_POST8:
            if (state) FIO0SET_bit.P0_0 = 1;
            else FIO0CLR_bit.P0_0 = 1;
            break;
        case LED_OK:
            if (state) FIO1SET_bit.P1_21 = 1;
            else FIO1CLR_bit.P1_21 = 1;
            break;
        case LED_CANSEL:
            if (state) FIO0SET_bit.P0_4 = 1;
            else FIO0CLR_bit.P0_4 = 1;
            break;
    }
#endif
}

void SelAllLeds(CPU_INT08U state)
{
#if defined(BOARD_CENTRAL_CARWASH)
    SetBacklight(LED_POST1, state);
    SetBacklight(LED_POST2, state);
    SetBacklight(LED_POST3, state);
    SetBacklight(LED_POST4, state);
    SetBacklight(LED_POST5, state);
    SetBacklight(LED_POST6, state);
    SetBacklight(LED_POST7, state);
    SetBacklight(LED_POST8, state);
    SetBacklight(LED_OK, state);
    SetBacklight(LED_CANSEL, state);
#endif
    
#if defined(BOARD_SOLARIUM_VLAD)
    SetBacklight(LED_OK, state);
#endif
}

void  KbrdTask(void *p_arg)
{
  unsigned long prew_state = 0;
  
  while (1)
    {
      unsigned long state;

      state = 0;      

      #if defined(BOARD_CENTRAL_CARWASH)
      OSTimeDly(20);
      if (!FIO1PIN_bit.P1_18) state |= (1UL << KEY_POST1);
      if (!FIO3PIN_bit.P3_26) state |= (1UL << KEY_POST2);
      if (!FIO0PIN_bit.P0_26) state |= (1UL << KEY_POST3);
      if (!FIO0PIN_bit.P0_9)  state |= (1UL << KEY_POST4);
      if (!FIO0PIN_bit.P0_7)  state |= (1UL << KEY_POST5);
      if (!FIO0PIN_bit.P0_5)  state |= (1UL << KEY_POST6);
      if (!FIO1PIN_bit.P1_28) state |= (1UL << KEY_POST7);
      if (!FIO1PIN_bit.P1_26) state |= (1UL << KEY_POST8);
      if (!FIO4PIN_bit.P4_28) state |= (1UL << KEY_CANSEL);
      #endif
      
      #if defined(BOARD_SOLARIUM_WEB)
      OSTimeDly(16);
      KBRD_SCAN_LINE1();
      OSTimeDly(1);
      if (!FIO1PIN_bit.P1_18) state |= (1UL << KEY_DIGIT1);
      if (!FIO1PIN_bit.P1_19) state |= (1UL << KEY_DIGIT2);
      if (!FIO1PIN_bit.P1_20) state |= (1UL << KEY_DIGIT3);
      KBRD_SCAN_LINE2();
      OSTimeDly(1);
      if (!FIO1PIN_bit.P1_18) state |= (1UL << KEY_DIGIT4);
      if (!FIO1PIN_bit.P1_19) state |= (1UL << KEY_DIGIT5);
      if (!FIO1PIN_bit.P1_20) state |= (1UL << KEY_DIGIT6);
      KBRD_SCAN_LINE3();
      OSTimeDly(1);
      if (!FIO1PIN_bit.P1_18) state |= (1UL << KEY_DIGIT7);
      if (!FIO1PIN_bit.P1_19) state |= (1UL << KEY_DIGIT8);
      if (!FIO1PIN_bit.P1_20) state |= (1UL << KEY_DIGIT9);
      KBRD_SCAN_LINE4();
      OSTimeDly(1);
      if (!FIO1PIN_bit.P1_18) state |= (1UL << KEY_STAR);
      if (!FIO1PIN_bit.P1_19) state |= (1UL << KEY_DIGIT0);
      if (!FIO1PIN_bit.P1_20) state |= (1UL << KEY_SHARP);
      #endif      
     
      #if defined(BOARD_SOLARIUM_VLAD)
      OSTimeDly(17);
      KBRD_SCAN_LINE1();
      OSTimeDly(1);
      if (!FIO1PIN_bit.P1_23) state |= (1UL << KEY_F1);
      if (!FIO1PIN_bit.P1_25) state |= (1UL << KEY_F2);
      if (!FIO1PIN_bit.P1_24) state |= (1UL << KEY_F3);
      KBRD_SCAN_LINE2();
      OSTimeDly(1);
      if (!FIO1PIN_bit.P1_23) state |= (1UL << KEY_LEFT);
      if (!FIO1PIN_bit.P1_25) state |= (1UL << KEY_UP);
      if (!FIO1PIN_bit.P1_24) state |= (1UL << KEY_RIGHT);
      KBRD_SCAN_LINE3();
      OSTimeDly(1);
      if (!FIO1PIN_bit.P1_23) state |= (1UL << KEY_STOP);
      if (!FIO1PIN_bit.P1_25) state |= (1UL << KEY_DOWN);
      if (!FIO1PIN_bit.P1_24) state |= (1UL << KEY_START);

      if (!FIO3PIN_bit.P3_26) state |= (1UL << KEY_SOLAR_START1);
      if (!FIO1PIN_bit.P1_18) state |= (1UL << KEY_SOLAR_STOP1);
      if (!FIO0PIN_bit.P0_5) state |= (1UL << KEY_SOLAR_START2);
      if (!FIO4PIN_bit.P4_28) state |= (1UL << KEY_SOLAR_STOP2);
      if (!FIO1PIN_bit.P1_28) state |= (1UL << KEY_SOLAR_START3);
      if (!FIO1PIN_bit.P1_26) state |= (1UL << KEY_SOLAR_STOP3);

      #endif

      #if defined(BOARD_POST_CARWASH)
      OSTimeDly(20);
      #endif

      #if defined(BOARD_CENTRAL_CARWASH) || defined(BOARD_POST_CARWASH) || defined(BOARD_SOLARIUM_VLAD)
      if (!FIO1PIN_bit.P1_20) state |= (1UL << KEY_START);
      #endif
      
      if (prew_state == state)
        { // устранили дребезг
          if (kbrd_state ^ state)
            { // есть изменения нажатия
              for (unsigned long i = 0; i < KEY_COUNT; i++)
                {
                  // ловим передний фронт при нажатии
                  if (!(kbrd_state & (1UL << i)) && (state & (1UL << i)))
                    {
                      #if defined(BOARD_CENTRAL_CARWASH)
                      if ((GetMode() != MODE_WORK) && (i >= KEY_POST1) && (i <= KEY_POST8))
                      {
                          CPU_INT32U action;
                          GetData(&KeyActionDesc, &action, i - KEY_POST1, DATA_FLAG_DIRECT_INDEX);
                          switch (action)
                          {
                              case KEY_ACTION_EMPTY:
                                  break;
                              case KEY_ACTION_LEFT:
                                  i = KEY_LEFT;
                                  OSQPost(KbrdQuery, (void *)i);
                                  break;
                              case KEY_ACTION_RIGHT:
                                  i = KEY_RIGHT;
                                  OSQPost(KbrdQuery, (void *)i);
                                  break;
                              case KEY_ACTION_DOWN:
                                  i = KEY_DOWN;
                                  OSQPost(KbrdQuery, (void *)i);
                                  break;
                              case KEY_ACTION_UP:
                                  i = KEY_UP;
                                  OSQPost(KbrdQuery, (void *)i);
                                  break;
                              case KEY_ACTION_OK:
                                  i = KEY_START;
                                  OSQPost(KbrdQuery, (void *)i);
                                  break;
                              case KEY_ACTION_CANSEL:
                                  i = KEY_STOP;
                                  OSQPost(KbrdQuery, (void *)i);
                                  break;
                          }
                      }
                      else
                      {
                          OSQPost(KbrdQuery, (void *)i);
                          PostUserEvent(EVENT_KEY_EMPTY+i); // пользователю тоже постим
                      }
                      #else
                      OSQPost(KbrdQuery, (void *)i);
                      PostUserEvent(EVENT_KEY_EMPTY+i); // пользователю тоже постим
                      #if defined(BOARD_SOLARIUM_WEB)
                      ZummerBeep();
                      #endif
                      #endif

                    }
                }
            }
          kbrd_state = state;
        }
      
      prew_state = state;
    }
    
}

int GetKbrdEvent(int* event)
{
  CPU_INT08U err = 0; 
  int evt  = (int)OSQPend(KbrdQuery, 1, &err);
  if (err != 0) return 0;
  *event = evt;
  return 1;  
}

unsigned long GetKbrdState(void)
{
    unsigned long state; 
    #if OS_CRITICAL_METHOD == 3
    OS_CPU_SR  cpu_sr = 0;
    #endif
    OS_ENTER_CRITICAL();
    state = kbrd_state;
    OS_EXIT_CRITICAL();
    return state;
}   
    