Logo Search packages:      
Sourcecode: tucnak2 version File versions  Download package

sdev.c

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

#define STARTB 4
#define STOPB 1

struct sdevlist *init_sdevlist(){
    struct sdevlist *sdevlist;

    sdevlist=g_new0(struct sdevlist,1);
    sdevlist->sdevs=g_ptr_array_new();
    sdevlist->sconns=g_ptr_array_new();
    return sdevlist;
}

int free_sdevlist(struct sdevlist *sdevlist){
    int i;
    for (i=0;i<sdevlist->sdevs->len;i++){
        struct sdev *sd;
        sd=(struct sdev *)g_ptr_array_index(sdevlist->sdevs, i);
        free_sd(sdevlist, sd);
    }
    g_free(sdevlist);
    return 0;
}

void check_sdevlist(struct sdevlist *sdevlist){
    int i;
    for (i=0;i<sdevlist->sconns->len;i++){
        struct sconn *sc;
        struct sjob *sjob;
        
        sc=(struct sconn *)g_ptr_array_index(sdevlist->sconns, i);
        if (list_empty(sc->sjobq)) continue;
        
        sjob=sc->sjobq.next;
        if (sjob->state) continue;

        /*dbg("check_sdevlist: sd_send(,%d,,)\n", sjob->fce);*/
        if (sc->fd<=1){
            /* TODO reconnect */
            /* if (error) continue; */
        }
        sd_send(sjob->sdev, sjob->fce, sjob->req, sjob->len);
        sjob->timer_id=install_timer(sjob->sdev->timeout_ms, sc_timeout, (union cba_t)sc); 
     /*   dbg("check_sdevlist: installed timer %d to sjob %p\n", sjob->timer_id, sjob);*/
        sjob->state=1;
        
    }
}


struct sdev *sd_open_ttys(struct sdevlist *sdevlist, char saddr, char *filename, int timeout_ms){
    int i;
    struct sconn *sc;
      struct sdev *sd;
      struct termios tio;
    gchar *c,*lockfile;
    struct passwd *pwd;
    FILE *f;
      char errbuf[1024];
    
    
/*    dbg("sd_open_ttys(%s)\n", filename);*/
    lockfile=NULL;
    sd=g_new0(struct sdev,1);
    g_ptr_array_add(sdevlist->sdevs, sd);
    
    for (i=0;i<sdevlist->sconns->len;i++){
        sc=(struct sconn *)g_ptr_array_index(sdevlist->sconns, i);
        if (sc->type!=CT_TTYS) continue;
        if (strcmp(sc->ttys_filename, filename)!=0) continue;
        /*dbg("found sc=%p\n", sc);*/
      sc->refcnt++;
        goto found;
    }
    /* sconn not found */
    
    lockfile=NULL;
    c=rindex(filename, '/');
    if (!c){
        log_addf("Warning: bad filename %s", filename);
    }else{
        lockfile=g_strdup_printf("/var/lock/LCK..%s", c+1);
        f=fopen(lockfile, "rt");
        if (f){
            int pid;
            char s[256];
            int locked=1;
            
            if (fgets(s, 250, f)){
                pid=atoi(s);
                if (pid){
                    if (kill(pid, 0)){
                        log_addf("Lockfile %s is stale", lockfile);
                        if (unlink(lockfile)) log_addf("Can't delete lockfile %s",lockfile);
                        else locked=0;
                    }
                }
            }
            fclose(f); /* real unlink is now */
            if (locked){
                log_addf("Device %s is locked see %s", filename, lockfile);
                g_free(lockfile);
                g_ptr_array_remove(sdevlist->sdevs, sd);
                g_free(sd);
                return NULL;
            }
        }
    }

