/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2021  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.

*/

#include "header.h"

#include "dxc.h"
#include "fifo.h"
#include "language2.h"
#include "main.h"
#include "qsodb.h"
#include "rc.h"
#include "terminal.h"
#include "trig.h"
#include "tsdl.h"
#include "zstring.h"



#define NOTHING 1
static int rigerr = NOTHING;

#ifdef __GNUC__
#define TRTR(thr, m...) if (cfg->trace_rig >= (thr ? 2 : 1)){ \
    GString *gs = g_string_new("RIG: "); \
    if (thr) g_string_append(gs, "        "); \
	g_string_append_printf(gs, m); \
	if (rigerr != NOTHING) g_string_append_printf(gs, ":      %s", trig_short_errstr(rigerr)); \
	trace(1, "%s", gs->str); \
	g_string_free(gs, TRUE); \
}
#else
#define TRTR(thr, m, ...) if (cfg->trace_rig >= (thr ? 2 : 1)){ \
    GString *gs = g_string_new("RIG"); \
    if (thr) g_string_append(gs, "           "); \
	g_string_append_printf(gs, m, __VA_ARGS__); \
	if (rigerr != NOTHING) g_string_append_printf(gs, ":      %s", trig_short_errstr((enum rig_errcode_e)rigerr)); \
	trace(1, "%s", gs->str); \
	g_string_free(gs, TRUE); \
}
#endif


// ---------------- config_rig functions
struct config_rig *get_config_rig_by_number(GPtrArray *crigs, int nr){
    struct config_rig *crig;
    int i;

    for (i=0; i<cfg->crigs->len; i++){
        crig = (struct config_rig *)g_ptr_array_index(crigs, i);
        if (crig->nr==nr) return crig;	
    }
    return NULL;   
}

#ifdef HAVE_HAMLIB

struct trig *get_trig_by_number(struct trigs *trigs, int nr){
    struct trig *trig;
    int i;
    for (i=0; i<trigs->trigs->len; i++){
        trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
        if (trig->nr==nr) return trig;
    }

    
    return NULL;
}


struct trigs *gtrigs;
ZPtrArray *riglist = NULL;

//static int rig_load_all_backends_called = 0;

// ---------------- trigs functions
void init_trigs(void){
	int i, verbose = 0;
	
	gtrigs = g_new0(struct trigs, 1);
    gtrigs->qrg = 0.0;
    gtrigs->rit = 0;
	gtrigs->trigs = g_ptr_array_new();
	gtrigs->split_vfo = RIG_VFO_MAIN;

	for (i = 0; i < cfg->crigs->len; i++){
		struct config_rig *crig = (struct config_rig *)g_ptr_array_index(cfg->crigs, i);
		if (!crig->rig_enabled) continue;
        verbose |= crig->rig_verbose;
    }
    if (verbose)
		rig_set_debug(RIG_DEBUG_TRACE);
    else
        rig_set_debug(RIG_DEBUG_NONE);

    if (!riglist){
        riglist = z_ptr_array_new();
		//if (!rig_load_all_backends_called){
			rig_load_all_backends();
			//	rig_load_all_backends_called = 1;
		//}
        rig_list_foreach(trig_save_riglist, riglist);
        z_ptr_array_qsort(riglist, trig_compare);
#if 0
        for (i=0; i<riglist->len; i++){
            struct rig_caps *caps = (struct rig_caps *)z_ptr_array_index(riglist, i);
            dbg("%4d %4d %-20s %s\n", i, caps->rig_model, caps->mfg_name, caps->model_name);
        }
        dbg("X\n");
#endif
    }

	for (i = 0; i < cfg->crigs->len; i++){
		struct trig *trig;
		struct config_rig *crig = (struct config_rig *)g_ptr_array_index(cfg->crigs, i);
		if (!crig->rig_enabled) continue;

		trig = init_trig(crig);
		if (trig != NULL) g_ptr_array_add(gtrigs->trigs, trig);
	}

}

void free_trigs(struct trigs *trigs){
	int i;
    
    if (riglist){
        z_ptr_array_free(riglist, TRUE);
    }
        riglist = NULL;

	for (i = 0; i < trigs->trigs->len; i++){
		struct trig *trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
		free_trig(trig);
	}
	g_ptr_array_free(trigs->trigs, 1);
	g_free(trigs);
}

