x10/ 775 0 0 0 11363303772 71615ustar00syssysx10/Cat 775 0 0 222 10041014240 7547ustar00syssys#!/bin/rc rm /srv/*x10 srv -q tcp!localhost!x10 mount /srv/*x10 /n/x10 cd /n/x10 while(;){ ls >/dev/null cat * >/dev/null sleep 3 echo -n . } x10/Gui 775 0 0 131 10041030613 7565ustar00syssys#!/bin/rc rm /srv/*x10 srv -q tcp!localhost!x10 mount /srv/*x10 /n/x10 cd /n/x10 x10/gui x10/Off 775 0 0 145 10041014153 7561ustar00syssys#!/bin/rc ; ; mount /srv/*x10 /n/x10 ; ; cd /n/x10 ; while(;){ for (f in pwr*) { echo off >$f } } x10/On 775 0 0 144 10041014205 7420ustar00syssys#!/bin/rc ; ; mount /srv/*x10 /n/x10 ; ; cd /n/x10 ; while(;){ for (f in pwr*) { echo on >$f } } x10/R 775 0 0 52 10041034077 7234ustar00syssys#!/bin/rc kill fs|rc broke|rc x10/fs -D x10/fs.c 664 0 0 35633 10434627743 7774ustar00syssys#include #include #include #include #include #include #include #include <9p.h> #include #include "x10.h" static X10* x; static char myhc; /* * 0 -> cm11 * 1..n -> devices */ enum { Qdir = 0, Qcm11= 256, // 1..n -> devices Qauth= 128, // 128..m -> auth files Nauth = 2, }; static char Eperm[] = "permission denied"; static char Egone[] = "device is gone"; static char Enotexist[] = "file does not exist"; static char Ebadctl[] = "unknown control message"; static char Eattach[] = "invalid attach specifier"; static char Ex10[]= "X10 request failed"; static char Eauth[]= "authentication failed"; static char* uids[Ndevs+1]; static char* gids[Ndevs+1]; static int modes[Ndevs+1]; static char* names[Ndevs+1]; static int vers; static AuthRpc* authf[Nauth]; static int authok[Nauth]; static char* authu[Nauth]; /* * simplistic permission checking. assume that * each user is the leader of her own group. */ static int allowed(int qid, char *uid, int p) { static char* elf; int m; int mode; char* g; char* u; if (elf == nil){ elf=getenv("user"); u = strchr(elf, '\n'); if (u != nil) *u = 0; } switch(qid){ case Qdir: mode = 0775; break; case Qcm11: qid = 0; // and fall... default: if (modes[qid]) mode = modes[qid]; else mode = 0664; } if (qid >= 0 && gids[qid]) g = gids[qid]; else g = "sys"; if (qid >= 0 && uids[qid]) u = uids[qid]; else u = "sys"; m = mode & 7; /* other */ if((p & m) == p) return 1; if(strcmp(u, uid) == 0 || strcmp(uid, elf) == 0) { m |= (mode>>6) & 7; if((p & m) == p) return 1; } if(strcmp(g, uid) == 0) { m |= (mode>>3) & 7; if((p & m) == p) return 1; } return 0; } static int dirgen(int i, Dir *d, void*) { int n; Dev* devs; char name[40]; memset(d, 0, sizeof *d); d->uid = estrdup9p("sys"); d->gid = estrdup9p("sys"); d->length = 0; d->atime = d->mtime = time(nil); switch(i){ case -1: d->name = estrdup9p("/"); d->qid.type = QTDIR; d->qid.path = Qdir; d->mode = DMDIR|0775; break; case 0: d->name = estrdup9p("cm11"); d->qid.type = 0; d->qid.path = Qcm11; d->qid.vers = vers; d->mode = 0664; if (uids[0] != nil){ free(d->uid); d->uid = estrdup9p(uids[0]); } if (gids[0] != nil){ free(d->gid); d->gid = estrdup9p(gids[0]); } if (modes[0] != 0) d->mode = modes[0]&0777; break; default: devs = x10devs(x); for (n = 0; n < Ndevs; n++) if (devs[n].hc !=0 && --i == 0) break; if (n == Ndevs) return -1; if (names[n+1] == nil){ name[0] = hctochr(devs[n].hc); seprint(name+1, name+sizeof(name), "%d", dctoint(devs[n].dc)); d->name = estrdup9p(name); } else d->name = estrdup9p(names[n+1]); d->qid.type = 0; d->qid.path = n+1; d->qid.vers = vers; d->mode = 0664; if (uids[n+1] != nil){ free(d->uid); d->uid = estrdup9p(uids[n+1]); } if (gids[n+1] != nil){ free(d->gid); d->gid = estrdup9p(gids[n+1]); } if (modes[n+1] != 0) d->mode = modes[n+1]&0777; } return 0; } static char *keyspec = "proto=p9any role=server"; static void fsauth(Req* r) { int i; int afd; int fd; for (i = 0; i < Nauth; i++) if (authf[i] == nil) break; if (i == Nauth){ respond(r, "No more auth files"); return; } r->afid->qid.path = Qauth+i; r->afid->qid.type = QTAUTH; r->afid->omode = ORDWR; r->ofcall.qid = r->afid->qid; if(access("/mnt/factotum", 0) < 0) if((fd = open("/srv/factotum", ORDWR)) >= 0) mount(fd, -1, "/mnt", MBEFORE, ""); afd = open("/mnt/factotum/rpc", ORDWR); if (afd < 0) goto fail; authf[i] = auth_allocrpc(afd); authok[i] = 0; if (authf[i] == nil) goto fail; if(auth_rpc(authf[i], "start", keyspec, strlen(keyspec)) != ARok) goto fail; if (r->ifcall.uname == nil || r->ifcall.uname[0] == 0) goto fail; authu[i] = estrdup9p(r->ifcall.uname); respond(r, nil); return; fail: if (afd >= 0) close(afd); free(authf[i]); authf[i] = nil; respond(r, Eauth); } static void clrauth(int i) { if (authf[i] == nil) return; free(authu[i]); close(authf[i]->afd); free(authf[i]); authu[i] = nil; authf[i] = nil; authok[i] = 0; } static long _authread(Fid* fid, void* data, long count) { int i; long n; int rr; AuthInfo*ai; if (fid->qid.type != QTAUTH) return -1; i = fid->qid.path - Qauth; if (i < 0 || i >= Nauth || authf[i] == nil) return -1; rr = auth_rpc(authf[i], "read", nil, 0); n = 0; switch(rr){ case ARdone: ai = auth_getinfo(authf[i]); if(ai == nil){ clrauth(i); return -1; } auth_freeAI(ai); if (debug) fprint(2, "user %s authenticated\n", fid->uid); authok[i] = 1; break; case ARok: if(count < authf[i]->narg){ clrauth(i); return -1; } memmove(data, authf[i]->arg, authf[i]->narg); n = authf[i]->narg; break; case ARphase: default: clrauth(i); return -1; } return n; } static void fsauthread(Req* r) { int n; n = _authread(r->fid, r->ofcall.data, r->ifcall.count); if (n < 0) respond(r, Eauth); r->ofcall.count = n; respond(r, nil); } static void fsauthwrite(Req* r) { int ret; int i; i = r->fid->qid.path - Qauth; if (i < 0 || i >= Nauth || authf[i] == nil){ respond(r, Enotexist); return; } ret = auth_rpc(authf[i], "write", r->ifcall.data, r->ifcall.count); if(ret != ARok){ clrauth(i); respond(r, Eauth); return; } r->ofcall.count = r->ifcall.count; respond(r, nil); } static void fsattach(Req *r) { char *spec; int i; uchar buf[1]; if (r->afid == nil){ respond(r, Eauth); return; } i = r->afid->qid.path - Qauth; if (i < 0 || i >= Nauth || authf[i] == nil){ respond(r, Eauth); return; } if (!authok[i] && _authread(r->afid, buf, 0) != 0){ clrauth(i); respond(r, Eauth); return; } authok[i] = 1; if (strcmp(authu[i], r->fid->uid) != 0){ clrauth(i); respond(r, Eauth); return; } clrauth(i); x10reqsts(x); vers++; spec = r->ifcall.aname; if(spec != nil && spec[0] != 0){ respond(r, Eattach); return; } r->ofcall.qid = (Qid){0, 0, QTDIR}; r->fid->qid = r->ofcall.qid; respond(r, nil); } static void fsopen(Req *r) { ulong qid; int mode; r->ifcall.mode &= 3; if (r->fid->qid.type == QTAUTH){ r->fid->omode = r->ifcall.mode; respond(r, nil); return; } switch(r->ifcall.mode){ case OREAD: mode = AREAD; break; case OWRITE: mode = AWRITE; break; case ORDWR: mode = AREAD|AWRITE; break; default: respond(r, Eperm); return; } qid = r->fid->qid.path; if (qid >= 0 && qid <= Ndevs){ r->fid->qid.vers = vers; r->ofcall.qid = r->fid->qid; } if (!allowed(qid, r->fid->uid, mode) || (r->ifcall.mode != OREAD && qid == Qdir) ){ respond(r, Eperm); return; } r->fid->omode = r->ifcall.mode; respond(r, nil); } static void fsread(Req *r) { static char null[] = ""; static char* ons[] = {"off", "on"}; Dev* devs; ulong qid; int o; char buf[80]; static ulong laststs; ulong t; qid = r->fid->qid.path; if (r->fid->qid.type == QTAUTH){ if (debug) fprint(2, "auth read\n"); fsauthread(r); return; } o = r->fid->omode & 3; if (o != OREAD && o != ORDWR){ respond(r, Eperm); return; } switch(qid){ case Qdir: x10reqsts(x); vers++; dirread9p(r, dirgen, nil); break; case Qcm11: cm11sprint(x, buf, sizeof(buf)); readstr(r, buf); break; default: if (!laststs) laststs = time(nil); t = time(nil); if (t - laststs >= 10){ if (x10reqsts(x) < 0){ sleep(500); if (x10reqsts(x) < 0){ respond(r, Ex10); return; } } laststs = time(nil); } devs = x10devs(x); if (qid <= 0 || qid > Ndevs || devs[qid-1].hc ==0){ respond(r, Egone); return; } readstr(r, ons[devs[qid-1].on]); } respond(r, nil); } /* * Process command as-is */ static char* cm11cmd(char* cmd) { char* args[10]; int nargs; int r; char saved[40]; int attempts; if (debug) fprint(2, "cm11cmd %s ", cmd); strecpy(saved, saved+sizeof(saved), cmd); nargs = tokenize(cmd, args, nelem(args)); if (nargs == 0){ if (debug) fprint(2, "ignored\n"); return nil; } if (nargs == nelem(args)) sysfatal("bug: sh: fixme: Nargs overflow"); if (*args[1] != myhc){ if (debug) fprint(2, "ignored\n"); return nil; } if (debug) fprint(2, "\n"); args[nargs] = nil; attempts = 0; again: r = runfunc(x, nargs, args); if (r == 0){ syslog(0, logf, "cm11cmd %s: bad ctl", saved); return Ebadctl; } if (r < 0){ if (attempts++ < 10){ sleep(1000); goto again; } syslog(0, logf, "cm11cmd %s failed", saved); return Ex10; } syslog(0, logf, "cm11cmd %s", saved); return nil; } /* * process "first word" + house + device + "rest" */ static char* devcmd(char* cmd, uchar hc, uchar dc) { char ncmd[50]; char* s; s = strchr(cmd, ' '); if (s == nil) s = ""; else *s++= 0; seprint(ncmd, ncmd+sizeof(ncmd), "%s %c %d %s", cmd, hctochr(hc), dctoint(dc), s); return cm11cmd(ncmd); } static void fswrite(Req *r) { static char buf[30]; Dev* devs; ulong qid; char* e; int l; ulong o; if (r->fid->qid.type == QTAUTH){ fsauthwrite(r); return; } o = r->fid->omode & 3; if (o != OWRITE && o != ORDWR){ respond(r, Eperm); return; } r->ofcall.count = r->ifcall.count; if (r->ofcall.count > sizeof(buf)-1) r->ofcall.count = sizeof(buf)-1; memmove(buf, r->ifcall.data, r->ofcall.count); buf[r->ofcall.count] = 0; l = strlen(buf); if (l > 0 && buf[l-1] == '\n') buf[l-1] = 0; qid = r->fid->qid.path; switch(qid){ case Qdir: respond(r, Eperm); return; case Qcm11: e = cm11cmd(buf); if (e != nil){ respond(r, e); return; } break; default: devs = x10devs(x); if (qid <= 0 || qid > Ndevs || devs[qid-1].hc ==0){ respond(r, Egone); return; } // BUG: should handle 'on ' besides 'on ' e = devcmd(buf, devs[qid-1].hc, devs[qid-1].dc); if (e != nil){ respond(r, e); return; } break; } respond(r, nil); // and update our status now that it changed x10reqsts(x); vers++; } static void fsstat(Req *r) { ulong qid; qid = r->fid->qid.path; dirgen(qid == Qdir ? -1 : qid, &r->d, nil); respond(r, nil); } static char* fswalk1(Fid *fid, char *name, void*) { int n; uchar hc; uchar dc; Dev* devs; int i; if(strcmp(name, "..") == 0) // we're in / return nil; if (strcmp(name, "cm11") == 0){ fid->qid.type = 0; fid->qid.path = Qcm11; return nil; } for (i = 0; i < Ndevs; i++) if (names[i] != nil && strcmp(names[i], name) == 0){ fid->qid.type = 0; fid->qid.path = i; return nil; } if (name[0] >= 'a' && name[0] <= 'p' ){ hc = chrtohc(name[0]); n = atoi(name+1); dc = inttodc(n); devs = x10devs(x); for (i = 0; i < Ndevs; i++) if (devs[i].hc == hc && devs[i].dc == dc){ fid->qid.type = 0; fid->qid.path = i+1; return nil; } } return Enotexist; } static char* fsclone(Fid *, Fid*, void*) { return nil; } static void fswalk(Req *r) { //x10reqsts(x); walkandclone(r, fswalk1, fsclone, nil); } static void fswstat(Req* r) { ulong qid; Dev* devs; qid = r->fid->qid.path; switch(qid){ case Qdir: respond(r, Eperm); return; case Qcm11: qid = 0; goto chperm; default: devs = x10devs(x); if (qid <= 0 || qid > Ndevs || devs[qid-1].hc ==0){ respond(r, Egone); return; } chperm: if (r->d.uid && r->d.uid[0]){ if (uids[qid] != nil && strcmp(uids[qid], r->d.uid) != 0 ){ respond(r, Eperm); return; } uids[qid] = strdup(r->d.uid); } if (r->d.gid && r->d.gid[0]){ if (gids[qid] != nil){ respond(r, Eperm); return; } gids[qid] = strdup(r->d.gid); } if (~(ulong)r->d.mode){ if (!uids[qid] && modes[qid] != 0){ respond(r, Eperm); return; } if (uids[qid] && strcmp(r->fid->uid, uids[qid])){ respond(r, Eperm); return; } modes[qid] = r->d.mode; } } respond(r, nil); } static Channel* reqc; static Channel* waitc; static void fssend(Req* r) { sendp(reqc, r); recvp(waitc); } static void shutdown(Srv* p) { close(p->infd); free(p); threadexits("done"); } static void fsproc(void*) { Req* r; threadsetname("fsproc"); for(;;){ r = recvp(reqc); switch(r->ifcall.type){ case Tauth: fsauth(r); break; case Tattach: fsattach(r); break; case Topen: fsopen(r); break; case Tread: fsread(r); break; case Twrite: fswrite(r); break; case Tstat: fsstat(r); break; case Twstat: fswstat(r); break; case Twalk: fswalk(r); break; default: respond(r, "bug in fsproc: bad ifcall type"); break; } sendp(waitc, nil); } } static Srv sfs= { .auth= fssend, .attach=fssend, .open= fssend, .read= fssend, .write= fssend, .stat= fssend, .wstat= fssend, .walk= fssend, .end= shutdown, }; static void perm(char* ln) { char* args[10]; int nargs; int n; // perm name owner group mode nargs = tokenize(ln, args, nelem(args)); if (nargs != 5) return; if (*args[1] != myhc) return; n = atoi(args[1]+1); if (n <0 || n >= Ndevs) return; uids[n] = strdup(args[2]); gids[n] = strdup(args[3]); modes[n]= strtol(args[4], nil, 0); } static void setname(char* ln) { char* args[10]; int nargs; int n; // name a1 str nargs = tokenize(ln, args, nelem(args)); if (nargs != 3) return; if (*args[1] != myhc) return; n = atoi(args[1]+1); if (n <0 || n >= Ndevs) return; names[n] = estrdup9p(args[2]); } static void config(char* conf) { Biobuf* bc; char* ln; char* c; if (conf == nil) return; bc = Bopen(conf, OREAD); if (bc == nil) return; while(ln = Brdstr(bc, '\n', 1)){ c = strchr(ln, '#'); if (c != nil) *c = 0; if (ln[0] == '\n' || ln[0] == '#' || ln[0] == 0) continue; if (strncmp("perm", ln, 4) == 0) perm(ln); else if (strncmp("name", ln, 4) == 0) setname(ln); else cm11cmd(ln); } Bterm(bc); } typedef struct PArg PArg; struct PArg { int lfd; char ldir[40]; }; static void srvproc(void* a) { PArg* p; Srv* msrv; int dfd; p = a; threadsetname("srvproc"); dfd = accept(p->lfd, p->ldir); if (dfd < 0){ free(p); threadexits(nil); } close(p->lfd); free(p); msrv = emalloc9p(sizeof(Srv)); *msrv = sfs; msrv->infd = dfd; msrv->outfd= dfd; msrv->srvfd= -1; msrv->nopipe= 1; rfork(RFNOTEG); srv(msrv); threadexits(nil); } static void listener(void *) { int afd, lfd; char adir[40]; char ldir[40]; PArg* p; threadsetname("listener"); afd = announce("tcp!*!19000", adir); if (afd < 0) sysfatal("can't announce: %r"); for(;;){ lfd = listen(adir, ldir); if (lfd < 0) sysfatal("can't listen: %r"); p = emalloc9p(sizeof(PArg)); p->lfd = lfd; strcpy(p->ldir, ldir); proccreate(srvproc, p, 32*1024); } } static void announceproc(void*) { int afd = -1; char* addr; addr = smprint("tcp!%s!19000 ", sysname()); for(;;){ afd = announcevol(afd, addr, "/devs/x10", nil); sleep(10 * 1000); } } void pfs(X10* p, char hc, char* conf) { x = p; myhc = hc; config(conf); x10reqsts(x); reqc = chancreate(sizeof(void*), 0); waitc = chancreate(sizeof(void*), 0); if (proccreate(announceproc, nil, 8*1024) < 0) sysfatal("procrfork: %r"); if (proccreate(listener, nil, 32*1024) < 0) sysfatal("procrfork: %r"); proccreate(fsproc, nil, 32*1024); syslog(0, logf, "X10 house %c started", hc); } 0) respond(r, Eauth); r->ofcall.count = n; respond(r, nil); } static void fsauthwrite(Req* r) {x10/gui.c 664 0 0 11546 10431042024 10121ustar00syssys#include #include #include #include typedef struct X10 X10; struct X10 { char *name; char *file; Rectangle r; int on; int err; int locked; }; X10 *x10; int nx10; Image *lightblue; Image *yellow; Image *red; int dsz=2; enum { PAD = 3, MARGIN = 5 }; char *dir = "/devs/x10"; void* erealloc(void *v, ulong n) { v = realloc(v, n); if(v == nil) sysfatal("out of memory reallocating %lud", n); return v; } void* emalloc(ulong n) { void *v; v = malloc(n); if(v == nil) sysfatal("out of memory allocating %lud", n); memset(v, 0, n); return v; } char* estrdup(char *s) { int l; char *t; if (s == nil) return nil; l = strlen(s)+1; t = emalloc(l); memcpy(t, s, l); return t; } void init(void) { int i, j, fd, nr; Dir *pd; char buf[128]; if((fd = open(dir, OREAD)) < 0) return; nr = dirreadall(fd, &pd); x10 = emalloc(nr * sizeof(X10)); for(i=j=0; i= 0){ str = ( x10[i].on ? "on" : "off"); n = write(fd, str, strlen(str)); if (n < 0) x10[i].err = 1; } else x10[i].err = 1; close(fd); } int readx10(void) { int i; int fd; char buf[80]; int n; int changed; int last; changed = 0; for (i = 0; i < nx10; i++){ last = x10[i].on; x10[i].on = 0; fd = open(x10[i].file, OREAD); n = read(fd, buf, sizeof(buf)-1); if (n > 0){ buf[n] = 0; if (strcmp(buf, "on") == 0) x10[i].on = 1; } if (n < 0) x10[i].err = 1; close(fd); changed |= (x10[i].err || x10[i].on != last); } return changed; } void drawx10(int i) { if(x10[i].err || x10[i].locked){ draw(screen, x10[i].r, red, nil, ZP); x10[i].err = 0; } else if(x10[i].on) draw(screen, x10[i].r, yellow, nil, ZP); else draw(screen, x10[i].r, lightblue, nil, ZP); _string(screen, addpt(x10[i].r.min, Pt(2,0)), display->black, ZP, font, x10[i].name, nil, strlen(x10[i].name), x10[i].r, nil, ZP, SoverD); border(screen, x10[i].r, 1, display->black, ZP); } void x10togglelock(int i) { Dir d; nulldir(&d); if (x10[i].locked) d.mode = 0644; else d.mode = 0444; x10[i].locked = !x10[i].locked; dirwstat(x10[i].file, &d); } void geometry(void) { static int cols; int i, ncols, rows; Rectangle r; rows = (Dy(screen->r)-2*MARGIN+PAD)/(font->height*dsz+PAD); if(rows*cols < nx10 || rows*cols >= nx10*2){ ncols = (nx10+rows-1)/rows; if(ncols != cols){ cols = ncols; } } r = Rect(0,0,(Dx(screen->r)-2*MARGIN+PAD)/cols-PAD, font->height*dsz); for(i=0; ir.min); } void redraw(Image *screen) { int i; draw(screen, screen->r, lightblue, nil, ZP); for(i=0; i 1){ dir = *argv++; argc--; } if(argc > 1) { argv++; argc--; x10 = emalloc((argc)*sizeof(X10)); while(argc--) { x10[argc].file = estrdup(argv[argc]); c = strrchr(x10[argc].file, '/'); x10[argc].name = (c == nil ? x10[argc].file : c+1); x10[argc].on = -1; x10[argc].err= 0; nx10++; } } else init(); initdraw(0, 0, "x10/gui"); lightblue = allocimagemix(display, DPalebluegreen, DWhite); if(lightblue == nil) sysfatal("allocimagemix: %r"); yellow = allocimagemix(display, DYellow, DWhite); if(yellow == nil) sysfatal("allocimagemix: %r"); red = allocimagemix(display, DRed, DWhite); if(red == nil) sysfatal("allocimagemix: %r"); eresized(0); einit(Emouse|Ekeyboard|0x8); etimer(0x8, 10 * 1000); for(;;){ switch(eread(Emouse|Ekeyboard|0x8, &e)){ case Ekeyboard: if(e.kbdc==0x7F || e.kbdc=='q') exits(0); break; case Emouse: if(e.mouse.buttons) click(e.mouse); break; case 0x8: if (readx10()) redraw(screen); break; } } } [0]); n = atoi(name+1); dc = inttodc(n); devs = x10devs(x); for (i = 0; i < Ndevs; i++) if (devs[i].hc == hc && devs[i].dc == dc){ fid->qidx10/main.c 664 0 0 10450 10043644710 10263ustar00syssys#include #include #include #include #include #include #include <9p.h> #include "x10.h" typedef struct Cmd Cmd; struct Cmd { char* name; int nargs; int (*f)(X10*, int, char**); }; int quiet; int interactive; int mainstacksize = 32*1024; char logf[] = "x10X"; static int func(X10*x, int, char** args) { char hc; int dc; int i; int dim; for (i = 0; i < Fmax; i++) if (strcmp(args[0], x10fnames[i]) == 0) break; if (i == Fmax) return -1; hc=args[1][0]; dc=1; dim = 0; if (args[2] != nil) dc=atoi(args[2]); if (args[3] != nil) dim = atoi(args[3]); if (x10reqaddr(x, hc, dc) < 0 || x10reqfunc(x, i, dim) < 0) return -1; return 0; } static int sts(X10* x, int, char**) { return x10reqsts(x); } static int dump(X10*x, int, char**) { x10print(2, x); return 0; } static int quit(X10* x, int, char**) { x10close(x); threadexitsall(nil); return 0; } static int devs(X10* x, int, char**) { static char* ons[] = { "off", "on " }; Dev* d; int i; if (x10reqsts(x) < 0) return -1; d = x10devs(x); for(i = 0; i < Ndevs; i++){ if (d[i].hc != 0) fprint(2, "dev %c %d %s dim %d\n", hctochr(d[i].hc), dctoint(d[i].dc), ons[d[i].on], d[i].dim); } return 0; } static int dbg(X10*, int, char**args) { debug = atoi(args[1]); return 0; } static int help(X10*, int, char**); static char prompt[] = "\n→ "; static Cmd cmds[] = { // All X10 funcs plus.. {"s", 0, sts}, {"sts", 0, sts}, {"d", 0, dump}, {"dump", 0, dump}, {"q", 0, quit}, {"quit",0, quit}, {"p", 0, devs}, {"print",0, devs}, {"?", 0, help}, {"D", 1, dbg}, }; // 0: disabled; 1 hc; 2 hc dc; 3 hc dc dim static int x10fargs[] = { 1, 1, 2, 2, 3, 3, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, }; static char* fusage[] = { "—disabled—", "hc", "hc dc", "hc dc dim", }; static int help(X10*, int, char**) { int i; int a; print("\ts status\n"); print("\td dump\n"); print("\tq quit\n"); print("\tp print\n"); for (i = 0; i < Fmax; i++){ a = x10fargs[i]; if (a != 0) print("\t%s %s\n", x10fnames[i], fusage[a]); } return 0; } int runfunc(X10* x, int nargs, char** args) { int i; int a; for (i = 0; i < Fmax; i++) if (strcmp(args[0], x10fnames[i]) == 0) break; if (i == Fmax) return 0; a = x10fargs[i]; if (a == 0) return 0; if (nargs < 1 + a){ if (interactive) print("%s: wrong number of arguments\n", args[0]); else return -1; } else if (func(x, nargs, args) < 0){ if (interactive) print("%s: failed\n", args[0]); return -1; } return 1; } static int runcmd(X10* x, int nargs, char** args) { int i; for (i = 0; i < nelem(cmds); i++) if (strcmp(args[0], cmds[i].name) == 0) break; if (i == nelem(cmds)) return 0; if (cmds[i].nargs >= 0 && 1+cmds[i].nargs != nargs) print("%s: wrong number of arguments\n", args[0]); else if (cmds[i].f(x, nargs, args) < 0) print("%s: failed\n", cmds[i].name); return 1; } static void sh(X10* x) { Biobuf bin; char* args[10]; int nargs; char* ln; Binit(&bin, 0, OREAD); for(;;){ if (!quiet) print("%s", prompt); ln = Brdstr(&bin, '\n', 1); if (ln == nil) break; if (ln[0] == '\n' || ln[0] == 0) continue; memset(args, 0, sizeof(args)); nargs = tokenize(ln, args, nelem(args)); if (nargs == 0) continue; if (nargs == nelem(args)) sysfatal("bug: sh: fixme: Nargs overflow"); if (args[0] == nil){ print("sh: null command\n"); continue; } if (!runfunc(x, nargs, args) && !runcmd(x, nargs, args)) print("?\n"); } } static void usage(void) { fprint(2, "usage: %s [-Diq] [-h hc] [-d dev] [-f cnf]\n", argv0); threadexitsall("usage"); } void threadmain(int argc, char* argv[]) { X10* x10; char* dev; char* conf; char hc; int net; net = 1; dev = "/dev/eia0"; conf= "/sys/lib/x10conf"; hc = 'a'; ARGBEGIN{ case 'i': interactive = 1; break; case 'D': if (debug) chatty9p++; debug = 1; break; case 'q': quiet = 1; break; case 'd': dev = EARGF(usage()); break; case 'f': conf= EARGF(usage()); break; case 'h': hc = *EARGF(usage()); break; default: usage(); }ARGEND; if (argc != 0) usage(); logf[3] = hc; x10 = x10open(dev, hc); x10reqsts(x10); sleep(1000); if (net){ pfs(x10, hc, conf); } else if (interactive){ sh(x10); x10close(x10); } else usage(); sleep(3*1000); threadexits(nil); } sysx10/mkfile 664 0 0 256 10431043536 10330ustar00syssys #include #include #include #include #include typedef struct X10 X10; struct X10 { char *name; char *file; Panel* g; int on; int err; int locked; }; X10 x10[50]; int nx10; char *dir = "/devs/x10"; Panel*gtop; void addx10(char* f) { int i, j, fd, nr; Dir* d; Dir* pd; char* fn; char xname[50]; if((fd = open(f, OREAD)) < 0) return; d = dirfstat(fd); if (d == nil){ close(fd); return; } if (d->qid.type&QTDIR){ nr = dirreadall(fd, &pd); for(i=0; ipanel && !x10[i].locked){ x10[i].on = !x10[i].on; writex10(i); drawx10(); break; } } void protect(Oev* g) { int i; char nam[40]; for (i = 0; i < nx10; i++) if (x10[i].g == g->panel){ x10togglelock(i); openpanel(x10[i].g, OWRITE|OTRUNC); if(x10[i].locked){ seprint(nam, nam+sizeof(nam), "[%s]", x10[i].name); writepanel(x10[i].g, nam, strlen(nam)); } else writepanel(x10[i].g, x10[i].name, strlen(x10[i].name)); closepanel(x10[i].g); drawx10(); break; } } void timerproc(void*a) { Channel*tc = a; for(;;){ sleep(3*1000); sendul(tc, 0); } } void usage(void) { fprint(2, "usage: x10/gui [file...]\n"); exits("usage"); } int omerogone(void) { sysfatal("gone"); return 0; } void threadmain(int argc, char *argv[]) { Oev e; int t; Alt a[] = { {nil, &e, CHANRCV}, {nil, &t, CHANRCV}, {nil, nil, CHANEND}, }; ARGBEGIN{ default: usage(); }ARGEND; gtop = createpanel("x10", "col", nil); if (gtop == nil) sysfatal("initgraph"); if (argc == 0) addx10("/devs/x10"); else while(argc--) addx10(*argv++); closepanelctl(gtop); a[0].c = omeroeventchan(nil); a[1].c = chancreate(sizeof(ulong), 0); proccreate(timerproc, a[1].c, 8*1024); updatex10(); drawx10(); for(;;){ switch(alt(a)){ case 0: if (!strcmp(e.ev, "look")) protect(&e); else if (!strcmp(e.ev, "exec")) toggle(&e); clearoev(&e); break; case 1: if (updatex10()) drawx10(); break; default: sysfatal("alt"); } } } ustar00syssysx10/power.c 644 0 0 13651 10156311252 10614ustar00nemosys#include #include enum { Hitmout = 60 * 60, // power off time out (secs) Lotmout = 60, // lights off Ival = 5, // check interval (secs) // power states Sunknown = 0, Sidle, // no who, no pwr Son, // who, pwr Stmout, // pwr timing out Nstates, }; typedef struct Cmd Cmd; typedef struct State State; typedef int (*Statef)(Cmd* c, State* s); struct State { vlong gonetime; int who; int lastwho; vlong now; }; struct Cmd { vlong gonetime; char* file; int state; int last; int tmout; Statef func[Nstates]; }; int getx10(char* f) { int fd; char buf[10]; int n; fd = open(f, OREAD); if (fd < 0) return -1; n = read(fd, buf, sizeof(buf)-1); if (n < 0){ close(fd); return -1; } buf[n] = 0; close(fd); if (strcmp(buf, "on") == 0) return 1; else return 0; } void setx10(char* f, char* to) { int fd; int n; if (f == nil) return; fd = open(f, OWRITE); if (fd < 0){ fprint(2, "%s: error: %s -> %s: %r\n", argv0, f, to); syslog(0, "x10a", "%s: open error: %s -> %s: %r\n", argv0, f, to); return; } n = write(fd, to, strlen(to)); close(fd); if (n < 0) syslog(0, "x10a", "%s: write error: %s -> %s: %r\n", argv0, f, to); } static void switchdev(char* file, char* what, int tmout) { if (tmout > 0){ syslog(0, "x10a", "%s: switching %s" " %s in %d minutes", argv0, what, file, tmout/60); } else { syslog(0, "x10a", "%s: switching %s %s now", argv0, what, file); setx10(file, what); sleep(1000); } } void setvol(char* file, int val) { int fd; fd = open(file, OWRITE); if (fd < 0) return; syslog(0, "x10a", "%s: adjusting %s to %d", argv0, file, val); fprint(fd, "audio out %d\n", val); close(fd); } int getvol(char* file) { char buf[100]; int fd; int n; int l; fd = open(file, OREAD); if (fd < 0) return -1; n = read(fd, buf, sizeof(buf)-1); close(fd); if (n < 0) return -1; buf[n] = 0; l = strlen("audio out "); if (strncmp(buf, "audio out ", l) != 0) return 70; return atoi(buf + l); } static int terminit(Cmd* c, State* s) { if (s->who){ switchdev(c->file, "on", 0); return Son; } else { s->gonetime = s->now; switchdev(c->file, "off", c->tmout); return Stmout; } } static int volinit(Cmd* c, State* s) { if (c->last < 0) c->last = getvol(c->file); if (s->who){ return Son; } else { return Stmout; } } static int nvolinit(Cmd* c, State* s) { c->last = getvol(c->file); if (s->who){ if (c->last > 40) setvol(c->file, 40); return Son; } else { if (c->last > 0) setvol(c->file, c->last); return Sidle; } } static int termidle(Cmd* c, State* s) { if (s->who && !s->lastwho){ switchdev(c->file, "on", 0); return Son; } else return Sidle; } static int volidle(Cmd* c, State* s) { if (c->last < 0) c->last = 70; if (s->who && !s->lastwho){ setvol(c->file, c->last); return Son; } else return Sidle; } static int nvolidle(Cmd* c, State* s) { if (s->who && !s->lastwho){ c->last = getvol(c->file); if (c->last == 0){ sleep(1000); c->last = getvol(c->file); } if (c->last > 70) setvol(c->file, 70); return Son; } else return Sidle; } static int termon(Cmd* c, State* s) { if (!s->who && s->lastwho){ switchdev(c->file, "off", c->tmout); return Stmout; } else return Son; } static int volon(Cmd* c, State* s) { if (!s->who && s->lastwho){ c->last = getvol(c->file); return Stmout; } else return Son; } static int nvolon(Cmd* c, State* s) { if (!s->who && s->lastwho){ if (c->last == 0){ c->last = getvol(c->file); } if (c->last > 0) setvol(c->file, c->last); return Sidle; } else return Son; } static int termtmout(Cmd* c, State* s) { if (s->who && !s->lastwho){ switchdev(c->file, "on", 0); return Son; } else if (s->gonetime > 0 && s->now - s->gonetime >= c->tmout){ switchdev(c->file, "off", 0); c->gonetime = 0; // no more power offs until he cames return Sidle; } else return Stmout; } static int voltmout(Cmd* c, State* s) { if (s->who && !s->lastwho){ if (c->last == 0) c->last = 70; setvol(c->file, c->last); return Son; } else if (s->gonetime > 0 && s->now - s->gonetime >= c->tmout){ c->last = getvol(c->file); setvol(c->file, 0); s->gonetime = 0; // no mutes until he cames return Sidle; } else return Stmout; } Cmd tcmd = { 0LL, nil, Sunknown, -1, Hitmout, {terminit, termidle, termon, termtmout} }; Cmd lcmd = { 0LL, nil, Sunknown, -1, Lotmout, {terminit, termidle, termon, termtmout} }; Cmd vcmd = { 0LL, nil, Sunknown, -1, Lotmout, {volinit, volidle, volon, voltmout} }; Cmd ncmd = { 0LL, nil, Sunknown, -1, Lotmout, {nvolinit, nvolidle, nvolon, nil} }; Cmd cmds[100]; int ncmds; void usage(void) { fprint(2, "usage: %s " "[-t term] [-n vol] [-v vol] [-l light] whofile\n", argv0); exits("usage"); } void main(int argc, char* argv[]) { State s; char* whof; Cmd* cp; int i; ARGBEGIN{ case 't': cmds[ncmds] = tcmd; cmds[ncmds].file = EARGF(usage()); ncmds++; break; case 'v': cmds[ncmds] = vcmd; cmds[ncmds].file = EARGF(usage()); ncmds++; break; case 'n': cmds[ncmds] = ncmd; cmds[ncmds].file = EARGF(usage()); ncmds++; break; case 'l': cmds[ncmds] = lcmd; cmds[ncmds].file = EARGF(usage()); ncmds++; break; default: usage(); }ARGEND; if (argc != 1 || ncmds == 0) usage(); whof = argv[0]; memset(&s, 0, sizeof(s)); for(;;){ sleep(Ival * 1000); s.now = time(nil); s.lastwho = s.who; s.who = getx10(whof); if (s.who < 0){ syslog(0, "x10a", "%s: can't read %s", argv0, whof); continue; } if (s.who != s.lastwho){ if (s.who){ for (i = 0; i < ncmds; i++) cmds[i].gonetime = 0; //syslog(0, "x10a", "%s: %s came", argv0, whof); s.gonetime = 0; } else { for (i = 0; i < ncmds; i++) cmds[i].gonetime = s.now; //syslog(0, "x10a", "%s: %s gone", argv0, whof); s.gonetime = s.now; } } for (i = 0; i < ncmds; i++){ cp = &cmds[i]; assert(cp->state >= 0 && cp->state < Nstates); cp->state = cp->func[cp->state](cp, &s); } } } d); if (d == nil){ close(fd); return; } if (d->qid.type&QTDIR){ nr = dirreadalx10/x10.c 664 0 0 32335 10041232042 7742ustar00syssys#include #include #include #include #include "x10.h" typedef struct Event Event; // event from CM11 typedef struct Func Func; // function event typedef struct CM11 CM11; // CM11 status info enum { Nevs = 16, // Event.type Enone = 0, Eaddr, Efunc, }; struct Func { uchar hc; // house code uchar fn; // function union { // !Fext struct { uchar val; }; // Fext struct { uchar data; uchar cmd; }; }; }; struct Event { int type; union { Addr a; Func f; }; }; struct CM11 { ushort timer; short h,m,s; short day; short yday; uchar wdays; uchar hc; uchar vers; ushort devs; ushort sts; ushort dim; }; struct X10 { char* dev; // serial device char* sdev; // ctl for device uchar hc; // house code int fd; // file descriptor for dev int ndevs; // # of known devices Dev devs[Ndevs]; // known devices Event evs[Nevs]; // events from CM11 CM11 cm11; }; int debug=0; // housecode 'A'..'P static char hcodes[] = { 0x6, 0xe, 0x2, 0xa, 0x1, 0x9, 0x5, 0xd, 0x7, 0xf, 0x3, 0xb, 0x0, 0x8, 0x4, 0xc }; // device code 1..16 static char dcodes[] = { 0x6, 0xe, 0x2, 0xa, 0x1, 0x9, 0x5, 0xd, 0x7, 0xf, 0x3, 0xb, 0x0, 0x8, 0x4, 0xc }; /* dcbit[dc] bit's on if dc is in mask */ static ushort dcbit[] = { 0x4000, 0x0040, 0x0400, 0x0004, 0x0200, 0x0002, 0x2000, 0x0020, 0x8000, 0x0080, 0x0800, 0x0008, 0x0100, 0x0001, 0x1000, 0x0010, }; // function names char* x10fnames[] = { "alloff", "lightson", "on", "off", "dim", "bright", "lightsoff", "ext", "hailreq", "hailack", "psdim1", "psdim2", "extxfer", "stson", "stsoff", "stsreq" }; Dev* x10devs(X10* x) { return &x->devs[0]; } uchar hctochr(uchar c) { int i; for (i = 0; i < nelem(hcodes); i++) if (c == hcodes[i]) return 'a'+i; return '?'; } uchar chrtohc(uchar hc) { hc = tolower(hc); if (hc < 'a') hc = 'a'; if (hc > 'p') hc = 'p'; hc -= 'a'; return hcodes[hc]; } uchar dctoint(uchar c) { int i; for (i = 0; i < nelem(hcodes); i++) if (c == hcodes[i]){ return i+1; } return -1; } uchar inttodc(uchar dc) { if (dc < 1) dc = 1; if (dc > 16) dc = 16; dc -= 1; return dcodes[dc]; } char* fntostr(uchar f) { static char unk[] = "Func?"; if (f < nelem(x10fnames)) return x10fnames[f]; else return unk; } void cm11sprint(X10* x, char* buf, int len) { CM11* c; char* b; c = &x->cm11; b = seprint(buf, buf+len, "timer %04x ", c->timer); b = seprint(b, buf+len, "%d:%d:%d ", c->h, c->m, c->s); b = seprint(b, buf+len, "day %d days %x ", c->yday, c->wdays); b = seprint(b, buf+len, "hc %c vers %d ", hctochr(c->hc), c->vers); b = seprint(b, buf+len, "devs %04x sts %04x ", c->devs, c->sts); seprint(b, buf+len, "dim %04x\n", c->dim); } void x10print(int fd, X10* x) { static char* ons[] = { "off", "on" }; int i; Addr* a; Func* f; Dev* d; CM11* c; fprint(fd, "dev at %s (hc %c):\n", x->dev, hctochr(x->hc)); c = &x->cm11; fprint(2, "\tcm11: timer %04x ", c->timer); fprint(2, "%d:%d:%d ", c->h, c->m, c->s); fprint(2, "day %d days %x ", c->yday, c->wdays); fprint(2, "hc %c vers %d ", hctochr(c->hc), c->vers); fprint(2, "devs %04x sts %04x ", c->devs, c->sts); fprint(2, "dim %04x\n", c->dim); fprint(fd, "\n\tdevices: "); for (i = 0; i < Ndevs; i++){ d = &x->devs[i]; if (d->hc != 0){ fprint(fd, "%c:%d=", hctochr(d->hc), dctoint(d->dc)); fprint(fd, "[%s,%x] ", ons[d->on], d->dim); } } fprint(fd, "\n\tevents: "); for (i = 0; i < Nevs; i++){ switch(x->evs[i].type){ case Eaddr: a = &x->evs[i].a; fprint(fd, "%c:%d ", hctochr(a->hc), dctoint(a->dc)); break; case Efunc: f = &x->evs[i].f; fprint(fd, "%c:%s", hctochr(f->hc), fntostr(f->fn)); if (f->fn == Fext) fprint(fd, "[%x %x] ", f->data, f->cmd); else fprint(fd, "[%x]", f->val); break; } } fprint(fd, "\n"); } static void updatedevs(X10* x) { int i; int di; Addr* a; Func* f; // Look at events reported // learn any address mentioned in the same hc // and update its on/off status by looking at funcions di = -1; for (i = 0; i < Nevs; i++){ switch(x->evs[i].type){ case Eaddr: a = &x->evs[i].a; if (a->hc != x->hc){ di = -1; continue; } di = dctoint(a->dc)-1; x->devs[di].hc = x->hc; x->devs[di].dc = a->dc; break; case Efunc: if (di < 0) continue; f= &x->evs[i].f; if (f->hc != x->hc) continue; if (f->fn == Fon) x->devs[di].on = 1; if (f->fn == Foff) x->devs[di].on = 0; break; } } memset(x->evs, 0, sizeof(x->evs)); // Add any other shown in cm11 devs & sts masks for (i = 0; i < Ndevs; i++){ x->devs[i].on = 0; x->devs[i].dim = 0; x->devs[i].dc = inttodc(i+1); if (x->cm11.devs & dcbit[i]) x->devs[i].hc = x->hc; if (x->cm11.sts & dcbit[i]){ x->devs[i].hc = x->hc; x->devs[i].on = 1; } } } /* * X10 Protocol * PC <-> CM11 interface * req→ * ←sum * ack→ * ←rtr * * The interface can also request Ipoll, Itmr at any time. */ static int x10ringing(X10* x) { int fd; char buf[80]; fd = open(x->sdev, OREAD); if (fd < 0) return -1; memset(buf, 0, sizeof(buf)); read(fd, buf, sizeof(buf)); close(fd); buf[sizeof(buf)-1] = 0; return (strstr(buf, "ring") != nil); } // service an interface poll request (Ipoll) static void x10poll(X10* x) { uchar repl; uchar l; uchar buf[10]; uchar* bp; int i, n; Func* f; Addr* a; int max; max = 0; repl = Ppoll; memset(buf, 0, sizeof(buf)); memset(x->evs, 0, sizeof(x->evs)); if (debug) fprint(2, "poll "); do { write(x->fd, &repl, 1); i = read(x->fd, buf, 1); } while (i == 1 && buf[0] == Ipoll && max++ < 255); if (max >= 255){ if (debug) fprint(2, "loop\n"); syslog(0, logf, "x10 poll loop broken"); return; } //write(x->fd, &repl, 1); if (i != 1){ if (debug) fprint(2, "len read err: got %d bytes\n", i); syslog(0, logf, "len read err: got %d bytes\n", i); return; } l = buf[0]; if (l > 9){ syslog(0, logf, "big poll buffer %d (ignored)", l); if (debug) fprint(2, "big poll buffer %d\n", l); return; } if (debug) fprint(2, "%d bytes [", l); repl = Pack; for (i = 0; i < l; i++){ read(x->fd, buf+1+i, 1); if (debug) fprint(2, "%02x ", buf[1+i]); write(x->fd, &repl, 1); } if (debug) fprint(2, "]\n"); write(x->fd, &repl, 1); if (l > 0){ l--; // don't count mask bp = buf+2; n = 0; for (i = 0; i < l; i++){ if (buf[1]&(1<evs[n].type = Efunc; f = &x->evs[n].f; f->hc = (bp[i]>>4); f->fn = (bp[i]&0xf); if (f->fn != Fext) f->val = bp[++i]; else { f->data= bp[++i]; f->cmd = bp[++i]; } } else { x->evs[n].type = Eaddr; a = &x->evs[n].a; a->hc = (bp[i]>>4); a->dc = (bp[i]&0xf); } n++; } } if (debug) x10print(2, x); updatedevs(x); } static void ring(X10* x, int on) { uchar cmd; uchar rep; if (on) cmd = Pringe; else cmd = Pringd; write(x->fd, &cmd, 1); read(x->fd, &rep, 1); write(x->fd, &cmd, 1); read(x->fd, &rep, 1); } // service a time request (Itmr) // this also disables the ring signal. static void x10time(X10* x) { uchar req[7]; Tm* tm; if (debug) fprint(2, "time req "); syslog(0, logf, "power failed or controller reset"); tm = localtime(time(nil)); USED(tm); req[0] = Ptmr; #ifdef notdef req[1] = tm->sec; req[2] = (tm->hour%2)*60 + tm->min; req[3] = tm->hour/2; req[4] = tm->yday & 0x0ff; req[5] = ((tm->yday & 0x100)>>1)| (1 << (6-tm->wday)); #endif req[1] = 1; req[2] = 1; req[3] = 1; req[4] = 1; req[5] = 1; req[6] = ((x->hc << 4)|1); if (write(x->fd, req, sizeof(req)) != sizeof(req)) syslog(0, logf, "can't write time\n"); req[0] = -1; read(x->fd, req, 1); if (debug) fprint(2, "%x\n", req[0]); ring(x, 1); } static uchar mksum(uchar* msg, int l) { uint s; int i; s = 0; for (i = 0; i < l; i++){ s+=msg[i]; s&=0xff; } return s; } int x10req(X10* x, Msg* m) { int i; uchar msg[5]; uchar ack; uchar buf[20]; uchar sum; uchar msum; int l; int r; msg[0] = m->hdr; if (m->hdr != Xhdr){ l = 2; msg[1] = m->code; } else { l = 5; msg[1] = m->func; msg[2] = m->unit; msg[3] = m->data; msg[4] = m->cmd; } msum = mksum(msg, l); if (x->fd < 0){ syslog(0, logf, "x10req: no dev\n"); return -1; } for(i = 0; i < 10; i++){ if (debug) fprint(2, "msg [%ux %ux] sum %ux:",msg[0], msg[1], msum); if (write(x->fd, msg, l) != l){ if (debug) fprint(2, "write: %r\n"); syslog(0, logf, "x10req: write: %r\n"); continue; } sum = 0; if (read(x->fd, &sum, 1) < 1){ if (debug) fprint(2, "read: %r\n"); syslog(0, logf, "x10req: read: %r\n"); return -1; } if (sum != msum && sum == Ipoll){ if (debug) fprint(2, "poll!\n"); x10poll(x); continue; } if (sum != msum && sum == Itmr){ if (debug) fprint(2, "time!\n"); x10time(x); continue; } if (sum != msum){ if (debug) fprint(2, "bad checksum (%x %x); retrying\n", sum, msum); continue; } if (debug) fprint(2, "sent\n"); ack = Pack; for(r = 0; r < 5; r++){ write(x->fd, &ack, 1); l = read(x->fd, buf, sizeof(buf)); if (l == 1 && buf[0] == Irtr) return 0; else if (l == 1 && buf[0] == Ipoll){ if (debug) fprint(2, "poll on rtr!\n"); x10poll(x); return 0; } else if (l == 1 && buf[0] == Itmr){ if (debug) fprint(2, "poll on rtr!\n"); x10time(x); return 0; } else fprint(2, "req: not ready (%x); await\n", buf[0]); sleep(100); } } syslog(0, logf, "x10req: command failed\n"); return -1; } /* * PC requests */ int x10reqaddr(X10* x, char hc, char dc) { Msg m; x->hc = chrtohc(hc); dc = inttodc(dc); m.hdr = Hsync|Haddr|Hstd; m.code = ((x->hc&0xf)<<4) | (dc&0xf); return x10req(x, &m); } int x10reqfunc(X10* x, int fn, int dim) { Msg m; if (dim < 0) dim = 0; if (dim > 100) dim = 100; dim = dim*Dimmax/100; m.hdr = (dim<<3)|Hsync|Hfunc|Hstd; m.code = (x->hc<<4)|(fn&0xf); return x10req(x, &m); } int x10reqsts(X10* x) { uchar r; int i; uchar buf[14]; uchar* bp; int nest; nest = 0; again: nest++; r = Psts; write(x->fd, &r, 1); if (debug) fprint(2, "sts #%d [", nest); bp = buf; for (i = 0; i < 14; i++){ r = Pack; read(x->fd, bp, 1); write(x->fd, &r, 1); if (debug) fprint(2, " %x", *bp); if (buf[0] == Ipoll){ if (debug){ if (x10ringing(x)) fprint(2, "*ring*"); fprint(2, "!poll]\n"); } x10poll(x); goto again; } if (buf[0] == Itmr){ if (debug) fprint(2, "!time]\n"); x10time(x); goto again; } bp++; } if (debug) fprint(2, "]\n"); x->cm11.timer = (buf[0]<<8)|buf[1]; x->cm11.h = buf[4]*2+buf[3]/60; x->cm11.m = (buf[3]%60); x->cm11.s = buf[2]; x->cm11.yday = buf[5]|((buf[6]&0x80)<<1); x->cm11.wdays= buf[6]&0x7f; x->cm11.vers = buf[7]&0xf; x->cm11.hc = buf[7]>>4; x->cm11.devs = (buf[8]<<8)|buf[9]; x->cm11.sts = (buf[10]<<8)|buf[11]; x->cm11.dim = (buf[12]<<8)|buf[13]; if (debug) x10print(2, x); updatedevs(x); return 0; } /* * CM11 eeprom: * Macro offset (2 bytes) * Timer initiators up to the first 0xff * Macro initiators up to macro offset. * Macros * * It's downloaded in 3+Eblksz byte blocks, starting with * Peeprom and the eeprom address (3 + 16 bytes). * * This eeprom is meant to clear any macros * that come programmed from the factory or previous * use of the cm11 */ static uchar eeprom[] = { [0x00] 0x00, // macro offset: 0x0003 [0x01] 0x0, // [0x02] 0xff, // End of timer initiators }; static int x10puteeblock(X10* x, ushort a, uchar* block) { int i; uchar sum; uchar isum; uchar ack; if (debug) fprint(2, "eeprom block...\n"); sum = 0; for (i = 0; i < Eblksz + 3; i++){ if (debug){ if (i >= 3) fprint(2, "[%02x]", a+i-3); fprint(2, "\t%02x\n",block[i]); } write(x->fd, block+i, 1); if (i != 0) sum = (sum + block[i]) & 0xff; } isum = 0; read(x->fd, &isum, 1); if (isum != sum){ fprint(2, "puteeblock: bad checksum %x %x\n", isum, sum); return -1; } ack = Pack; write(x->fd, &ack, 1); read(x->fd, &ack, 1); if (ack != Irtr){ fprint(2, "puteeblock: not ready"); return -1; } return 0; } static void putshort(uchar* bp, ushort s) { bp[0] = (s&0xff); bp[1] = (s>>8); } static void x10puteeprom(X10* x, uchar *e, int l) { static uchar block[3+Eblksz]; ushort addr; int bl; addr = 0x0000; while(l > 0){ memset(block, 0, sizeof(block)); block[0] = Peeprom; putshort(block+1, addr); bl = l; if (bl > Eblksz) bl = Eblksz; memmove(block+3, e, bl); e += bl; l -= bl; if (x10puteeblock(x, addr, block) < 0){ syslog(0, logf, "eeprom clear failed\n"); return; } addr += Eblksz; } syslog(0, logf, "eeprom cleared\n"); } X10* x10open(char* dev, char hc) { int fd; char* cdev; char ctlstr[] = "b4800 c0 d0 e0 l8 m0 pn r1 s1 i0 ier=3"; X10* x; int i; x = malloc(sizeof(X10)); memset(x, 0, sizeof(X10)); x->hc = chrtohc(hc); x->dev = strdup(dev); x->sdev= smprint("%sstatus", dev); x->fd = -1; cdev = smprint("%sctl", dev); fd = open(cdev, OWRITE); if (fd >= 0){ write(fd, ctlstr, strlen(ctlstr)); close(fd); } free(cdev); x->fd = open(dev, ORDWR); if (x->fd < 0){ syslog(0, logf, "open %s: %r\n", dev); fprint(2, "open %s: %r\n", dev); sysfatal("nodev"); } x10time(x); x10puteeprom(x, eeprom, sizeof(eeprom)); sleep(1000); for (i = 0; i < 5; i++) if (x10reqsts(x) >= 0) break; ring(x, 1); return x; } void x10close(X10* x) { close(x->fd); free(x); } = &x->devs[i]; if (d->hc != 0){ fprint(fd, "%c:%d=", hctochr(d->hc), dctoint(d->dc)); fprint(fd, "[%s,%x] ", ons[d->on], d->dim); } } fprint(fd, "\n\tevents: "); for (i = 0; i < Nevs; i++){ switch(x->evs[i].type){ case Eaddr: a = &x->evs[i].a; fprint(fd, "%c:%d ", hcx10/x10.h 664 0 0 4232 10037160633 7735ustar00syssys typedef struct Msg Msg; typedef struct X10 X10; typedef struct Addr Addr; // device address typedef struct Dev Dev; // device /* * X10 messages */ enum { Dimmax = 22, // 100% dims Ndevs = 16, // Msg.hdr: dim:Hsync:Hfunc|Haddr:Hext|Hstd Hsync = 0x4, Hfunc = 0x2, Haddr = 0x0, Hext = 0x1, Hstd = 0x0, // Extended msg header Xhdr = Hsync|Hfunc|Hext, // Msg.code: :| // X10 Functions Falloff = 0x0, Flightson = 0x1, Fon = 0x2, Foff = 0x3, Fdim = 0x4, Fbright = 0x5, Flightsoff = 0x6, Fext = 0x7, Fhailreq = 0x8, Fhailack = 0x9, Fpsdim1 = 0xa, Fpsdim2 = 0xb, Fextxfer = 0xc, Fstson = 0xd, Fstsoff = 0xe, Fstsreq = 0xf, Fmax, }; struct Msg{ uchar hdr; union { // regular message struct { uchar code; }; // extended message struct { uchar func; uchar unit; uchar data; uchar cmd; }; }; }; enum { // PC requests/replies Pack = 0x00, // sum ok Ppoll = 0xc3, // Ok to upload Ptmr = 0x9b, // Timer download Psts = 0x8b, // CM11 sts request Peeprom = 0xfb, // starting to download eeprom Pringe = 0xeb, // enable the ring Pringd = 0xdb, // disable the ring // Interface requests/replies Irtr = 0x55, // ready to receive Itmr = 0xa5, // set timer (power fail) Ipoll = 0x5a, // poll to PC (upload events) // eeprom Eblksz = 16, // download block data size }; /* * X10 user interface */ struct Addr { uchar hc; // house code uchar dc; // device code, if != 0 }; struct Dev { Addr; int on; int dim; }; extern char* x10fnames[]; extern int debug; extern int interactive; extern char logf[]; X10* x10open(char* dev, char hc); void x10close(X10* x); void x10print(int fd, X10* x); int x10req(X10* x, Msg* m); int x10reqaddr(X10* x, char hc, char dc); int x10reqfunc(X10* x, int fn, int dim); int x10reqsts(X10* x); Dev* x10devs(X10* x); uchar dctoint(uchar c); uchar hctochr(uchar c); uchar inttodc(uchar dc); char* fntostr(uchar f); uchar chrtohc(uchar hc); /* * file system */ void fs(X10* p, char hc, char* conf, char* srv, char* mnt); void pfs(X10* p, char hc, char* conf); int runfunc(X10* x, int nargs, char** args); void cm11sprint(X10* x, char* buf, int len); x10/x10conf 664 0 0 50 10007740206 10424ustar00nemosyscm11 nemo planb 664 a1 nemo nemo 664 on