    if (lockfile){
        f=fopen(lockfile, "wt");
        if (!f){
            log_addf("Can't create lock file %s", lockfile);
        }else{
            fprintf(f, "%10d tucnak ", getpid()); 
            pwd=getpwuid(getuid());
            if (pwd) fprintf(f, "%s\n", pwd->pw_name);
            else fprintf(f, "%d\n", getuid());
            fclose(f);
        }
        g_free(lockfile);
    }
    
    
    sc=g_new0(struct sconn,1);
    /*dbg("new sc %p\n",sc);*/
    sc->refcnt++;
    sd->sconn=sc;
    g_ptr_array_add(sdevlist->sconns, sc);
    init_list(sc->sjobq);
    sc->type=CT_TTYS;
    sc->ttys_filename=g_strdup(filename);
    sc->fd=open(filename, O_RDWR | O_SYNC | O_NONBLOCK | O_NOCTTY);
    if (sc->fd<0){
        log_addf("Can't open device %s", filename);
        lockfile=g_strdup_printf("/var/lock/LCK..%s", c+1);
        if (unlink(lockfile)) log_addf("Can't delete lockfile %s: %s",lockfile, strerror_r(errno, errbuf, sizeof(errbuf)) );
        g_free(lockfile);
        free_sd(sdevlist,sd);
        return NULL;
    }
    
    if (fcntl(sc->fd,F_SETFL,O_NONBLOCK)) {
        free_sd(sdevlist,sd);
        return NULL;
    }
    
      tcgetattr(sc->fd,&tio);
      tio.c_cflag=B9600|CS8|CLOCAL|CREAD|PARENB;/*|PARODD;*/
      tio.c_iflag=INPCK;
      tio.c_lflag=0;
      tio.c_oflag=0;
      tio.c_cc[VMIN]=1;
      tio.c_cc[VTIME]=5;
    
      tcsetattr(sc->fd,TCSANOW,&tio);
    i = TIOCM_RTS; 
    ioctl (sc->fd, TIOCMBIS, &i); /* set */
    i = TIOCM_DTR; 
    ioctl (sc->fd, TIOCMBIS, &i); /* set */

/* 
 * normally 0
 * 1 for debugging with atisp
 *
 */

#if 0    
    i = TIOCM_RTS; /* clear PSEN*/
    ioctl (sc->fd, TIOCMBIC, &i); /* clear = log.1*/
    usleep(100000);
    i = TIOCM_DTR; /* clear reset*/
    ioctl (sc->fd, TIOCMBIC, &i); /* clear */
#endif
      
    set_handlers(sc->fd, sc_read_handler, NULL, NULL, (union cba_t)sc);

    
found:    
    sd->sconn=sc;
    sd->saddr=saddr;
    sd->timeout_ms=timeout_ms;
    /*dbg("sd=%p refcnt=%d\n",sd,sc->refcnt);*/
    return sd;


    
}

struct sdev *sd_open_udp(char *hostname, int udpport){
    return NULL;    
}

struct sdev *sd_open_tcp(char *hostname, int tcpport){
    
    return NULL;
}

int free_sd(struct sdevlist *sdevlist, struct sdev *sd){
    struct sconn *sc;
    struct sjob *sjob;
    
/*    dbg(" ------\n");*/
   /* dbg("free_sd(%p)\n", sd);*/

    if (!sd) return -1;

    sc=sd->sconn;
    foreach(sjob, sc->sjobq){
        struct sjob *sj;
        /*dbg("try job %p\n", sjob);*/
        if (sd!=sjob->sdev) continue;
        sj=sjob->prev;
        del_from_list(sjob);
        free_sjob(sjob);
        sjob=sj;
    }
   /* dbg("  refcnt=%d\n", sc->refcnt);*/
    sc->refcnt--;
    if (!sc->refcnt){
        /*dbg("  freeing sc %p\n", sc);*/
        if (sc->fd>=0){
            gchar *lockfile,*c;

            close(sc->fd);
            c=rindex(sc->ttys_filename, '/');
            if (!c){
                log_addf("Warning: bad filename %s", sc->ttys_filename);
            }else{
                lockfile=g_strdup_printf("/var/lock/LCK..%s", c+1);
                if (unlink(lockfile)) log_addf("Can't delete lockfile %s",lockfile);
                g_free(lockfile);
            }
        }
        CONDGFREE(sc->ttys_filename);
        CONDGFREE(sc->ip_hostname);
        g_ptr_array_remove(sdevlist->sconns, sc);
        g_free(sc);
    }else{
        /*dbg("  sc %p already active\n", sc);*/
    }
    g_ptr_array_remove(sdevlist->sdevs, sd);
    g_free(sd);
    return (0);
}