void trigs_read_handler(struct trigs *trigs, int n, char **items){
    char *cmd;
	int rignr;
    struct trig *trig;
    
	rignr = atoi(items[1]);
    cmd = items[2];
    dbg("trig_read_handler   nr=%d  cmd='%s'\n", rignr, cmd);
    trig = get_trig_by_number(trigs, rignr);
    if (strcmp(cmd, "!")==0){  /* error */
		log_addf("Rig %d error: %s", rignr, items[3]);
		TRTR(0, "#%d: Rig error: %s", rignr, items[3]);
        if (trig != NULL){
            g_ptr_array_remove(trigs->trigs, trig);
            free_trig(trig);
        }
        progress(NULL);
        goto x;
    }
    
    if (!trig){
       // dbg("Unknown rig nr=%d", rignr);
        TRTR(0, "#%d: Unknown rig nr", rignr);
        goto x;
    }

    if (strcasecmp(cmd, "qrg")==0){
		double freq, lo;
        struct band *b;
		struct config_rig *crig = get_config_rig_by_number(cfg->crigs, rignr);

		freq = atof(items[3]);
		lo = get_rig_lo(aband, rignr);
        trigs->qrg = freq + lo;
		TRTR(0, "#%d: New qrg %8.3f = %8.3f + %8.3f", rignr, trigs->qrg/1000000.0, freq/1000000.0, lo/1000000.0);

        b = find_band_by_qrg(trigs->qrg);
        if (b) {
            b->qrg = trigs->qrg;
   //         TRTR(0, "#%d: set %s->qrg = %8.3f", rignr, b->bandname, b->qrg / 1000000.0);
        }
        if (aband && crig){
            if (trigs->qrg < aband->qrg_min * 1000.0 || trigs->qrg > aband->qrg_max * 1000.0){
                if (crig->rig_qrg_r2t){ 
                    if (b) activate_band(b);
                } 
            }
        }
        
        trigs_set_qrg_except(trigs, rignr, trigs->qrg);
		dxc_qrg_changed(trigs->qrg);
    }else if (strcasecmp(cmd, "rit")==0){
        trigs->rit = atol(items[3]);
        //dbg("get_rig(#%d)=%ld\n", rignr, trigs->rit);
		TRTR(0, "#%d: New rit %ld", rignr, trigs->rit);
        trigs_set_rit_except(trigs, rignr, trigs->rit);
    }else {
		TRTR(0, "#%d: Unknown command cmd", rignr);
	}
x:;
    redraw_later();
}

void trigs_set_qrg(struct trigs *trigs, double qrg){
	int i;

	for (i = 0; i < trigs->trigs->len; i++){
		struct trig *trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
		trig_set_qrg(trig, qrg);
	}
}

void trigs_set_qrg_except(struct trigs *trigs, int except_rigr, double qrg){
	int i;

	for (i = 0; i < trigs->trigs->len; i++){
		struct trig *trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
        if (trig->nr == except_rigr) continue;
		trig_set_qrg(trig, qrg);
	}
}

void trigs_set_rit_except(struct trigs *trigs, int except_rigr, double rit){
	int i;

	for (i = 0; i < trigs->trigs->len; i++){
		struct trig *trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
        if (trig->nr == except_rigr) continue;
		trig_set_rit(trig, rit);
	}
}

// rignr == -1 -> resend all trigs
void trigs_resend_freq(struct trigs *trigs, int rignr){
	int i;

	for (i = 0; i < trigs->trigs->len; i++){
		struct trig *trig;
		if (rignr >= 0 && i != rignr) continue;
		trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
		trig_resend_freq(trig);
	}
}

void trigs_set_ptt(struct trigs *trigs, int ptt){
	int i;

	if (trigs == NULL) return;

	for (i = 0; i < trigs->trigs->len; i++){
		struct trig *trig;
		trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
		if (trig->ptt_t2r != 0) {
            trig_set_ptt(trig, ptt ? trig->ptt_t2r : RIG_PTT_OFF);
        }
	}
}

