/* d_vswtch.c  94.12.09
 * Copyright 1994   Albert Davis
 * voltage controlled switch model.
 * netlist syntax:
 * device:  Sxxxx n+ n- vc+ vc- mname <on>|<off> <model-card-args>
 * model:   .model mname SW <args>
 * current controlled switch
 * device:  Wxxxx n+ n- controlelement mname <on>|<off> <model-card-args>
 * model:   .model mname CSW <args>
 */
#include "ecah.h"
#include "argparse.h"
#include "branch.h"
#include "d_vswtch.h"
#include "error.h"
#include "mode.h"
#include "status.h"
#include "types.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
static 	void    parse_vswtch(branch_t*,const char*,int*);
static 	void    print_vswtch(const branch_t*,int,int);
static	branch_t *create_model_vswtch(const functions_t*);
static	branch_t *copy_model_vswtch(const branch_t*);
static 	void	parse_model_vswtch(branch_t*,const char*,int*);
static 	void	print_model_vswtch(const branch_t*,int,int);
static 	void	expand_cswtch(branch_t*);
static 	void	expand_vswtch(branch_t*);
static 	int	tr_vswtch(branch_t*);
static 	void	ac_vswtch(branch_t*);
/*--------------------------------------------------------------------------*/
extern const int sim_phase;
extern const struct status stats;
static struct vswtch defalt = {(generic_t*)NULL, sizeof(struct vswtch),
    (struct vswtchmod*)NULL, vswDEFDEV_modelname, vswDEFDEV_ic, /*more*/};
static struct vswtchmod defaltmodel = {(generic_t*)NULL, 
    sizeof(struct vswtchmod), vswDEFMOD_vt, vswDEFMOD_vh, vswDEFMOD_ron,
    vswDEFMOD_roff, vswDEFMOD_type};
static branch_t modellist = {(generic_t*)&defaltmodel, sizeof(branch_t),
    &model_vswtch, &modellist, &modellist, &modellist, &modellist,
    (branch_t*)NULL, (branch_t*)NULL, vswDEFMOD_modelname, /*more*/};