static char sd_chk(unsigned char *s, int len){
      unsigned char chk, *c;
    chk=0;
      for (c=s;len;c++,len--){
            chk^=*c;
      }
      return chk;
}


int sd_send(struct sdev *sd, char fce, char *data, char len){
      unsigned char rawdata[300];
      int rawlen,written;

    /* clearing queue, filedescriptor is non-blocking */
    while (read(sd->sconn->fd, rawdata, sizeof(rawdata))>0){};
    
      rawlen=0;
      memset(rawdata, 0xff, STARTB); rawlen+=STARTB;
      rawdata[rawlen++]=0xc5;
      rawdata[rawlen++]=fce&0x7f;
      rawdata[rawlen++]=sd->saddr;
      rawdata[rawlen++]=len;
    memcpy(rawdata+rawlen, data, len); rawlen+=len;
      rawdata[rawlen]=sd_chk(rawdata+STARTB, rawlen-STARTB);
    rawlen++;
      memset(rawdata+rawlen, 0xff, STOPB); rawlen+=STOPB;
      
      written=write(sd->sconn->fd, rawdata, rawlen);
   /* dbg("sd_send: written=%d\n", written);*/
    if (written<0) return written;
    return 0;
}

struct sjob gsjob;
void sc_read_handler(union cba_t cba){
    int ret,max,i;
    struct sjob *sjob;
    struct sconn *sc;

    sc=cba.sconn;
    max=SDMAXLEN-sc->rawi;
    if (max<0) raise(SIGSEGV);
    
    /*usleep(50000);  //todo*/
    ret=read(sc->fd, sc->rawdata+sc->rawi, max);
    /*dbg("read=%d\n", ret);*/
#if 1
    dbg("sc_read_handler: rawi=%d read=%d data=", sc->rawi, ret);
    if (ret>0){
        int i;
        for (i=0;i<sc->rawi;i++) dbg("%02x ", sc->rawdata[i]);
        dbg(" [");
        for (i=0;i<ret;i++) dbg("%02x ", sc->rawdata[i+sc->rawi]);
    }
    dbg("]\n");
#endif
    sc=cba.sconn;

    if (list_empty(sc->sjobq)){
        dbg("sc_read_handler: no job  ret=%d\n",ret);
        sc->rawi=0;
        return;
    }
    sjob=sc->sjobq.next;
    
    if (ret<=0){
        /*dbg("sc_read_handler: read<0 error:%d %s\n", errno, strerro_r(errno));*/
        sjob->ret=1;
        goto error;
    }
    sc->rawi+=ret;
    
    for (i=0;i<sc->rawi;i++){
        if (sc->rawdata[i]!=0xc5) continue;  
            /* found C5, begin of packet */
       /* dbg("found c5\n");*/
        if (i+5>sc->rawi) return; /* too short packet, waiting  */
/*        dbg("i=%02x len=%02x sc->rawi=%d\n", i, sc->rawdata[i+SDLEN], sc->rawi);*/
        if (i+5+sc->rawdata[i+SDLEN]>sc->rawi) {
/*            dbg("too short packet\n");*/
            return;/* too short packet, waiting  */
        }
    
#if 1    
        dbg("sc_read_handler: i=%d rawi=%d data=",i,sc->rawi);
        if (ret>0){
            int j;
            for (j=i;j<sc->rawi;j++) {
                if (j==i) dbg("--");
                if (j==i+4) dbg("[");
                if (j==i+4+sc->rawdata[i+3]) dbg("]");
                dbg("%02x", sc->rawdata[j]);
                dbg(" ");
                if (j==i+4+sc->rawdata[i+3]) break;
            }
        }
        dbg("\n");
#endif
        if (sd_chk(sc->rawdata+i, 5+sc->rawdata[i+SDLEN])){
            sjob->ret=11;
            goto error;
        }
        
            /* correct checksum */
        if (sc->rawdata[i+SDFCE]==0){       /* unknown function */
            sjob->ret=17;
            goto error;
        }
        if (sc->rawdata[i+SDFCE]==128){     /* error */
            sjob->ret=14;
            goto error;
        }
        if ((sc->rawdata[i+SDFCE]&0x80)==0x00){   /* command, try next data */
            continue;
        }
#if 0       
        if (sc->rawdata[i+SDADR]!=sjob->sdev->saddr){
            /*dbg("  sc->rawdata[%d]=%d  sjob->sdev->saddr=%d \n", i+SDADR, sc->rawdata[i+SDADR],sjob->sdev->saddr);*/
            sjob->ret=16;
            goto error;
        }
        if (sc->rawdata[i+SDFCE]!=sjob->fce+128){
            /*dbg("  sc->rawdata[%d]=%d sjob->fce=%d \n", i+SDFCE,sc->rawdata[i+SDFCE],sjob->fce);*/
            sjob->ret=16;
            goto error;
        }
#endif
        sjob->ret=0;
        sjob->data=sc->rawdata+i+4;
        sjob->len=sc->rawdata[i+SDLEN];
        /*dbg("  ret=%d\n", sjob->ret);  */
        if (sjob->callback) sjob->callback(sjob);
        sc->rawi=0;
        /*sc->rawi-=i+sc->rawdata[i+SDLEN]+5;
        memmove(sc->rawdata, sc->rawdata+i+sc->rawdata[i+SDLEN]+5,sc->rawi); */
        goto clean;
    }
    /* no C5, clearing buffer */
    sc->rawi=0;
/*    dbg("a   short packet\n");*/
    return; 

error:;
/*    dbg("sd_read_handler ret=%d\n", sjob->ret);  */
    sc->rawi=0;
    sjob->data=NULL;sjob->len=0;
    if (sjob->callback) sjob->callback(sjob);
clean:;    
    del_from_list(sjob);
    free_sjob(sjob);    /* tohle pri PD2007 zuchlo pri killnuti neexistujiciho casovace */
}

