/*
 * scbus utils to switch card settings.
 *
 * Copyright (C) 2011 Otvos Attila oattila@onebithq.com
 *
 * This 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 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>

#include "config.h"
#include "scbus-device.h"
#include "rs485.h"
#include "util.h"

#define STATUS_CHECK_OLD        1
#define STATUS_CHECK_NEW        2
#define STATUS_OLDID            4
#define STATUS_NEWID            8

int async_quit_request = 0;

static void usage(char *selfname) {
    fprintf(stderr,"SwitchCard BUS change device number V1.0\n");
    fprintf(stderr,"(C) 2010 Attila Otvos\n");
    fprintf(stderr,"Web-page: http://onebithq.com/");
    fprintf(stderr,"License type: GPL v2\n");
    fprintf(stderr,"\n");
    fprintf(stderr,"Usage: %s <old device ID> <new device ID> [-s|--serial <serial port>] [-b|--baud <baud rate>] [-n|--nocheck] [-h|--help]\n",selfname);
    fprintf(stderr,"\t-s|--serial:\tserial port device name (default: %s)\n",DEFAULT_SERIAL);
    fprintf(stderr,"\t-b|--baud:\tserial port baud rate (default: %d)\n",DEFAULT_BAUD);
    fprintf(stderr,"\t-n|--nocheck:\tno check old and new device ID\n");
    fprintf(stderr,"\t-h|--help:\tprint this list\n");
    fprintf(stderr,"\n");
}

static void exit_sighandler(int x){
    static int sig_count=0;

    ++sig_count;
    if(sig_count==6) exit(1);
    if(sig_count<=1)
        switch(x){
        case SIGINT:
        case SIGQUIT:
        case SIGTERM:
        case SIGKILL:
            async_quit_request = 1;
            return;
        }
    exit(1);
}

int main(int argc, char** argv) {
    void* rs485;

    int baud = 0;
    char *device = NULL;
    int nocheck = 0;
    int olddeviceid = 0;
    int newdeviceid = 0;
    int i,n,t,sec;
    char cmd[8192];
    char buffer[8192];
    unsigned char param[32];
    int status = 0;


    for(i=1;i<argc;i++) {
        if((!strcmp(argv[i],"-s") || !strcmp(argv[i],"--serial")) && argv[i+1]) {
            device=argv[++i];
            continue;
        }
        if((!strcmp(argv[i],"-b") || !strcmp(argv[i],"--baud")) && argv[i+1]) {
            baud=atoi(argv[++i]);
            continue;
        }
        if((!strcmp(argv[i],"-n") || !strcmp(argv[i],"--nocheck"))) {
            nocheck=1;
            continue;
        }
        if((!strcmp(argv[i],"-h") || !strcmp(argv[i],"--help"))) {
            usage(argv[0]);
            exit(1);
        }
        if(!olddeviceid) {
            if((olddeviceid=str2num(argv[i])))
                continue;
        }
        if(!newdeviceid) {
            if((newdeviceid=str2num(argv[i])))
                continue;
        }
        fprintf(stderr,"Error: Illegal parameter: %s\n\n",argv[i]);
        exit(1);
    }
    if(!olddeviceid) {
        fprintf(stderr,"Error: The old device ID isn't set.\n");
        exit(1);
    }
    if(!newdeviceid) {
        fprintf(stderr,"Error: The new device ID isn't set.\n");
        exit(1);
    }
    if(!device)
        device=DEFAULT_SERIAL;
    if(!baud)
        baud=DEFAULT_BAUD;
    if(!(rs485=init_rs485(baud,device))) {
        fprintf(stderr,"Error: %s\n",strerror(errno));
        exit(1);
    }
    if(!inited_rs485(rs485)) {
        fprintf(stderr,"Error: %s\n",geterror_rs485(rs485));
        done_rs485(rs485);
        exit(1);
    }

    signal(SIGTERM,exit_sighandler);
    signal(SIGINT,exit_sighandler);
    signal(SIGQUIT,exit_sighandler);

    memset(cmd,0,sizeof(cmd));
    sec=t=0;
    if(nocheck) {
        status|=STATUS_OLDID;
    }
    while(!async_quit_request) {
        if(isdata_rs485(rs485)) {
            memset(buffer,0,sizeof(buffer));
            while((n=readline_rs485(rs485, buffer, sizeof(buffer)))) {
                if(process_line(buffer, param, sizeof(param))) {
                    if(param[0]=='S') {
                        if(param[1]==olddeviceid)
                            status|=STATUS_OLDID;
                        if(param[1]==newdeviceid)
                            status|=STATUS_NEWID;
                    }
                }
                memset(buffer,0,sizeof(buffer));
            }
        }
        usleep(1000);
        if(!nocheck) {
            if(!(status & STATUS_CHECK_OLD) && (status & STATUS_NEWID)) {
                if(sec)
                    fprintf(stdout,"\r");
                fflush(stdout);
                fprintf(stderr,"Error: New ID is exist.\n");
                break;
            }
            if((status & STATUS_CHECK_OLD) && (status & STATUS_NEWID)) {
                if(sec)
                    fprintf(stdout,"\r");
                fflush(stdout);
                fprintf(stderr,"Change device ID is success.\n");
                break;
            }
            if(!(status & STATUS_CHECK_OLD) && !(status & STATUS_OLDID) && t>1000) {
                if(sec)
                    fprintf(stdout,".");
                else
                    fprintf(stdout,"Check old device ID .");
                fflush(stdout);
                sec++;
                t=0;
                snprintf(buffer,sizeof(buffer),"*G%02X\n",olddeviceid);
                write_rs485(rs485, buffer, strlen(buffer));
            }
            if(sec>5) {
                fprintf(stdout,"\n");
                fprintf(stderr,"Error: Old ID not found.\n");
                break;
            }
        }
        if((status & STATUS_OLDID) && (!(status & STATUS_CHECK_OLD) || t>1000)) {
            if(!(status & STATUS_CHECK_OLD)) {
                sec=1;
                fprintf(stdout,"Change device ID .");
            } else {
                fprintf(stdout,".");
                sec++;
            }
            fflush(stdout);
            t=0;
            snprintf(buffer,sizeof(buffer),"*D%02X%02X\n",olddeviceid,newdeviceid);
            write_rs485(rs485, buffer, strlen(buffer));
            status|=STATUS_CHECK_OLD;
            if(sec>10) {
                fprintf(stdout,"\n");
                fprintf(stderr,"Error: Change device ID is fail.\n");
                break;
            }
        }
        t++;
    }
    done_rs485(rs485);
    return 0;
}