void trigs_toggle_split_vfo(struct trigs *trigs){
	int i;

	if (trigs == NULL) return;

	// parameters obtained experimentally on IC-7610
	if (gtrigs->split_vfo == RIG_VFO_MAIN) {
		gtrigs->split_vfo = RIG_VFO_SUB;
	}
	else{
		gtrigs->split_vfo = RIG_VFO_MAIN;
	}

	TRTR(0, " trigs_toggle_split_vfo  split_vfo=%s", gtrigs->split_vfo == RIG_VFO_MAIN ? "MAIN" : "SUB");
	
	for (i = 0; i < trigs->trigs->len; i++){
		struct trig *trig;
		trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
		trig_toggle_split_vfo(trig);
	}
}

void trigs_send_voice_mem(struct trigs *trigs, int ch){

#ifdef HAVE_RIG_SEND_VOICE_MEM
	if (trigs == NULL) return;
	TRTR(0, " trigs_send_voice_mem  %d", ch);

	int i;
	for (i = 0; i < trigs->trigs->len; i++){
		struct trig *trig;
		trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
		trig_send_voice_mem(trig, ch);
	}
#endif    
}

void trigs_send_morse(struct trigs *trigs, const char *msg){

#ifdef HAVE_RIG_SEND_MORSE
    if (trigs == NULL) return;
	TRTR(0, " trigs_send_morse  '%s'", msg);

	int i;
	for (i = 0; i < trigs->trigs->len; i++){
		struct trig *trig;
		trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
		trig_send_morse(trig, msg);
	}
#endif    
}

void trigs_stop_morse(struct trigs *trigs){

#ifdef HAVE_RIG_STOP_MORSE
	int i;
	if (trigs == NULL) return;
	TRTR(0, " trigs_stop_morse");

	for (i = 0; i < trigs->trigs->len; i++){
		struct trig *trig;
		trig = (struct trig *)g_ptr_array_index(trigs->trigs, i);
		trig_stop_morse(trig);
	}
#endif    
}


// ---------------- trig functions

struct trig *init_trig(struct config_rig *crig){
	struct trig *trig;
    int ret;
	RIG *tmprig;
	enum rig_port_e rp = RIG_PORT_NONE;
	
	progress(VTEXT(T_INIT_RIG), crig->nr);		

	TRTR(0, "#%d: init_trig, model=%d verbose=%d", crig->nr, crig->rig_model, crig->rig_verbose);
        
    if (!crig->rig_model) return NULL;
	if (crig->rig_model != 1 && crig->rig_model != 2){
		if (!crig->rig_filename || !*crig->rig_filename) return NULL;
	}

	trig = g_new0(struct trig, 1);
	trig->nr = crig->nr;
	trig->poll_ms = crig->rig_poll_ms;
    trig->model = crig->rig_model;
    trig->filename = g_strdup(crig->rig_filename);
    trig->speed = crig->rig_speed;
	trig->handshake_none = crig->rig_handshake_none;
	trig->qrg_t2r = crig->rig_qrg_t2r;
	trig->civaddr = crig->rig_civaddr;
	trig->mode_t2r = crig->rig_mode_t2r;
	trig->ssbcw_shift = crig->rig_ssbcw_shift;
	trig->clr_rit = crig->rig_clr_rit;
	trig->ptt_t2r = crig->rig_ptt_t2r;
	trig->conf = g_strdup(crig->rig_conf);

    MUTEX_INIT(trig->jobs);
   
    tmprig = rig_init(crig->rig_model);
	if (tmprig){
		rp = tmprig->state.rigport.type.rig;
		rig_cleanup(tmprig);
	}

	trig_set_conf(trig);

	if (rp == RIG_PORT_SERIAL && cfg->nolocks == 0){
        ret = zfhs_lock(trig->filename, 1);
        if (ret){
            char *c = zfhs_strdup_error(ret, crig->rig_filename);
            log_addf(VTEXT(T_RIG_ERROR), c, crig->rig_filename);
            g_free(c);
            free_trig(trig);
            return NULL;
        }
        trig->locked = 1;
    }
    
    init_list(trig->jobs);
    trig->thread = g_thread_try_new("hamlib rig", trig_main, (gpointer)trig, NULL); 
    if (!trig->thread) {
        log_addf(VTEXT(T_CANT_CREATE_RIG_THREAD));
        g_free(trig);
        return NULL;
    }
	return trig;
}

