/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2015  Ladislav Vaiz <ok1zia@nagano.cz>

    This program is free software; you can redistribute it and/or 
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

28.Oct 2008:
Modification by dl5ybz  for fast fix .. this file needs review by Lada (or anyone else who codes in C) ..!
Winkey2 works for me  so far now  73 de Olaf / DL5YBZ

    Documentation: http://k1el.tripod.com/files/WinkeyInterfaceGuide.pdf
*/

#include "header.h"
#include "bfu.h"
#include "cwdaemon.h"
#include "davac4.h"
#include "fifo.h"
#include "main.h"
#include "rc.h"
#include "terminal.h"
#include "winkey.h"

int winkey_init_serial(struct cwdaemon *cwda){
	cwda->zser = zserial_init_serial(cfg->cwda_device);
    cwda->zser_fd = -1;
	// set 1200 baud, 8bit, no parity, two stop bits
	zserial_set_line(cwda->zser, 1200, 8, 'N', 2);
	zserial_nolocks(cwda->zser, cfg->nolocks);
    winkey_open(cwda, 1);
	return 0;
}

int winkey_init_tcp(struct cwdaemon *cwda){
    dbg("winkey_init_tcp\n");
	cwda->zser = zserial_init_tcp(cfg->cwda_hostname, cfg->cwda_udp_port);
    cwda->zser_fd = -1;
	//// set 1200 baud, 8bit, no parity, two stop bits
	//zserial_set_line(cwda->zser, 1200, 8, 'N', 2); // useless over TCP
    winkey_open(cwda, 1);
	return 0;
}

int winkey_write(struct cwdaemon *cwda, void *data, int len){
    int ret;

    ret = zserial_write(cwda->zser, data, len);
    if (ret < 0){
        dbg("winkey_write: zserial_write failed\n");
        if (cwda->zser_fd >= 0){
            zselect_set(zsel, cwda->zser_fd, NULL, NULL, NULL, cwda);
            cwda->zser_fd = -1;
        }
    }
    return ret;
}

int winkey_open(struct cwdaemon *cwda, int verbose){
	int i;
	char s[256];

    dbg("winkey_open(verbose=%d)\n", verbose);

	if (zserial_open(cwda->zser)){
		if (verbose) log_addf("Winkey: %s", zserial_errorstr(cwda->zser));
//        winkey_reset(cwda);
//        winkey_free(cwda);
        return -1;
    }

	
    
    // to power up enable DTR and disable RTS
    zserial_dtr(cwda->zser, 1);
	zserial_rts(cwda->zser, 0);
    
    if (!cfg->wk_wk2){
        // delay 500ms for winkey init
        usleep(500000); 

        // calibration command
        winkey_write(cwda, "\x00\x00", 2); 
        usleep(100000); 
        winkey_write(cwda, "\xff", 1); 
    }

    // is winkey attached? echo command
	winkey_write(cwda, "\x00\x04\x55", 3);
    i = winkey_read(cwda, 999);
//    dbg("winkey_read: %d\n", i);
    if (i < 0){
        if (verbose) log_addf(VTEXT(T_CANT_INIT_WINKEY_S), cfg->cwda_device);
        zserial_close(cwda->zser);
        return -1;
    }
    
    // open winkey hostmode
    winkey_write(cwda, "\x00\x02", 2);
    i = winkey_read(cwda, 500);
//    dbg("winkey_read: %d\n", i);
    if (i < 0){
        if (verbose) error("Can't open winkey hostmode");
        zserial_close(cwda->zser);
        return -1;
    }
    cwda->winkey_version = (unsigned char)i;

    if (cwda->winkey_version >= 20){ // >= 2.0
        // set WK2 mode
        winkey_write(cwda, "\x00\x0b", 2);
    }

    // setup speed pot
    sprintf(s, "\x05%c\x1f\xff", cfg->cwda_minwpm);
    winkey_write(cwda, s, 4);

    // winkey2 mode
    if (cwda->winkey_version >= 20){
        s[0] = '\x0e';
        s[1] = ((cfg->wk_keymode-1)&0x03) << 4;
        if (cfg->wk_swap) s[1] |= 0x08;
        if (cfg->wk_echoback) s[1] |= 0x44; // serial and paddle echoback
        //dbg("wk_keymode=%d winkey2 mode=0x%02x\n", cfg->wk_keymode, s[1]);
        winkey_write(cwda, s, 2);
    }
    
    
    // force to send speed pot value
    winkey_write(cwda, "\x07", 1); 

    // force to send status
    winkey_write(cwda, "\x15", 1); 
    
    // set PTT lead in 
    s[0] = '\04';
    s[1] = cfg->cwda_leadin / 10;
	s[2] = cfg->cwda_tail / 10;
    //s[2] = '\x01';                  // \x00 means something strange, see winkeyusbman.pdf  
	winkey_write(cwda, s, 3);
    
    cwda->zser_fd = zserial_fd(cwda->zser);
    zselect_set(zsel, cwda->zser_fd, winkey_read_handler, NULL, NULL, cwda); 
    return 0;
}

int winkey_free(struct cwdaemon *cwda){

    if (!cwda) return 0;

//	dbg("Winkey_CW_host leaving sequence\n");
	winkey_write(cwda, "\x0a", 1); /*clear Buffer*/
	winkey_write(cwda, "\x00\x03", 2); /*leave hostmode*/
    
    // clear DTR
	zserial_dtr(cwda->zser, 0);

    if (cwda->zser_fd >= 0){
        zselect_set(zsel, cwda->zser_fd, NULL, NULL, NULL, cwda);
        cwda->zser_fd = -1;
    }
	zserial_free(cwda->zser);
	cwda->zser = NULL;
    return 0;
}

