/*
    this is an extract from kmclib (see github, dj0abr repos)
    it works on raspberry pi only

* Raspberry PI / Zero AddOn Board specially for Ham Radio Applications
* ====================================================================
* Author: DJ0ABR
*
*   (c) DJ0ABR
*   www.dj0abr.de
*
*   This program is free software; you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation; either version 2 of the License, or
*   (at your option) any later version.
*
*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with this program; if not, write to the Free Software
*   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* 
encoder.cpp
===========

function to handle rotary encoder

Usage:
======
initialize and assign ports to the encoders
-------------------------------------------
up to 3 encoders are supported, If not used, then assign port nunmber -1
init_rotencoder(int portA1, int portB1, int portA2, int portB2, int portA3, int portB3)
see gpio.h _INPUTS_ for valid port numbers

read encoder:
-------------
int getEncSteps(int idx)
idx ... encoder number 0,1 or 2
returns the number of steps since last read

*
*/

#include "../qo100trx.h"


int init_gpio();
int getPort(char *port);

#define NUM_OF_ENCODERS 2

pthread_mutex_t     rotenc_crit_sec;
#define LOCK	    pthread_mutex_lock(&(rotenc_crit_sec))
#define UNLOCK	    pthread_mutex_unlock(&(rotenc_crit_sec))

void *rotencproc(void *);    

char portA[NUM_OF_ENCODERS][3] = {"fa","va"};
char portB[NUM_OF_ENCODERS][3] = {"fb","vb"};

int encsteps[NUM_OF_ENCODERS];

pthread_t rotenc_tid;

// port numbers see gpio.h _INPORTS_
// -1 if not used
void init_rotencoder()
{
    // use the rotary encoder on a raspberry board only
    // RASPI is passed to the Makefile as: make RASPI='-DRASPI'
    #ifndef RASPI
    return;
    #endif 

    if(init_gpio() == -1) return;

    memset(&encsteps, 0, sizeof(int)*NUM_OF_ENCODERS);

    int pret = pthread_create(&rotenc_tid,NULL,rotencproc, NULL);
    if(pret)
    {
        printf("rotenc process NOT started\n");
        exit(0);
    }
}

int getEncSteps(int idx)
{
    int v;
    LOCK;
    v = encsteps[idx];
    encsteps[idx] = 0;
    UNLOCK;
    return v;
}

void *rotencproc(void *pdata)
{
    pthread_detach(pthread_self());
    
    printf("rotenc process started\n");

    int aval[NUM_OF_ENCODERS];
    int bval[NUM_OF_ENCODERS];
    int oldaval[NUM_OF_ENCODERS]={0,0};
    while(keeprunning)
    {
        for(int i=0; i<NUM_OF_ENCODERS; i++)
        {
            aval[i] = getPort(portA[i]);
            bval[i] = getPort(portB[i]);

            if(aval[i]==1 && oldaval[i]==0)
            {
                // falling edge of port A
                int dir = -1;
                if(bval[i] == 1) dir = 1;
                LOCK;
                encsteps[i] += dir;
                UNLOCK;
            }
            oldaval[i] = aval[i];
        }

        usleep(100);
    }

    printf("exit rotenc thread\n");
    pthread_exit(NULL);
}

// 0=RX, 1=TX, 2=just released, 3=just pressed
int test_ptt_gpio()
{
    #ifndef RASPI
    return -1;
    #endif 

static int gold = -1;
int ret = 0;

    int ptt = getPort("p");

    if(gold != -1)
    {
        if(ptt == 0)
        {
            // PTT is pressed
            if(gold == 0) ret = 1;
            else ret = 3;
        }
        else
        {
            // PTT is released
            if(gold == 0) ret = 2;
            else ret = 0;
        }
    }

    gold = ptt;

    return ret;
}

// 0=unmuted, 1=muted, 2=just unmuted, 3=just muted
int test_mute_gpio()
{
    #ifndef RASPI
    return -1;
    #endif 
    
static int gold = -1;
int ret = 0;

    int mute = getPort("m");

    if(gold != -1)
    {
        if(mute == 0)
        {
            // mute is pressed
            if(gold == 0) ret = 1;
            else ret = 3;
        }
        else
        {
            // mute is released
            if(gold == 0) ret = 2;
            else ret = 0;
        }
    }

    gold = mute;

    return ret;
}