void free_trig(struct trig *trig){
    
    
    if (!trig) return;

	progress(VTEXT(T_FREE_RIG), trig->nr);		

    if (trig->thread){
		progress(VTEXT(T_WAIT_FOR_RIG_THR));		

        trig->thread_break = 1;
        dbg("join trig...\n");
        g_thread_join(trig->thread);
        dbg("done\n");
        trig->thread=0;
    }
	if (trig->locked) zfhs_unlock(trig->filename);
	if (trig->rig){
        rig_close(trig->rig);
        rig_cleanup(trig->rig);
		zg_free0(trig->filename);
		zg_free0(trig->conf);
        trig->rig = NULL;
    }
    MUTEX_FREE(trig->jobs);
	g_free(trig);
}



void trig_set_mode(struct trig *trig, rmode_t mode){
    struct trig_job *job;

    if (!trig) return;
    job = g_new0(struct trig_job, 1);
    job->cmd = TRIG_MODE;
    job->mode = mode;
	TRTR(0, "#%d: Set mode %s", trig->nr, rig_strrmode(mode));
    trig_job_add(trig, job);
}

void trig_set_qrg(struct trig *trig, double qrg){
    struct trig_job *job;
	double lo;

    if (!trig) return;
    job = g_new0(struct trig_job, 1);
    job->cmd = TRIG_FREQ;
	lo = get_rig_lo(aband, trig->nr);
    job->freq = qrg - lo;
	TRTR(0, "#%d: Set QRG %5.3f = %5.3f - %5.3f", trig->nr, job->freq / 1000000.0, qrg / 1000000.0, lo / 1000000.0);
    trig_job_add(trig, job);
}

void trig_set_mode_qrg(struct trig *trig, rmode_t mode, double qrg){
    struct trig_job *job;
	double lo;

    if (!trig) return;
    job = g_new0(struct trig_job, 1);
    job->cmd = TRIG_MODE_FREQ;
	lo = get_rig_lo(aband, trig->nr);
    job->mode = mode;
    job->freq = qrg - lo;
	TRTR(0, "#%d: Set QRG %5.3f = %5.3f - %5.3f, mode %s", trig->nr, job->freq / 1000000.0, qrg / 1000000.0, lo / 1000000.0, rig_strrmode(mode));
    trig_job_add(trig, job);
}

void trig_resend_freq(struct trig *trig){
    struct trig_job *job;

    if (!trig) return;
    job = g_new0(struct trig_job, 1);
    job->cmd = TRIG_RESENDFREQ;
	TRTR(0, "#%d: Resend QRG", trig->nr);
    trig_job_add(trig, job);
}


void trig_set_rit(struct trig *trig, shortfreq_t rit){
    struct trig_job *job;

    if (!trig) return;
    job = g_new0(struct trig_job, 1);
    job->cmd = TRIG_RIT;
    job->rit = rit;
	TRTR(0, "#%d: Set RIT %ld", trig->nr, rit);
    trig_job_add(trig, job);
}

void trig_set_ptt(struct trig *trig, ptt_t ptt){
    struct trig_job *job;

    if (!trig) return;
    job = g_new0(struct trig_job, 1);
    job->cmd = TRIG_PTT;
    job->ptt = ptt;
	TRTR(0, "#%d: Set PTT %d", trig->nr, ptt);
    trig_job_add(trig, job);
}

void trig_toggle_split_vfo(struct trig *trig){
	struct trig_job *job;

	//log_addf("trig_toggle_split_vfo trig=%p  split_vfo=%d", trig, (int)gtrigs->split_vfo);

	if (!trig) return;

	job = g_new0(struct trig_job, 1);
	job->cmd = TRIG_TOGGLE_SPLIT_VFO;
	TRTR(0, "#%d: Split VFO %s", trig->nr, gtrigs->split_vfo == RIG_VFO_MAIN ? "MAIN" : "SUB");
	trig_job_add(trig, job);
}