int winkey_read(struct cwdaemon *cwda, int timeout_ms){
    unsigned char c;

	if (zserial_read(cwda->zser, &c, 1, timeout_ms) != 1){
        if (cwda->zser_fd >= 0){
            zselect_set(zsel, cwda->zser_fd, NULL, NULL, NULL, cwda);
            cwda->zser_fd = -1;
        }
		return -1;
	}
    return (int)c;
} 

int winkey_reset(struct cwdaemon *cwda){

    if (!cwda || cwda->fd<0) return 0;
    winkey_write(cwda, "\x0a", 1);
    return 0;
}

int winkey_cw(struct cwdaemon *cwda, int onoff){
    return 0;
}

int winkey_ptt(struct cwdaemon *cwda, int onoff){
    char s[16];
    
    dbg("winkey_ptt(%d)\n", onoff);
    if (!cwda || cwda->fd<0) return 0;
    sprintf(s,"\x18%c", onoff ? '\x01' : '\x00');
    winkey_write(cwda, s, 2);
    return 0;
}

int winkey_ssbway(struct cwdaemon *cwda, int onoff){
    return 0;
}

int winkey_text(struct cwdaemon *cwda, char *text){
    char *c, *s, *d;
    
    dbg("winkey_text fd=%d\n", cwda->fd); 
    if (!cwda || cwda->fd<0) return 0;

    s = g_strdup(text);
    for (c=text, d=s; *c!='\0'; c++, d++) *d=toupper(*c); 
    
//    dbg("winkey_text('%s')\n", s);
    winkey_write(cwda, s, strlen(s)); 
    g_free(s);
    return 0;
}

int winkey_speed(struct cwdaemon *cwda, int wpm){
    char s[16];
    
    if (!cwda || cwda->fd<0) return 0;

    dbg("winkey_speed=%d\n", wpm);
    sprintf(s,"\x02%c", wpm);
    winkey_write(cwda, s, 2);
    return 0;
}

int winkey_weight(struct cwdaemon *cwda, int weight){
    char s[16];

    if (!cwda || cwda->fd<0) return 0;
    
    dbg("winkey_weight=%d\n", weight);
    sprintf(s,"\x03%c", weight );
    winkey_write(cwda, s, 2);
    return 0;
}

int winkey_tune(struct cwdaemon *cwda, int tune){
    char s[16];

    if (!cwda || cwda->fd<0) return 0;
    sprintf(s, "\x0b%c", tune ? '\x01' : '\x00');
    winkey_write(cwda, s, 2);
    return 0;
}

int winkey_back(struct cwdaemon *cwda){
    char s[16];
    
    if (!cwda || cwda->fd<0) return 0;

    strcpy(s, "\x08");
    winkey_write(cwda, s, 1);
    return 0;
}

void winkey_read_handler(void *arg){
    char s[1024], status;
    int ret, i, speed;
    struct cwdaemon *cwda;

    cwda = (struct cwdaemon*)arg;

	ret = z_pipe_read(cwda->zser_fd, s, 1000);
    if (ret<=0) return;
//    dbg("winkey_read_handler(");
    for (i=0; i<ret; i++){
        if ((s[i] & 0xc0) == 0xc0){
            status = s[i];
//            dbg("status=%02x ", (unsigned char)status);
            if (status != cwda->winkey_oldstatus){
                if (cwda->winkey_version >= 20 && status & 0x08 && cfg->wk_usebut){     
                    // pushbutton status
//                    dbg("keys=%02x ", status & 0x17);
                    if      ((status&0x01) && (cwda->winkey_oldstatus&0x01)==0) cq_run_by_number(0);
                    else if ((status&0x02) && (cwda->winkey_oldstatus&0x02)==0) cq_run_by_number(1);
                    else if ((status&0x04) && (cwda->winkey_oldstatus&0x04)==0) cq_run_by_number(2);
                    else if ((status&0x10) && (cwda->winkey_oldstatus&0x10)==0) cq_run_by_number(3);
                    
                }else{
                    // status
                    if (status & 0x02){
//                        dbg("break in ");
						zselect_msg_send(zsel, "%s;%s", "CW", "b");
                        //ret2 = write(tpipe->threadpipe_write, "CW;b\n", 5);
                    }else if ((cwda->winkey_oldstatus & 0x04) != 0 && 
                             (status & 0x04) == 0){
//                        dbg("text played cq=%p ", gses->last_cq);
						zselect_msg_send(zsel, "%s;%s", "CW", "e");
                        //ret2 = write(tpipe->threadpipe_write, "CW;e\n", 5);
                    }
                }
                cwda->winkey_oldstatus = status;
            }
            
        }else if ((s[i] & 0xc0) == 0x80){
            speed = (s[i] & 0x1f) + cfg->cwda_minwpm;
            if (cfg->wk_usepot && speed != cwda->speed){
                cwda->speed = speed;
//               dbg("pot=%d WPM ", cwda->speed);
                if (cwda->sspeed) cwda->sspeed(cwda, cwda->speed);
                redraw_later();
            }
            
        }else{
//            dbg("char=%c ", s[i]);
        }
    }
//    dbg(")\r\n");
}


/*int winkey4_init(struct cwdaemon *cwda){
    winkey_init(cwda);
#ifdef Z_HAVE_LIBFTDI
    davac4_init(cwda);
#endif
    return 0;
}
                        
int winkey4_free(struct cwdaemon *cwda){
    winkey_free(cwda);
#ifdef Z_HAVE_LIBFTDI
    davac4_free(cwda);
#endif
    return 0;
}

int winkey4_reset(struct cwdaemon *cwda){
    winkey_reset(cwda);
#ifdef Z_HAVE_LIBFTDI
    davac4_reset(cwda);
#endif
    return 0;
} */