int sd_aprot(struct sdev *sd, char fce, char *data, char len, void (*callback)(struct sjob *sjob), void *param){
    struct sjob *sjob;

    if (!sd) return -1;
    sjob=g_new0(struct sjob,1);
/*    dbg("sd_aprot: new job %p, sdev=%p, fce=%d (%d)\n", sjob, sd, fce, (unsigned char)sd->saddr);*/
    sjob->retry=1;
    sjob->callback=callback;
    sjob->param=param;
    sjob->fce=fce;
    sjob->req=g_malloc(len);
    sjob->timer_id=-1;
    memcpy(sjob->req, data, len);
    sjob->len=len;
    sjob->sdev=sd;
    /* add to end of queue */
    add_to_list(sd->sconn->sjobq, sjob);
    
    return 0;
}

void sc_timeout(union cba_t cba){
    struct sjob *sjob;
    struct sconn *sc;

    
    sc=cba.sconn;
    sjob=sc->sjobq.next;
    if (!sjob){
/*        dbg("sc_timeout: no sjob!\n");*/
        return;
    }
    sjob->timer_id=-1;
    sjob->retry--;
    if (!sjob->retry){  /* retryout */
        sjob->ret=13;
        if (sjob->callback) sjob->callback(sjob);

        del_from_list(sjob);
        free_sjob(sjob);
        return;
    }
    sd_send(sjob->sdev, sjob->fce, sjob->req, sjob->len);
    sjob->timer_id=install_timer(sjob->sdev->timeout_ms, sc_timeout, (union cba_t)sc); 
   /* dbg("sc_timeout: installed timer %d\n", sjob->timer_id);*/
    
}

char *sd_err(int err){
    switch(err){
        case 0:
            return "OK";
        case 11:
            return "Bad checksum";
        case 13:
            return "Timeout";
        case 14:
            return "Error";
        case 16:
            return "Bad response";
        case 17:
            return "Unknown function";
        default:
            return "Unknown error code";
    }
}


int free_sjob(struct sjob *sjob){
/*    dbg("freeing job %p (%d)\n", sjob, (unsigned char)sjob->sdev->saddr);*/
    if (sjob->timer_id>=0) {
    /*    dbg("free_sjob: killing timer %d\n", sjob->timer_id);*/
        kill_timer(sjob->timer_id);
    }
    g_free(sjob);
    return 0;
}


Generated by  Doxygen 1.6.0   Back to index