#ifdef HAVE_RIG_SEND_VOICE_MEM
void trig_send_voice_mem(struct trig *trig, int ch){
	struct trig_job *job;

	if (!trig) return;

	job = g_new0(struct trig_job, 1);
	job->cmd = TRIG_SEND_VOICE_MEM;
	job->ch = ch;
	TRTR(0, "#%d: Send voice mem %d", trig->nr, ch);
	trig_job_add(trig, job);
}
#endif
                                                
#ifdef HAVE_RIG_SEND_MORSE
void trig_send_morse(struct trig *trig, const char *msg){
	struct trig_job *job;

	if (!trig) return;

	job = g_new0(struct trig_job, 1);
	job->cmd = TRIG_SEND_MORSE;
	job->msg = g_strdup(msg);
	TRTR(0, "#%d: Send morse '%s'", trig->nr, msg);
	trig_job_add(trig, job);
}
#endif

#ifdef HAVE_RIG_STOP_MORSE
void trig_stop_morse(struct trig *trig){
	struct trig_job *job;

	if (!trig) return;

	job = g_new0(struct trig_job, 1);
	job->cmd = TRIG_STOP_MORSE;
	TRTR(0, "#%d: Stop morse", trig->nr);
	trig_job_add(trig, job);
}
#endif


void trig_job_add(struct trig *trig, struct trig_job *job){
    MUTEX_LOCK(trig->jobs);
    add_to_list(trig->jobs, job);
    MUTEX_UNLOCK(trig->jobs);
}

struct trig_job *trig_job_get(struct trig *trig){
    struct trig_job *job;

    MUTEX_LOCK(trig->jobs);
    if (list_empty(trig->jobs)){
        MUTEX_UNLOCK(trig->jobs);
        return NULL;
    }
    job = trig->jobs.prev; 
    del_from_list(job);
    MUTEX_UNLOCK(trig->jobs);
    return job;
}

