#include #include #include #include #include "xte.h" #include "builtins.h" #include "blocktype.h" typedef struct priv PRIV; typedef struct sb SB; typedef struct kind KIND; struct kind { const char *name; int namelen; unsigned int flags; #define PF_CTL_FREQ 0x00000001 #define PF_CTL_DUTY 0x00000002 BLOCKDIMS d; int x_name; int x_val; int w_val; int x_out; } ; #define KINDINIT(n,f) { .name = (n), .flags = (f), .d = { .w = -1 } } struct priv { KIND *k; double freq; double freq2; double duty; double duty2; } ; struct sb { void (*cont)(void *, void *); void *contarg; PRIV p; } ; static int w_freq; static int w_duty; static int w_fv; static int w_dv; static int w_fdv; static int w_out = -1; static int w_dash; static Pixmap pm_outs = None; static BLOCKDIMS size(KIND *k) { int lw; int w; int w_name; if (k->d.w < 0) { k->namelen = strlen(k->name); w_name = widthof(k->name,k->namelen); if (w_out < 0) { w_freq = widthof("Freq",4); w_duty = widthof("Duty",4); w_dash = widthof("-",1); w_fv = widthof("0.00kHz",7); w = widthof("0.00mHz",7); if (w > w_fv) w_fv = w; w = widthof("0.00µHz",7); if (w > w_fv) w_fv = w; w = widthof("0.00nHz",7); if (w > w_fv) w_fv = w; w = widthof("epsilon",7); if (w > w_fv) w_fv = w; w = widthof("GHz",7); if (w > w_fv) w_fv = w; w_dv = widthof("00.0%",5); w_fdv = (w_fv > w_dv) ? w_fv : w_dv; w_out = 3 * font_space; if (w_out < font_baselineskip) w_out = font_baselineskip; } switch (k->flags & (PF_CTL_FREQ|PF_CTL_DUTY)) { case 0: lw = font_space; w = w_fdv; if (w_name > w) w = w_name; break; case PF_CTL_FREQ: lw = w_freq + (2 * font_space); w = (2 * w_fv) + (2 * font_space) + w_dash; if (w_dv > w) w = w_dv; if (w_name > w) w = w_name; break; case PF_CTL_DUTY: lw = w_duty + (2 * font_space); w = (2 * w_dv) + (2 * font_space) + w_dash; if (w_fv > w) w = w_fv; if (w_name > w) w = w_name; break; case PF_CTL_FREQ | PF_CTL_DUTY: lw = ((w_freq > w_duty) ? w_freq : w_duty) + (2 * font_space); w = (2 * w_fdv) + (2 * font_space) + w_dash; if (w_name > w) w = w_name; break; } k->x_val = lw; k->w_val = w; w += lw; k->d.w = w + w_out + (2 * font_space); k->d.h = 4 * font_baselineskip; k->x_name = k->x_val + ((k->w_val - w_name) / 2); k->x_out = k->d.w - w_out - font_space; } return(k->d); } static void setup_done(int ok, void *sbv) { SB sb; PRIV *p; sb = *(SB *)sbv; free(sbv); if (ok) { p = malloc(sizeof(PRIV)); *p = sb.p; } else { p = 0; } (*sb.cont)(p,sb.contarg); } static void setup_duty2(int ok, void *sbv) { SB sb; if (ok) { setup_getarg("Duty cycle 2",&setup_done,sbv,&((SB *)sbv)->p.duty2,PAR_FRANGE,0.,100.); } else { sb = *(SB *)sbv; free(sbv); (*sb.cont)(0,sb.contarg); } } static void setup_duty(int ok, void *sbv) { SB sb; if (ok) { if (((SB *)sbv)->p.k->flags & PF_CTL_DUTY) { setup_getarg("Duty cycle 1",&setup_duty2,sbv,&((SB *)sbv)->p.duty,PAR_FRANGE,0.,100.); } else { setup_getarg("Duty cycle",&setup_done,sbv,&((SB *)sbv)->p.duty,PAR_FRANGE,0.,100.); } } else { sb = *(SB *)sbv; free(sbv); (*sb.cont)(0,sb.contarg); } } static void setup_freq2(int ok, void *sbv) { SB sb; if (ok) { setup_getarg("Frequency 2",&setup_duty,sbv,&((SB *)sbv)->p.freq2,PAR_FREQ); } else { sb = *(SB *)sbv; free(sbv); (*sb.cont)(0,sb.contarg); } } static void setup(KIND *kind, void (*cont)(void *, void *), void *arg) { SB *sb; sb = malloc(sizeof(SB)); sb->cont = cont; sb->contarg = arg; sb->p.k = kind; if (kind->flags & PF_CTL_FREQ) { setup_getarg("Frequency 1",&setup_freq2,sb,&sb->p.freq,PAR_FREQ); } else { setup_getarg("Frequency",&setup_duty,sb,&sb->p.freq,PAR_FREQ); } } static void destroy(BLOCK_DESTROY_ARGS) { free(priv); } static void create_pm_outs(Drawable d) { int h; XPoint *tpts; int x; int y; tpts = malloc(((w_out>6)?w_out:6)*sizeof(XPoint)); h = 3 * font_baselineskip; pm_outs = XCreatePixmap(disp,d,w_out,h,1); XFillRectangle(disp,pm_outs,gc_1bpp_0,0,0,w_out,h); for (x=0;x font_baselineskip-2) y = font_baselineskip - 2; tpts[x].x = x; tpts[x].y = y; } XDrawPoints(disp,pm_outs,gc_1bpp_1,&tpts[0],w_out,CoordModeOrigin); tpts[0].x = 0; tpts[0].y = h / 2; tpts[1].x = w_out / 4; tpts[1].y = font_baselineskip + 1; tpts[2].x = (3 * w_out) / 4; tpts[2].y = (2 * font_baselineskip) - 2; tpts[3].x = w_out - 1; tpts[3].y = h / 2; XDrawLines(disp,pm_outs,gc_1bpp_1,&tpts[0],4,CoordModeOrigin); tpts[0].x = 0; tpts[0].y = (5 * font_baselineskip) / 2; tpts[1].x = 0; tpts[1].y = (2 * font_baselineskip) + 1; tpts[2].x = w_out / 2; tpts[2].y = (2 * font_baselineskip) + 1; tpts[3].x = w_out / 2; tpts[3].y = (3 * font_baselineskip) - 2; tpts[4].x = w_out - 1; tpts[4].y = (3 * font_baselineskip) - 2; tpts[5].x = w_out - 1; tpts[5].y = tpts[0].y; XDrawLines(disp,pm_outs,gc_1bpp_1,&tpts[0],6,CoordModeOrigin); free(tpts); } static int cvt_freq(double freq, char *buf) { int l; long long int ifreq; int i; unsigned char suf; if (freq < 0) panic(); do <"no0"> { do <"0"> { if (freq < 1) { ifreq = (freq * 1e12) + .5; // ifreq = freq in pHz if (ifreq < 1) { strcpy(buf,"epsilon"); return(7); } if (ifreq < 10) { return(sprintf(buf,".00%dnHz",(int)ifreq)); } if (ifreq < 100) { l = sprintf(buf,".0%d",(int)ifreq); while (buf[l-1] == '0') l --; strcpy(&buf[l],"nHz"); return(l+3); } if (ifreq < 1000) // <= .999nHz { l = sprintf(buf,".%d",(int)ifreq); while (buf[l-1] == '0') l --; strcpy(&buf[l],"nHz"); return(l+3); } if (ifreq < 10000) ifreq += 5; if (ifreq < 10000) // <= 9.99nHz { i = (int)ifreq / 10; suf = 'n'; l = sprintf(buf,"%d.%02d",i/100,i%100); break <"0">; } if (ifreq < 100000) ifreq += 50; if (ifreq < 100000) // <= 99.9nHz { i = (int)ifreq / 100; suf = 'n'; l = sprintf(buf,"%d.%d",i/10,i%10); break <"0">; } if (ifreq < 1000000) ifreq += 500; if (ifreq < 1000000) // <= 999nHz { i = (int)ifreq / 1000; suf = 'n'; l = sprintf(buf,"%d",i); break <"no0">; } if (ifreq < 10000000) // <= 9999nHz (9.999µHz) { i = (int)ifreq / 1000; suf = 'n'; l = sprintf(buf,"%d",i); break <"no0">; } if (ifreq < 100000000LL) ifreq += 50000; if (ifreq < 100000000LL) // <= 99.9µHz { i = ifreq / 100000LL; suf = 'µ'; l = sprintf(buf,"%d.%d",i/10,i%10); break <"0">; } if (ifreq < 1000000000LL) ifreq += 500000LL; if (ifreq < 1000000000LL) // <= 999µHz { i = ifreq / 1000000LL; suf = 'µ'; l = sprintf(buf,"%d",i); break <"no0">; } if (ifreq < 10000000000LL) // <= 9999µHz (9.999mHz) { i = ifreq / 1000000LL; suf = 'µ'; l = sprintf(buf,"%d",i); break <"no0">; } if (ifreq < 100000000000LL) ifreq += 50000000LL; if (ifreq < 100000000000LL) // <= 99.99mHz { i = ifreq / 100000000LL; suf = 'm'; l = sprintf(buf,"%d.%d",i/10,i%10); break <"0">; } ifreq += 500000000LL; i = ifreq / 1000000000LL; suf = 'm'; l = sprintf(buf,"%d",i); break <"no0">; } if (freq >= 1e9) { strcpy(buf,"GHz"); return(3); } ifreq = (freq * 1000) + .5; // ifreq = freq in mHz if (ifreq < 10000LL) ifreq += 5; if (ifreq < 10000LL) // <= 9.99Hz { i = (int)ifreq / 10; suf = '\0'; l = sprintf(buf,"%d.%02d",i/100,i%100); break <"0">; } if (ifreq < 100000LL) ifreq += 50; if (ifreq < 100000LL) // <= 99.9Hz { i = (int)ifreq / 100; suf = '\0'; l = sprintf(buf,"%d.%d",i/10,i%10); break <"0">; } if (ifreq < 1000000LL) ifreq += 500; if (ifreq < 1000000LL) // <= 999Hz { i = (int)ifreq / 1000; suf = '\0'; l = sprintf(buf,"%d",i); break <"no0">; } if (ifreq < 10000000LL) // <= 9999Hz (9.999kHz) { i = (int)ifreq / 1000; suf = '\0'; l = sprintf(buf,"%d",i); break <"no0">; } if (ifreq < 100000000LL) ifreq += 50000; if (ifreq < 100000000LL) // <= 99.9kHz { i = ifreq / 100000LL; suf = 'k'; l = sprintf(buf,"%d.%d",i/10,i%10); break <"0">; } if (ifreq < 1000000000LL) ifreq += 500000LL; if (ifreq < 1000000000LL) // <= 999kHz { i = ifreq / 1000000LL; suf = 'k'; l = sprintf(buf,"%d",i); break <"0">; } if (ifreq < 10000000000LL) // <= 9999kHz { i = ifreq / 1000000LL; suf = 'k'; l = sprintf(buf,"%d",i); break <"0">; } if (ifreq < 100000000000LL) ifreq += 50000000LL; if (ifreq < 100000000000LL) // <= 99.9MHz { i = ifreq / 100000000LL; suf = 'M'; l = sprintf(buf,"%d.%d",i/10,i%10); break <"0">; } if (ifreq < 1000000000000LL) ifreq += 500000000LL; if (ifreq < 1000000000000LL) // <= 999MHz { i = ifreq / 1000000000LL; suf = 'M'; l = sprintf(buf,"%d",i); break <"0">; } strcpy(buf,"GHz"); return(3); } while (0); while (buf[l-1] == '0') l --; if (buf[l-1] == '.') l --; } while (0); if (suf) buf[l++] = suf; buf[l++] = 'H'; buf[l++] = 'z'; return(l); } static int cvt_duty(double duty, char *buf) { int l; if ((duty < 0) || (duty > 100)) panic(); l = sprintf(buf,"%.1f",duty); if (l == 5) { if (strcmp(buf,"100.0")) panic(); l -= 2; } else { if (buf[l-1] == '0') l --; if (buf[l-1] == '.') l --; } buf[l++] = '%'; return(l); } static void render(BLOCK_RENDER_ARGS) { PRIV *p; KIND *k; int y; char s1[16]; char s2[16]; char s[40]; int l1; int l2; int l; p = priv; k = p->k; XFillRectangle(disp,d,gc_bg,0,0,k->d.w,k->d.h); XDrawLine(disp,d,gc_fg,0,0,k->d.w-2,0); XDrawLine(disp,d,gc_fg,k->d.w-1,0,k->d.w-1,k->d.h-2); XDrawLine(disp,d,gc_fg,k->d.w-1,k->d.h-1,1,k->d.h-1); XDrawLine(disp,d,gc_fg,0,k->d.h-1,0,1); y = font_baseline + (font_baselineskip / 2); XDrawString(disp,d,gc_fg,k->x_name,y,k->name,k->namelen); y += font_baselineskip; if (k->flags & PF_CTL_FREQ) { l1 = cvt_freq(p->freq,&s1[0]); l2 = cvt_freq(p->freq2,&s2[0]); l = sprintf(&s[0],"%.*s - %.*s",l1,&s1[0],l2,&s2[0]); } else { l = cvt_freq(p->freq,&s[0]); } XDrawString(disp,d,gc_fg,k->x_val+((k->w_val-widthof(&s[0],l))/2),y,&s[0],l); y += font_baselineskip; if (k->flags & PF_CTL_DUTY) { l1 = cvt_duty(p->duty,&s1[0]); l2 = cvt_duty(p->duty2,&s2[0]); l = sprintf(&s[0],"%.*s - %.*s",l1,&s1[0],l2,&s2[0]); } else { l = cvt_duty(p->duty,&s[0]); } XDrawString(disp,d,gc_fg,k->x_val+((k->w_val-widthof(&s[0],l))/2),y,&s[0],l); switch (k->flags & (PF_CTL_FREQ|PF_CTL_DUTY)) { case 0: break; case PF_CTL_FREQ: XDrawString(disp,d,gc_fg,font_space,font_baseline+((font_baselineskip*3)/2),"Freq",4); break; case PF_CTL_DUTY: XDrawString(disp,d,gc_fg,font_space,font_baseline+((font_baselineskip*3)/2),"Duty",4); break; case PF_CTL_FREQ | PF_CTL_DUTY: XDrawString(disp,d,gc_fg,font_space,font_baseline+(font_baselineskip/2),"Freq",4); XDrawString(disp,d,gc_fg,font_space,font_baseline+((font_baselineskip*5)/2),"Duty",4); break; } if (pm_outs == None) create_pm_outs(d); XCopyPlane(disp,pm_outs,d,gc_fg,0,0,w_out,font_baselineskip*3,k->x_out,font_baselineskip/2,1); } static int outy(BLOCK_OUTPUT_Y_ARGS) { return((pin+1)*font_baselineskip); } static KIND kind_osc = KINDINIT("Osc",0); static BLOCKDIMS size_osc(BLOCK_SIZE_ARGS) { return(size(&kind_osc)); } static void setup_osc(BLOCK_SETUP_ARGS) { setup(&kind_osc,cont,contarg); } static const char *outs[] = { "Sin", "Tri", "Sq" }; static BLOCKPARAM params_osc[] = { { .name = "Freq", .type = PAR_FREQ }, { .name = "Duty%", .type = PAR_FRANGE, .u = { .frange = { .min = 0, .max = 100 } } } }; BLOCKTYPE block_osc = BLOCKTYPE_O_P("Osc",outs,params_osc,size_osc,setup_osc,destroy,render,outy); static KIND kind_vco = KINDINIT("VCO",PF_CTL_FREQ); static BLOCKDIMS size_vco(BLOCK_SIZE_ARGS) { return(size(&kind_vco)); } static void setup_vco(BLOCK_SETUP_ARGS) { setup(&kind_vco,cont,contarg); } static int iny_vco(BLOCK_INPUT_Y_ARGS) { return(2*font_baselineskip); } static const char *ins_vco[] = { "Freq" }; static BLOCKPARAM params_vco[] = { { .name = "Freq1", .type = PAR_FREQ }, { .name = "Freq2", .type = PAR_FREQ }, { .name = "Duty%", .type = PAR_FRANGE, .u = { .frange = { .min = 0, .max = 100 } } } }; BLOCKTYPE block_vco = BLOCKTYPE_I_O_P("VCO",ins_vco,outs,params_vco,size_vco,setup_vco,destroy,render,iny_vco,outy); static KIND kind_ddcosc = KINDINIT("DDCOsc",PF_CTL_DUTY); static BLOCKDIMS size_ddcosc(BLOCK_SIZE_ARGS) { return(size(&kind_ddcosc)); } static void setup_ddcosc(BLOCK_SETUP_ARGS) { setup(&kind_ddcosc,cont,contarg); } static int iny_ddcosc(BLOCK_INPUT_Y_ARGS) { return(2*font_baselineskip); } static const char *ins_ddcosc[] = { "Duty" }; static BLOCKPARAM params_ddcosc[] = { { .name = "Freq", .type = PAR_FREQ }, { .name = "Duty%1", .type = PAR_FRANGE, .u = { .frange = { .min = 0, .max = 100 } } }, { .name = "Duty%2", .type = PAR_FRANGE, .u = { .frange = { .min = 0, .max = 100 } } } }; BLOCKTYPE block_ddcosc = BLOCKTYPE_I_O_P("DDCOsc",ins_ddcosc,outs,params_ddcosc,size_ddcosc,setup_ddcosc,destroy,render,iny_ddcosc,outy); static KIND kind_genosc = KINDINIT("GenOsc",PF_CTL_FREQ|PF_CTL_DUTY); static BLOCKDIMS size_genosc(BLOCK_SIZE_ARGS) { return(size(&kind_genosc)); } static void setup_genosc(BLOCK_SETUP_ARGS) { setup(&kind_genosc,cont,contarg); } static int iny_genosc(BLOCK_INPUT_Y_ARGS) { return(((3+(2*pin))*font_baselineskip)/2); } static const char *ins_genosc[] = { "Freq", "Duty" }; static BLOCKPARAM params_genosc[] = { { .name = "Freq1", .type = PAR_FREQ }, { .name = "Freq2", .type = PAR_FREQ }, { .name = "Duty%1", .type = PAR_FRANGE, .u = { .frange = { .min = 0, .max = 100 } } }, { .name = "Duty%2", .type = PAR_FRANGE, .u = { .frange = { .min = 0, .max = 100 } } } }; BLOCKTYPE block_genosc = BLOCKTYPE_I_O_P("GenOsc",ins_genosc,outs,params_genosc,size_genosc,setup_genosc,destroy,render,iny_genosc,outy);