/* ============= Linux GPIO interface =============
 requires packages: gpiod  libgpiod-dev

 command line interface see:
 https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/README

 C-Functions see: /usr/include/gpiod.h

 connect rotary encoders to these pins:

 frequency-encoder A ... GPIO17 (Pin11)
 frequency-encoder B ... GPIO27 (Pin13)
 volume   -encoder A ... GPIO4  (Pin 7)
 volume   -encoder B ... GPIO22 (Pin15)

 PTT input           ... GPIO18 (Pin12)
 Mute                ... GPIO23 (Pin16)

 PTT output          ... GPIO24 (Pin18)
*/

#include <gpiod.h>

struct gpiod_chip *chip = NULL;
struct gpiod_line *fa = NULL;
struct gpiod_line  *fb = NULL, *va = NULL, *vb = NULL, *gptt = NULL, *gmute = NULL, *pttout = NULL;

int init_gpio()
{
    int ret;

    chip= gpiod_chip_open("/dev/gpiochip0");
    if(!chip)
    {
        printf("cannot open GPIO chip\n");
        return -1;
    }

    //fa= gpiod_chip_get_info(chip,17);
    if (!fa) {
        printf("cannot access GPIO17\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //fb= gpiod_chip_get_line(chip,27);
    if (!fb) {
        printf("cannot access GPIO27\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //va= gpiod_chip_get_line(chip,4);
    if (!va) {
        printf("cannot access GPIO4\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //vb= gpiod_chip_get_line(chip,22);
    if (!vb) {
        printf("cannot access GPIO22\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //gptt = gpiod_chip_get_line(chip,18);
    if (!gptt) {
        printf("cannot access GPIO18\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //gmute = gpiod_chip_get_line(chip,23);
    if (!gmute) {
        printf("cannot access GPIO23\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //pttout = gpiod_chip_get_line(chip,24);
    if (!pttout) {
        printf("cannot access GPIO24\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //ret = gpiod_line_request_get_fd(fa, "huhu");
    if (ret) {
        printf("cannot init GPIO17 for input\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //ret = gpiod_line_request_input(fb, "huhu");
    if (ret) {
        printf("cannot init GPIO27 for input\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //ret = gpiod_line_request_input(va, "huhu");
    if (ret) {
        printf("cannot init GPIO4 for input\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //ret = gpiod_line_request_input(vb, "huhu");
    if (ret) {
        printf("cannot init GPIO22 for input\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //ret = gpiod_line_request_input(gptt, "huhu");
    if (ret) {
        printf("cannot init GPIO18 for input\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //ret = gpiod_line_request_input(gmute, "huhu");
    if (ret) {
        printf("cannot init GPIO23 for input\n");
        gpiod_chip_close(chip);
        return -1;
    }

    //ret = gpiod_line_request_get_fd(pttout, "huhu", 0);
    if (ret) {
        printf("cannot init GPIO24 for output\n");
        gpiod_chip_close(chip);
        return -1;
    }

    printf("GPIOs initialized\n");

    return 0;
}
void close_gpio()
{
 /*   if(fa) gpiod_line_request(fa);
    if(fb) gpiod_line_request(fb);
    if(va) gpiod_line_request(va);
    if(vb) gpiod_line_request(vb);
    if(gptt) gpiod_line_request(gptt);
    if(gmute) gpiod_line_request(gmute);
*/    
    if(chip) gpiod_chip_close(chip);   
}

// get status of physical port
int getPort(char *port)
{
    #ifndef RASPI
    return 0;
    #endif 

    if(port[0] == 'f')
    {
        //if(port[1] == 'a') return gpiod_line_value(fa);
        //return gpiod_line_value(fb);
    }

    if(port[0] == 'v')
    {
        //if(port[1] == 'a') return gpiod_line_value(va);
        //return gpiod_line_value(vb);
    }

    //if(port[0] == 'p')
        //return gpiod_line_value(gptt);

    //if(port[0] == 'm')
        //return gpiod_line_value(gmute);

    return 0;
}

void setPort(char *port, int value)
{
    #ifndef RASPI
    return;
    #endif 

    if(port[0] == 'p')
    {
        //gpiod_line_value(pttout,value);
    }
}