gpointer trig_main(gpointer xxx){
    //int ret;
    freq_t freq, oldfreq;
    struct trig *trig;
    shortfreq_t rit, oldrit, tmprit;
    int rigerr = NOTHING;
    char *civaddr_str;

    trig = (struct trig *)xxx;
	zg_thread_set_name("Tucnak trig");

	TRTR(1, "trig_main(#%d, model=%d, filename='%s', speed=%d)", trig->nr, trig->model, trig->filename, trig->speed);

    freq = oldfreq = (freq_t)0;
    rit = oldrit = (shortfreq_t)0;
    
	const struct rig_caps *caps = rig_get_caps(trig->model);


    trig->rig = rig_init(trig->model);
    if (!trig->rig){
        zselect_msg_send(zsel, "TRIG;%d;!;Can't init rig %d", trig->nr, (int)trig->model);
		TRTR(1, "#%d: Can't init rig %d", trig->nr, (int)trig->model);
        return NULL;
    }

    safe_strncpy(trig->rig->state.rigport.pathname, trig->filename, HAMLIB_FILPATHLEN);
    if (trig->speed > 0) trig->rig->state.rigport.parm.serial.rate = trig->speed;
	if (trig->handshake_none) trig->rig->state.rigport.parm.serial.handshake = RIG_HANDSHAKE_NONE;

#ifdef Z_UNIX_ANDROID
    trig->rig->state.rigport.timeout = 500; // 2000ms rig 311 on Debian 8.10
#elif defined(Z_MSC_MINGW)
    trig->rig->state.rigport.timeout = 400;	// 2000ms rig 311 on Windows 7
#else    
    trig->rig->state.rigport.timeout = 1000; // probably not reached
#endif
    civaddr_str = g_strdup_printf("%d", trig->civaddr);
	rig_set_conf(trig->rig, rig_token_lookup(trig->rig, "civaddr"), civaddr_str);
    g_free(civaddr_str);
    
//    dbg("pathname=%s\n", trig->rig->state.rigport.pathname);
//    dbg("type=%d\n",  trig->rig->state.rigport.type.rig);
    rigerr = rig_open(trig->rig);
	TRTR(1, "rig_open(#%d, %d)", trig->nr, (int)trig->model);
    if (rigerr != RIG_OK){
        zselect_msg_send(zsel, "TRIG;%d;!;Can't open rig %d (%s), error %d (%s)", trig->nr, (int)trig->model, trig->rig->state.rigport.pathname, rigerr, trig_short_errstr((enum rig_errcode_e)rigerr));
		TRTR(1, "rig_open(#%d)", trig->nr);
		gtrigs->rigerr = trig->rigerr = rigerr;
		rig_cleanup(trig->rig);
        trig->rig = NULL;
        return NULL;
    }
    
    
	if (trig->model == 1){ // dummy backend
		rigerr = rig_set_freq(trig->rig, RIG_VFO_CURR, 144300000);
	}

    while(!trig->thread_break){
        struct trig_job *job;
        rmode_t mode;
        pbwidth_t width;
        vfo_t vfo;

        if (trig->rigerr == -RIG_EIO){
			zselect_msg_send(zsel, "TRIG;%d;qrg;%"PRIfreq"", trig->nr, 0.0);
			zselect_msg_send(zsel, "TRIG;%d;rit;%ld", trig->nr, 0L);
            zselect_msg_send(zsel, "TRIG;%d;!;I/O error rig %d, model %d", trig->nr, trig->nr, (int)trig->model);
            break;
        }

        job = trig_job_get(trig);
        if (!job){
            usleep(trig->poll_ms * 1000);
			ST_START();
			rigerr = rig_get_vfo(trig->rig, &vfo);
			ST_STOP("rig_get_vfo");
			if (rigerr == -RIG_ENAVAIL){
                vfo = RIG_VFO_CURR;
            }else{
                if (rigerr != RIG_OK) {
					TRTR(1, "rig_get_vfo(#%d, %s)", trig->nr, rig_strvfo(vfo));
                    gtrigs->rigerr = trig->rigerr = rigerr;
                    continue;
                }
            }

			ST_START();
            usleep(trig->poll_ms * 1000);
			ST_STOP("poll_ms");
			ST_START();
			rigerr = rig_get_freq(trig->rig, vfo, &freq);
			ST_STOP("rig_get_freq");
            if (rigerr != RIG_OK){
				TRTR(1, "rig_get_freq(#%d, %s)", trig->nr, rig_strvfo(vfo));
                gtrigs->rigerr = trig->rigerr = rigerr;
                //dbg("rig_get_freq()=%d\n", status);
                continue;
            }else{
                if (trig->rigerr != RIG_OK) oldfreq = -1;
                gtrigs->rigerr = trig->rigerr = RIG_OK;
            } 

            //dbg("TRIG;qrg;%"PRIfreq"\n", freq);
            if (freq != oldfreq){
                oldfreq = freq;
				TRTR(1, "rig_get_freq(#%d, %s, %5.3f)", trig->nr, rig_strvfo(vfo), freq / 1000000.0);
				//                dbg("get_freq: %8.3f\n", freq / 1000000.0);
				zselect_msg_send(zsel, "TRIG;%d;qrg;%"PRIfreq"", trig->nr, freq);
            }  

			if (caps->get_rit){
				rigerr = rig_get_rit(trig->rig, vfo, &tmprit);
				if (rigerr != RIG_OK && rigerr != -RIG_ENAVAIL){
					gtrigs->rigerr = trig->rigerr = rigerr;
					TRTR(1, "rig_get_rit(#%d, %s)", trig->nr, rig_strvfo(vfo));
				}
				if (rigerr == RIG_OK){
					if (tmprit < -10000 || tmprit > 10000) continue; // obviously mistake
					rit = tmprit;
					if (rit != oldrit){
						oldrit = rit;
						TRTR(1, "rig_get_rit(#%d, %s, %ld)", trig->nr, rig_strvfo(vfo), rit);
						zselect_msg_send(zsel, "TRIG;%d;rit;%ld", trig->nr, rit);
					}
				}
			}
            continue;
        }

		switch (job->cmd){
			case TRIG_MODE:
				usleep(trig->poll_ms * 1000);
				rigerr = rig_get_mode(trig->rig, RIG_VFO_CURR, &mode, &width);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					TRTR(1, "rig_get_mode(#%d, RIG_VFO_CURR)", trig->nr);
					break;
				}
				usleep(trig->poll_ms * 1000);
				rigerr = rig_set_mode(trig->rig, RIG_VFO_CURR, job->mode, width /*RIG_PASSBAND_NORMAL*/);
				TRTR(1, "rig_set_mode(#%d, RIG_VFO_CURR, %s, %ld)", trig->nr, rig_strrmode(job->mode), width);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					break;
				}
				break;

			case TRIG_FREQ:
				usleep(trig->poll_ms * 1000);
				rigerr = rig_set_freq(trig->rig, RIG_VFO_CURR, job->freq);
				TRTR(1, "rig_set_freq(#%d, RIG_VFO_CURR, %8.3f)", trig->nr, job->freq / 1000000.0);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					break;
				}
				break;
			case TRIG_MODE_FREQ:
				usleep(trig->poll_ms * 1000);
				rigerr = rig_get_mode(trig->rig, RIG_VFO_CURR, &mode, &width);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					TRTR(1, "rig_get_mode(#%d, RIG_VFO_CURR)", trig->nr);
					break;
				}
				//dbg("mode=%d job->mode=%d\n", mode, job->mode);
				if (mode == job->mode) break;
				usleep(trig->poll_ms * 1000);
				rigerr = rig_set_mode(trig->rig, RIG_VFO_CURR, job->mode, width /*RIG_PASSBAND_NORMAL*/);
				TRTR(1, "rig_set_mode(#%d, RIG_VFO_CURR, %s, %ld", trig->nr, rig_strrmode(job->mode), width);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					break;
				}

				usleep(trig->poll_ms * 1000);
				rigerr = rig_set_freq(trig->rig, RIG_VFO_CURR, job->freq);
				TRTR(1, "rig_set_freq(#%d, RIG_VFO_CURR, %8.3f)", trig->nr, job->freq / 1000000.0);
				//                dbg("set_freq: %8.3f\n", job->freq/1000000.0);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					break;
				}
				break;

			case TRIG_RESENDFREQ:
				zselect_msg_send(zsel, "TRIG;%d;qrg;%"PRIfreq"", trig->nr, freq);
				zselect_msg_send(zsel, "TRIG;%d;rit;%"PRIfreq"", trig->nr, rit);
				break;
			case TRIG_RIT:
				// dbg("rig_set_rit(#%d,%d, %ld)\n", trig->nr, RIG_VFO_CURR, job->rit);
				usleep(trig->poll_ms * 1000);
				rigerr = rig_set_rit(trig->rig, RIG_VFO_CURR, job->rit);
				TRTR(1, "rig_set_rit(#%d, RIG_VFO_CURR, %ld)", trig->nr, job->rit);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					break;
				}
				break;
			case TRIG_PTT:
				usleep(trig->poll_ms * 1000);
				rigerr = rig_set_ptt(trig->rig, RIG_VFO_CURR, job->ptt);
				TRTR(1, "rig_set_ptt(#%d, RIG_VFO_CURR, %d)", trig->nr, job->ptt);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					break;
				}
				break;
			case TRIG_TOGGLE_SPLIT_VFO:
				usleep(trig->poll_ms * 1000);
				split_t split;

				if (gtrigs->split_vfo == RIG_VFO_MAIN) {
					split = RIG_SPLIT_OFF;
				}else{
					split = RIG_SPLIT_ON;
				}

				rigerr = rig_set_split_vfo(trig->rig, RIG_VFO_CURR, split, gtrigs->split_vfo);
				TRTR(1, "rig_set_split_vfo(#%d, RIG_VFO_CURR, %d, %s) ", trig->nr, (int)split, gtrigs->split_vfo == RIG_VFO_MAIN ? "MAIN" : "SUB");
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					break;
				}
				break;
			case TRIG_SEND_VOICE_MEM:
#ifdef HAVE_RIG_SEND_VOICE_MEM
				usleep(trig->poll_ms * 1000);
				rigerr = rig_send_voice_mem(trig->rig, RIG_VFO_CURR, job->ch);
				TRTR(1, "rig_send_voice_mem(#%d, RIG_VFO_CURR, %d) ", trig->nr, job->ch);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					break;
				}
#endif
				break;
			case TRIG_SEND_MORSE:
#ifdef HAVE_RIG_SEND_MORSE
				usleep(trig->poll_ms * 1000);
				rigerr = rig_send_morse(trig->rig, RIG_VFO_CURR, job->msg);
				TRTR(1, "rig_send_morse(#%d, RIG_VFO_CURR, '%s') ", trig->nr, job->msg);
				g_free(job->msg);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					break;
				}
#endif
				break;
			case TRIG_STOP_MORSE:
#ifdef HAVE_RIG_STOP_MORSE
				usleep(trig->poll_ms * 1000);
				rigerr = rig_stop_morse(trig->rig, RIG_VFO_CURR);
				TRTR(1, "rig_stop_morse(#%d, RIG_VFO_CURR) ", trig->nr);
				g_free(job->msg);
				if (rigerr != RIG_OK) {
					gtrigs->rigerr = trig->rigerr = rigerr;
					break;
				}