/*--------------------------------------------------------------------------*/
functions_t dev_cswtch = {
   (generic_t*)&defalt,	/* x */
   sizeof(functions_t),	/* ssize */
   sizeof(branch_t),	/* elementsize */
   (functions_t*)NULL,	/* super */
   2, 			/* numnodes */
   rnTWOPORT,		/* refnode */
   rnONEPORT,		/* isdevice */
   create_std,		/* create */
   copy_std,		/* copy */
   parse_vswtch,	/* parse */
   print_vswtch,	/* print */
   expand_cswtch,	/* expand */
   probe_std,		/* probe */
   tr_probe_std,	/* tr_probe */
   ac_probe_std,	/* ac_probe */
   xprobe_std,		/* xprobe */
   tr_vswtch,		/* dotr */
   unloadpassive,	/* untr */
   ac_vswtch,		/* doac */
   NULL,		/* trfun1 */
   NULL,		/* trfun0 */
   NULL,		/* acfun */
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   NULL			/* tr_review */
};
functions_t dev_vswtch = {
   (generic_t*)&defalt,	/* x */
   sizeof(functions_t),	/* ssize */
   sizeof(branch_t),	/* elementsize */
   (functions_t*)NULL,	/* super */
   4, 			/* numnodes */
   rnTWOPORT,		/* refnode */
   rnONEPORT,		/* isdevice */
   create_std,		/* create */
   copy_std,		/* copy */
   parse_vswtch,	/* parse */
   print_vswtch,	/* print */
   expand_vswtch,	/* expand */
   probe_std,		/* probe */
   tr_probe_std,	/* tr_probe */
   ac_probe_std,	/* ac_probe */
   xprobe_std,		/* xprobe */
   tr_vswtch,		/* dotr */
   unloadpassive,	/* untr */
   ac_vswtch,		/* doac */
   NULL,		/* trfun1 */
   NULL,		/* trfun0 */
   NULL,		/* acfun */
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   NULL			/* tr_review */
};
functions_t model_vswtch = {
   (generic_t*)&defaltmodel,	/* x */
   sizeof(functions_t),	/* ssize */
   sizeof(branch_t),	/* elementsize */
   (functions_t*)NULL,	/* super */
   0, 			/* numnodes */
   rnMODEL,		/* refnode */
   NO,			/* isdevice */
   create_model_vswtch,	/* create */
   copy_model_vswtch,	/* copy */
   parse_model_vswtch,	/* parse */
   print_model_vswtch,	/* print */
   NULL,		/* expand */
   NULL,		/* probe */
   NULL,		/* tr_probe */
   NULL,		/* ac_probe */
   NULL,		/* xprobe */
   NULL,		/* dotr */
   NULL,		/* untr */
   NULL,		/* doac */
   NULL,		/* trfun1 */
   NULL,		/* trfun0 */
   NULL,		/* acfun */
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   NULL			/* tr_review */
};
/*--------------------------------------------------------------------------*/
static void parse_vswtch(branch_t *brh, const char *cmd, int *cnt)
{
 struct vswtch *x;

 x = (struct vswtch*)brh->x;

 parselabel(brh,cmd,cnt);
 (void)parsenodes(brh,cmd,cnt);
 if (brh->f->numnodes == 2){
    parselabel_raw(brh->inputlabel,cmd,cnt);
 }
 (void)ctostr(cmd, cnt, x->modelname, LABELEN, TOKENTERM);
 x->m = (struct vswtchmod*)NULL;
 for (;;){
    if (argparse(cmd,cnt,REPEAT,
	"OFF",	aENUM,		&x->ic,		swOFF,
	"ON",	aENUM,		&x->ic,		swON,
	""))
	;
    else{
       syntax_check(cmd,cnt,bWARNING);
       break;
    }
 }
}
/*--------------------------------------------------------------------------*/
static void print_vswtch(const branch_t *brh, int where, int detail)
{
 const struct vswtch *x;

 x = (const struct vswtch*)brh->x;

 (void)printlabel(brh,where);
 printnodes(brh,where);
 if (brh->input){
    printlabel(brh->input,where);
 }else{
    mprintf(where, " %s ", brh->inputlabel);
 }
 mprintf(where, " %s ", x->modelname);

 if (x->ic == swOFF)
    mprintf(where, " off ");
 else if (x->ic == swON)
    mprintf(where, " on ");
 /* else (x->ic == swUNKNOWN) */
 mprintf(where, "\n");
}
/*--------------------------------------------------------------------------*/
static branch_t *create_model_vswtch(const functions_t *func)
{
 branch_t *brh;

 brh = create_std(func);
 brh->stprev = &modellist;
 return brh;
}
/*--------------------------------------------------------------------------*/
static branch_t *copy_model_vswtch(const branch_t *proto)
{
 branch_t *brh;

 brh = copy_std(proto);
 brh->stprev = &modellist;
 return brh;
}
/*--------------------------------------------------------------------------*/
static void parse_model_vswtch(branch_t *brh, const char *cmd, int *cnt)
{
 struct vswtchmod *m;

 m = (struct vswtchmod*)brh->x;

 (void)ctostr(cmd, cnt, brh->label, LABELEN, TOKENTERM);
 if (argparse(cmd,cnt,ONEPASS,
	"SW",	aENUM,		&m->type,	tVOLTAGE,
	"CSW",	aENUM,		&m->type,	tCURRENT,
 	"")){
        ;
 }else{
    syntax_check(cmd,cnt,bWARNING);
 }
 (void)skiplparen(cmd,cnt);
 for (;;){
    if (argparse(cmd,cnt,REPEAT,
	"VT",	aDOUBLE,	&m->vt,
	"VH",	aUDOUBLE,	&m->vh,
	"IT",	aDOUBLE,	&m->vt,
	"IH",	aUDOUBLE,	&m->vh,
	"RON",	aDOUBLE,	&m->ron,
	"ROFF",	aDOUBLE,	&m->roff,
 	"")){
       ;
    }else{
       (void)skiprparen(cmd,cnt);
       syntax_check(cmd,cnt,bWARNING);
       break;
    }
 }
}
/*--------------------------------------------------------------------------*/
static void print_model_vswtch(const branch_t *brh, int where, int detail)
{
 const struct vswtchmod *m;
 m = (const struct vswtchmod*)brh->x;

 if (m->type == tVOLTAGE){
    mprintf(where, ".model  %s  sw  (", brh->label);
    mprintf(where, " vt=%s ",  ftos(m->vt,  "", 7, 0));
    mprintf(where, " vh=%s ",  ftos(m->vh,  "", 7, 0));
 }else{
    mprintf(where, ".model  %s  csw  (", brh->label);
    mprintf(where, " it=%s ",  ftos(m->vt,  "", 7, 0));
    mprintf(where, " ih=%s ",  ftos(m->vh,  "", 7, 0));
 }
 mprintf(where, " ron=%s ",   ftos(m->ron,   "", 7, 0));
 mprintf(where, " roff=%s ",  ftos(m->roff,  "", 7, 0));
 mprintf(where, ")\n");
}
/*--------------------------------------------------------------------------*/
static void expand_cswtch(branch_t *brh)
{
 brh->input = findbranch_samescope(brh->inputlabel,brh);
 if (!brh->input)
    error(bERROR,"%s: can't find %s\n",printlabel(brh,NO),brh->inputlabel);
 expand_vswtch(brh);
}
/*--------------------------------------------------------------------------*/
static void expand_vswtch(branch_t *brh)
{
 struct vswtch *x;
 const struct vswtchmod *m;

 expandgeneric(brh,&modellist);
 x = (struct vswtch*)brh->x;
 m = x->m;
 brh->val = m->ron;
 brh->y0.f0 = LINEAR;
 if (x->ic == swON){
    brh->y0.f1 = m->ron;
 }else{			/* unknown is off */
    brh->y0.f1 = m->roff;
 }
 x->previous_state = x->current_state = x->ic;
 brh->m0.f1 = 1./brh->y0.f1;
 brh->m0.c0 = 0.;
 brh->ev.x  = brh->y0.f1;
 brh->ev.y  = 0.;
 brh->acg.x = brh->m0.f1;
 brh->acg.y = 0.;
 brh->nodamp = YES;
}
/*--------------------------------------------------------------------------*/
static int tr_vswtch(branch_t *brh)
{
 struct vswtch *x;
 const struct vswtchmod *m;
 double control;
 int new_state;
 
 x = (struct vswtch*)brh->x;
 m = x->m;
 
 if (stats.iter[iSTEP] <= 1){
    if (sim_phase == pINIT_DC){   
       if (x->ic == swON){
	  brh->y0.f1 = m->ron;
       }else{
	  brh->y0.f1 = m->roff;
       }
       x->current_state = x->ic;
       brh->m0.f1 = 1./brh->y0.f1;
    }
    x->previous_state = x->current_state;
 }
 
 control = (brh->input)
	? probe_branch(brh->input,"I")
 	: tr_volts(&(brh->n[IN1]),&(brh->n[IN2]));
 if (control > m->vt + m->vh){
    new_state = swON;
 }else if (control < m->vt - m->vh){
    new_state = swOFF;
 }else{
    new_state = x->previous_state;
 }

 if (new_state != x->current_state){
    if (new_state == swON){
       brh->y0.f1 = m->ron;
    }else{
       brh->y0.f1 = m->roff;
    }
    x->current_state = new_state;
    brh->m0.f1 = 1./brh->y0.f1;
    trloadpassive(brh);
    return NO;
 }else{
    trloadpassive(brh);
    return YES;
 }
}
/*--------------------------------------------------------------------------*/
static void ac_vswtch(branch_t *brh)
{
 brh->ev.x  = brh->y0.f1;
 brh->ev.y  = 0.;
 brh->acg.x = brh->m0.f1;
 brh->acg.y = 0.;
 acloadpassivereal(brh);
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