#endif
				break;
        }
    }
    return 0;
}

int trig_save_riglist(const struct rig_caps *caps, void *data){
    ZPtrArray *riglist = (ZPtrArray *)data;
    z_ptr_array_add(riglist, (struct rig_caps *)caps);
    return -1;
}

int trig_compare (const void *a, const void *b){
    struct rig_caps **rca, **rcb;
    int d;

    rca = (struct rig_caps **)a;
    rcb = (struct rig_caps **)b;

    if (!*rca && !*rcb) return 0;
    if (!*rca) return -1;
    if (!*rcb) return +1;

    d = strcasecmp((*rca)->mfg_name, (*rcb)->mfg_name);
    if (d) return d;
    return strcasecmp((*rca)->model_name, (*rcb)->model_name);
}

char *trig_short_errstr(enum rig_errcode_e error){
    static char s[20];

    switch ((int)error){
        case RIG_OK:         return "OK";
        case -RIG_EINVAL:    return VTEXT(T_INVALID_PARAM);
        case -RIG_ECONF:     return VTEXT(T_RIG_INVALID_CONFIG);
        case -RIG_ENOMEM:    return VTEXT(T_RIG_NOT_ENOUGH_MEM);
        case -RIG_ENIMPL:    return VTEXT(T_RIG_NOT_IMPLEMENTED);
        case -RIG_ETIMEOUT:  return VTEXT(T_RIG_COMM_TIMEOUT);
        case -RIG_EIO:       return VTEXT(T_RIG_IO_ERROR);
        case -RIG_EINTERNAL: return VTEXT(T_RIG_INTERNAL_ERROR);
        case -RIG_EPROTO:    return VTEXT(T_PROTOCOL_ERROR);
        case -RIG_ERJCTED:   return VTEXT(T_RIG_COMMAND_REJECT);
        case -RIG_ETRUNC:    return VTEXT(T_RIG_ARG_TRUNCATED);
        case -RIG_ENAVAIL:   return VTEXT(T_RIG_F_NOT_AVAILABLE);
        case -RIG_ENTARGET:  return VTEXT(T_RIG_VFO_NOT_TARGET);
        case -RIG_BUSERROR:  return VTEXT(T_RIG_ERROR_ON_BUS);
        case -RIG_BUSBUSY:   return VTEXT(T_RIG_BUS_COLLISION);
        case -RIG_EARG:      return VTEXT(T_RIG_INVALID_ARG);
        case -RIG_EVFO:      return VTEXT(T_RIG_INVALID_VFO);
        case -RIG_EDOM:      return VTEXT(T_RIG_ARG_OUT_OF_DOM);
		case NOTHING:        return "";
        default: 
            sprintf(s, VTEXT(T_ERROR_D), (int)error);
            return s;
    }
}

void trig_set_conf(struct trig *trig)
{
	if (!trig || !trig->conf) return;

	char *param = trig->conf;
	while (param && *param != '\0'){
		int ret;

		char* value = strchr(param, '=');
		if (!value) {
			log_addf(TRANSLATE("No rig config value sepatator"), param);
			return;
		}

		*value++ = '\0';
		char *n = strchr(value, ',');

		if (n) *n++ = '\0';

		int token = rig_token_lookup(trig->rig, param);
		if (token != 0){
			ret = rig_set_conf(trig->rig, rig_token_lookup(trig->rig, param), value);

			if (ret != RIG_OK){
				log_addf(TRANSLATE("Can't set rig parameter %s"), param);
				return;
			}
		}else{
			log_addf(TRANSLATE("Invalid rig config parameter %s"), param);
		}
		param = n;
	}
}


#endif
