ref: 3efb5bbb4061056e523858b134c555949591efe2
dir: /appl/demo/camera/camera.b/
implement Camera; include "sys.m"; sys : Sys; include "daytime.m"; daytime: Daytime; include "styx.m"; styx: Styx; Rmsg, Tmsg: import styx; include "styxservers.m"; styxservers: Styxservers; Fid, Navigator, Navop: import styxservers; Styxserver, Eexists, Eperm, Ebadfid, Enotdir, Enotfound, Ebadarg: import styxservers; nametree: Nametree; Tree: import nametree; include "string.m"; str : String; include "draw.m"; include "arg.m"; Camera : module { init : fn (nil : ref Draw->Context, argv : list of string); }; cdp_get_product_info: con 16r01; cdp_get_image_specifications: con 16r02; cdp_get_camera_status: con 16r03; cdp_set_product_info: con 16r05; cdp_get_camera_capabilities: con 16r10; cdp_get_camera_state: con 16r11; cdp_set_camera_state: con 16r12; cdp_get_camera_defaults: con 16r13; cdp_set_camera_defaults: con 16r14; cdp_restore_camera_states: con 16r15; cdp_get_scene_analysis: con 16r18; cdp_get_power_mode: con 16r19; cdp_set_power_mode: con 16r1a; cdp_get_s1_mode: con 16r1d; cdp_set_s1_mode: con 16r1e; cdp_start_capture: con 16r30; cdp_get_file_list: con 16r40; cdp_get_new_file_list: con 16r41; cdp_get_file_data: con 16r42; cdp_erase_file: con 16r43; cdp_get_storage_status: con 16r44; cdp_set_file_data: con 16r47; cdp_get_file_tag: con 16r48; cdp_set_user_file_tag: con 16r49; cdp_get_clock: con 16r70; cdp_set_clock: con 16r71; cdp_get_error: con 16r78; cdp_get_interface_timeout: con 16r90; cdp_set_interface_timeout: con 16r91; cdp_header_len: con 12; T_DIR: con 0; T_CTL: con 1; T_ABILITIES: con 2; T_TIME: con 3; T_JPGDIR: con 4; T_JPG: con 5; T_STORAGE: con 6; T_POWER: con 7; T_THUMB: con 8; T_THUMBDIR: con 9; T_STATE: con 10; T_INTERFACE: con 11; MAXFILESIZE : con 5000000; TIMEOUT : con 4000; nextjpgqid, nexttmbqid, dirqid, Qctl, Qabl, Qstore: int; Qstate, Qtime, Qjpgdir, Qpwr, Qthumbdir, Qinterface : int; error_table := array [] of { "No Error", "Unimplemented", "Unsupported Version", "Application Timeout", "Internal Error", "Parameter Error", "File System Null", "File Not Found", "Data Section Not Found", "Invalid File Type", "Unknown Drive", "Drive Not Mounted", "System Busy", "Battery Low", }; bintro := array [] of { byte 16ra5, byte 16r5a, byte 16r00, byte 16rc8, byte 16r00, byte 16r02, byte 16rc9, }; bak := array [] of { byte 16r5a, # 2 byte header byte 16ra5, byte 16r55, # I/F Type byte 16r00, # Comm Flag byte 16r00, byte 16r00, byte 16r00, byte 16r00, byte 16r00, byte 16r00, byte 16r00, byte 16r00, byte 16r00, }; pwl := array[] of { byte 0, byte 0, }; pak := array [] of { byte 0, byte 0, }; SERIAL, USB, IRDA: con (1<<iota); BEACON, BEACONRESULT: con (1<<iota); Camera_adt: adt { port_type: int; port_num: int; command: int; mode: int; fd: ref Sys->FD; ctlfd: ref Sys->FD; cdp: array of byte; bufbytes: int; baud: int; dfs, hfs: int; # device and host frame sizes stat: int; # eia status file }; statopt := array[] of { "status", "stat", }; DL_QUANTA: con 20000; TOUT: con -1729; Partialtag: adt { offset, length, filesize: int; }; Cfile: adt { driveno: int; pathname: array of byte; dosname: array of byte; filelength: int; filestatus: int; thumblength: int; thumbqid: int; }; Fitem : adt { qid: Sys->Qid; cf: Cfile; }; C: Camera_adt; filelist: array of Fitem; reslength: int; currentstate := ""; wait : int; usecache := 0; connected : int; recon := 0; verbosity := 4; interfacepath := ""; interfacepaths : array of string; camname := ""; gpid : int; init(nil : ref Draw->Context, argv : list of string) { err: string; sys = load Sys Sys->PATH; gpid = sys->pctl(Sys->NEWPGRP, nil); str = load String String->PATH; daytime = load Daytime Daytime->PATH; styx = load Styx Styx->PATH; styx->init(); styxservers = load Styxservers Styxservers->PATH; styxservers->init(styx); nametree = load Nametree Nametree->PATH; nametree->init(); arg := load Arg Arg->PATH; filelist = array[200] of Fitem; C.port_num = 0; # XXXXX from argv C.port_type = SERIAL; # Serial only for now C.baud = 115200; C.dfs = C.hfs = 1023; C.cdp = array [DL_QUANTA] of byte; C.mode = BEACON; ex.pnum = -1; ex.offset = -1; cachelist = nil; nextjpgqid = getqid(1, T_JPG); nexttmbqid = getqid(1, T_THUMB); dirqid = getqid(1,T_JPGDIR); Qctl = getqid(Qroot,T_CTL); Qabl = getqid(Qroot,T_ABILITIES); Qstore = getqid(Qroot,T_STORAGE); Qtime = getqid(Qroot,T_TIME); Qstate = getqid(Qroot,T_STATE); Qpwr = getqid(Qroot,T_POWER); Qjpgdir = getqid(Qroot,T_JPGDIR); Qthumbdir = getqid(Qroot,T_THUMBDIR); Qinterface = getqid(Qroot,T_INTERFACE); camname = "Camera"; extrafilelist: list of string = nil; arg->init(argv); arg->setusage("camera [-b baud] [-F framesize] [-f extrafiles] [-p port] [-n name] [-v verbosity]"); while ((opt := arg->opt()) != 0) { case opt { 'n' => camname = arg->earg(); 'v' => verbosity = int arg->earg(); 'F' => C.dfs = C.hfs = int arg->earg(); 'b' => C.baud = int arg->earg(); 'p' => C.port_num = int arg->earg(); 'c' => usecache = 1; 'f' => extrafilelist = arg->earg() :: extrafilelist; * => arg->usage(); } } arg = nil; interfacepaths = array[len extrafilelist] of string; # sys->print("INTERFACEPATHS: %d\n", len extrafilelist); for (i := 0; i < len interfacepaths; i++) { interfacepaths[i] = hd extrafilelist; # sys->print("INTERFACEPATH %d: %s\n", i, hd extrafilelist); extrafilelist = tl extrafilelist; } print(sys->sprint("Trying to connect to eia%d...\n",C.port_num),2); case C.port_type { SERIAL => # open port and return fd (C.fd, C.ctlfd, err) = serialport(C.port_num); if (C.fd == nil) { print("Could not open serial port\n",1); exit; } USB => ; IRDA => ; * => ; } if (connect() != 0) {; print("Connection failed\n",1); exit; } recon = 0; print("Connected!\n",2); set_interface_timeout(); set_camera_properties(); get_file_list(); connected = 1; ignoreabls = nil; get_camera_capabilities(); sync := chan of int; spawn serveloop(sys->fildes(0), sync); <-sync; } set_camera_properties() { for (i := 0; i < len set_camera_props; i++) set_camera_state(set_camera_props[i].t0,set_camera_props[i].t1); } set_camera_props := array[] of { ("mcap", 0), ("acpd", 65535), ("actc", 65535), ("btpd", 65535), ("bttc", 65535), ("flty", 1246774599), ("ssvl", 0), }; argval(argv: list of string, arg: string): string { if (arg == "") return ""; if (arg[0] != '-') arg = "-" + arg; while (argv != nil) { if (hd argv == arg && tl argv != nil && (hd tl argv)[0] != '-') return tonext(tl argv); argv = tl argv; } return ""; } tonext(los: list of string): string { s := ""; while (los != nil) { if ((hd los)[0] != '-') s += " " + hd los; else break; los = tl los; } if (s != "") s = s[1:]; return s; } int2hex(i:int): int { i2 := 0; s := string i; for (k := 0; k < len s; k++) i2 = (i2 * 16) + int s[k:k+1]; return i2; } connect(): int { connected = 0; datain := chan of array of byte; pchan := chan of int; tick := chan of int; reset(C.ctlfd); spawn timer2(tick,TIMEOUT * 2); tpid := <-tick; spawn beacon_intro(datain, pchan, C.fd); pid := <- pchan; # beacon phase Beacon: for (;;) { alt { buf := <- datain => # got some data case C.mode { BEACON => if (beacon_ok(buf)) { print("Got beacon\n",3); beacon_ack(C); spawn beacon_result(datain, pchan, C.fd); pid = <-pchan; C.mode = BEACONRESULT; break; } else { print("resetting\n",3); reset(C.ctlfd); } BEACONRESULT => kill(tpid); print("Checking beacon result\n",3); if (beacon_comp(buf, C) == 0) { return 0; break Beacon; } return -1; } <- tick => kill(pid); return -1; # failure } } } CTL, ABILITIES, DATA, JPG, PIC, TIME, CONV: con iota; NAME, FSIZE, PHOTO, THUMB: con iota; Qdir : con iota; contains(s: string, test: string): int { num :=0; if (len test > len s) return 0; for (i := 0; i < (1 + (len s) - (len test)); i++) { if (test == s[i:i+len test]) num++; } return num; } abilitiesfilter := array[] of { "Time Format", "Date Format", "File Type", "Video", "Media", "Sound", "Volume", "Reset Camera", "Slide", "Timelapse", "Burst", "Power", "Sleep", }; ignoreabls : list of string; defattr : list of (string, int); defaultattr, currentattr: array of (string, int); filterabls(pname, desc: string): int { for (i := 0; i < len abilitiesfilter; i++) { if (contains(desc, abilitiesfilter[i])) { ignoreabls = pname :: ignoreabls; return 1; } } return 0; } mountit(dfd, mountfd: ref sys->FD, sync: chan of int) { sys->pctl(sys->NEWNS | sys->NEWFD, 2 :: dfd.fd :: mountfd.fd :: nil); sync <-= 1; mountfd = sys->fildes(mountfd.fd); dfd = sys->fildes(dfd.fd); if (sys->mount(mountfd, nil, "/", sys->MREPL | sys->MCREATE, nil) == -1) { sys->fprint(sys->fildes(2), "cannot mount\n"); spawn exporterror(dfd, sys->sprint("%r")); } else { sync = chan of int; spawn exportpath(sync, dfd); <-sync; } } exporterror(dfd: ref Sys->FD, error: string) { tmsg := Tmsg.read(dfd, 0); if (tmsg == nil) { sys->fprint(sys->fildes(2), "exporterror() EOF\n"); exit; } pick t := tmsg { Readerror => sys->fprint(sys->fildes(2), "exporterror() Readerror\n"); * => reply: ref Rmsg = ref Rmsg.Error(tmsg.tag, error); data := reply.pack(); sys->write(dfd, data, len data); } } exportpath(sync: chan of int, dfd: ref sys->FD) { sync <-= 1; sys->export(dfd, "/", Sys->EXPWAIT); } Qroot : con int iota; ss : ref Styxserver; uid: string; exitfid := -1; getuid() { buf := array [100] of byte; fd := sys->open("/dev/user", Sys->OREAD); uidlen := sys->read(fd, buf, len buf); uid = string buf[0: uidlen]; } dir(name: string, perm: int, length: int, qid: int): Sys->Dir { d := sys->zerodir; d.name = name; d.uid = uid; d.gid = uid; d.qid.path = big qid; if (perm & Sys->DMDIR) d.qid.qtype = Sys->QTDIR; else { d.qid.qtype = Sys->QTFILE; d.length = big length; } d.mode = perm; d.atime = d.mtime = daytime->now(); return d; } User: adt { attachfid: int; attr: array of (string, int); }; users : array of User; getuser(fid: int): int { for (i := 0; i < len users; i++) if (users[i].attachfid == fid) return i; return -1; } getattr(pname: string): int { for (i := 0; i < len defaultattr; i++) if (defaultattr[i].t0 == pname) return i; return -1; } serveloop(fd : ref sys->FD, sync: chan of int) { tchan: chan of ref Tmsg; srv: ref Styxserver; echan := chan of string; users = array[20] of { * => User (-1, nil) }; sys->pctl(Sys->FORKNS, nil); sync <-= 1; print("serveloop\n",5); getuid(); (tree, treeop) := nametree->start(); tree.create(big Qroot, dir(".",8r555 | sys->DMDIR,0,Qroot)); tree.create(big Qroot, dir("ctl",8r222,0,Qctl)); tree.create(big Qroot, dir("abilities",8r444,0,Qabl)); tree.create(big Qroot, dir("storage",8r444,0,Qstore)); tree.create(big Qroot, dir("power",8r444,0,Qpwr)); tree.create(big Qroot, dir("date",8r666,0,Qtime)); tree.create(big Qroot, dir("state",8r666,0,Qstate)); tree.create(big Qroot, dir("jpg",8r777 | sys->DMDIR,0,Qjpgdir)); tree.create(big Qroot, dir("thumb",8r777 | sys->DMDIR,0,Qthumbdir)); for (j := 0; j < len interfacepaths; j++) { (n, idir) := sys->stat(interfacepaths[j]); if (n != -1) { idir.qid.path = big Qinterface; # intdir := dir("",8r777,0,Qinterface); # intdir.name = idir.name; # intdir.length = idir.length; # intdir.atime = idir.atime; # intdir.mtime = idir.mtime; tree.create(big Qroot, idir); Qinterface += 1<<4; } } tmsgqueue := Tmsgqueue.new(50); (tchan, srv) = Styxserver.new(fd,Navigator.new(treeop), big Qroot); fd = nil; gm, lastgm: ref Tmsg; gm = nil; oldfiles = nil; updatetree(tree); print("serveloop loop\n",5); alivechan := chan of int; spawn keepalive(alivechan); alivepid := <-alivechan; retryit := 0; notries := 0; readfid := -1; serveloop: for (;;) { wait = daytime->now(); if (notries > 5) retryit = 0; if (retryit) { gm = lastgm; notries++; } else { notries = 0; loop: for (;;) { gm = tmsgqueue.pop(readfid); if (gm != nil) break; alt { gm = <-tchan => break loop; c := <-alivechan => for (;;) { s := get_clock(); wait = daytime->now(); # print(sys->sprint("got alivechan: %s",s),1); if (recon) { killchan := chan of int; spawn noresponse(tchan,srv,killchan); reconnect(-1); killchan <-= 1; } else break; } } } } lastgm = gm; retryit = 0; if (gm == nil) { sys->print("exiting!\n"); break serveloop; # nil => EOF => last mount was unmounted } print(sys->sprint("Got new GM %s tag: %d\n", gm.text(), gm.tag),4); # print(sys->sprint("Got new GM %s tag: %d\n", gm.text(), gm.tag),2); if (!connected) { srv.reply(ref Rmsg.Error(gm.tag, "Could not connect to camera")); print("Error: not connected to camera\n",1); } else pick m := gm { Readerror => print(sys->sprint( "camera: fatal read error: %s\n", m.error),1); break serveloop; Attach => nu := getuser(-1); if (nu == -1) { srv.reply(ref Rmsg.Error(m.tag, "Camera in use")); break; } m.uname = string nu; srv.default(m); myattr := array[len currentattr] of (string, int); for (i := 0; i < len myattr; i++) myattr[i] = currentattr[i]; users[nu] = User (m.fid, myattr); print("adding user "+string nu, 2); Clunk => nu := getuser(m.fid); if (nu != -1) { users[nu] = User (-1, nil); print("removing user "+string nu, 2); } if (m.fid == readfid) { # sys->print("readfid clunk: %d\n",readfid); readfid = -1; } srv.default(gm); Remove => print("Removing file\n",3); f := srv.getfid(m.fid); if (f == nil) { print("Remove: Invalid fid\n",1); srv.reply(ref Rmsg.Error(m.tag, Ebadfid)); break; } ftype := gettype(int f.path); if (ftype != T_JPG) { srv.reply(ref Rmsg.Error(m.tag, "Cannot remove file")); break; } else { for (i := 0; i < reslength; i++) { if (f.path == filelist[i].qid.path) { print("removing filelist\n",5); if (erase_file(filelist[i].cf) != 0) { if (!recon) srv.reply(ref Rmsg.Error(m.tag, "Cannot remove file")); break; } srv.delfid(f); if (get_file_list() != 0) srv.reply(ref Rmsg.Error(m.tag, "Cannot read files")); else { updatetree(tree); srv.reply(ref Rmsg.Remove(m.tag)); } break; } } } Read => print("got read request in serveloop\n",6); (f,e) := srv.canread(m); if(f == nil) break; if (f.qtype & Sys->QTDIR) { print("reading directory\n",5); srv.read(m); break; } data : array of byte; case gettype(int f.path) { T_INTERFACE => (dir, intdata) := readinterface(int f.path, m.offset, m.count); if (dir != nil && m.offset == big 0) { dir.qid.path = f.path; tree.wstat(f.path, *dir); } srv.reply(ref Rmsg.Read(m.tag, intdata)); T_POWER => print("reading power mode...\n",3); data = array of byte get_power_mode(); if (!recon) srv.reply(styxservers->readbytes(m, data)); T_TIME => print("reading clock...\n",3); data = array of byte get_clock(); if (!recon) srv.reply(styxservers->readbytes(m, data)); T_ABILITIES => data = array of byte get_camera_capabilities(); if (!recon) srv.reply(styxservers->readbytes(m, data)); T_JPG => # sys->print("Read Jpg: user %d\n", int f.uname); if (readfid != -1 && readfid != m.fid) { tmsgqueue.push(m); # sys->print("in use!\n"); # srv.reply(ref Rmsg.Error(m.tag, "Camera in use, please wait")); break; } readfid = m.fid; data = photoread2(f.path, m,tree,0); if (!recon) srv.reply(ref Rmsg.Read(m.tag, data)); T_THUMB => if (readfid != -1 && readfid != m.fid) { # srv.reply(ref Rmsg.Error(m.tag, "Camera in use, please wait")); tmsgqueue.push(m); break; } readfid = m.fid; # sys->print("Read Thumb: user %d\n", int f.uname); data = photoread2(f.path, m,tree,1); if (!recon) srv.reply(ref Rmsg.Read(m.tag, data)); T_STATE => if (currentstate == "") srv.reply(ref Rmsg.Error(m.tag, "No state requested")); else { data = array of byte get_camera_state(currentstate,int m.offset); if (!recon) srv.reply(ref Rmsg.Read(m.tag, data)); } T_STORAGE => data = array of byte get_storage_status(); if (!recon) { if (len data == 0) srv.reply(ref Rmsg.Error(m.tag, "Could not read storage status")); else srv.reply(styxservers->readbytes(m, data)); } * => srv.reply(ref Rmsg.Error(m.tag, "Cannot read file")); } # if (readfid != -1) # sys->print("readfid set: %d\n",readfid); Write => print("got write request in serveloop\n",6); (f,e) := srv.canwrite(m); if(f == nil) { print("cannot write to file\n",1); break; } wtype := gettype(int f.path); (n, s) := sys->tokenize(string m.data, " \t\n"); if (wtype == T_TIME) { if (set_clock(string m.data) != 0) srv.reply(ref Rmsg.Error(m.tag, "Invalid date time format\n" + "Usage: MM/DD/YY HH/MM/SS\n")); else srv.reply(ref Rmsg.Write(m.tag, len m.data)); } else if (wtype == T_CTL) { err := ""; case hd s { "refresh" => # for (i := 0; i < reslength; i++) { # tree.remove(filelist[i].qid.path); # tree.remove(big filelist[i].cf.thumbqid); # } if (get_file_list() != 0) err = "Error: Could not read from camera"; else updatetree(tree); # for (i = 0; i < reslength; i++) # buildfilelist(tree, i); "snap" => nu := int f.uname; print(sys->sprint("User %d taking photo\n",nu),2); for (i := 0; i < len currentattr; i++) { # sys->print("user: %s=%d current: %s=%d\n", # users[nu].attr[i].t0,users[nu].attr[i].t1, # currentattr[i].t0,currentattr[i].t1); if (users[nu].attr[i].t1 != currentattr[i].t1) { set_camera_state(users[nu].attr[i].t0, users[nu].attr[i].t1); sys->sleep(100); } } e1 := capture(); if (e1 == -1) { err = "Cannot communicate with camera"; break; } if (e1 != 0) { err = "Error: "+error_table[e1]; break; } sys->sleep(4000); if (get_file_list() != 0) { err = "Error: Could not read from camera"; break; } updatetree(tree); * => if (n == 2) { # assume that it is a (string, int) tuple na := getattr(hd s); if (na == -1) err = "Invalid command name '"+hd s+"'"; else { e1 := set_camera_state(hd s, int hd tl s); if (e1 != nil) err = e; else users[int f.uname].attr[na].t1 = int hd tl s; } } } if (!recon) { if (err != "") { print(err+"\n",1); srv.reply(ref Rmsg.Error(m.tag, err)); } else srv.reply(ref Rmsg.Write(m.tag, len m.data)); } } else if (wtype == T_STATE) { if (s != nil) currentstate = hd s; srv.reply(ref Rmsg.Write(m.tag, len m.data)); } else srv.reply(ref Rmsg.Error(m.tag, "Could not write to file")); Wstat => print("Got Wstat command in serveloop\n",6); srv.reply(ref Rmsg.Error(m.tag, "Wstat failed")); * => srv.default(gm); } if (recon) { retryit = 1; ok := reconnect(4); if (!ok) { srv.reply(ref Rmsg.Error(gm.tag, "Could not connect to camera")); killchan := chan of int; spawn noresponse(tchan,srv,killchan); reconnect(-1); killchan <-= 1; retryit = 0; sys->sleep(100); } } } tree.quit(); kill(alivepid); killg(gpid); } Tmsgqueue: adt { start, end, length: int; a : array of ref Tmsg.Read; new: fn (n: int): ref Tmsgqueue; push: fn (t: self ref Tmsgqueue, t: ref Tmsg.Read): int; pop: fn (t: self ref Tmsgqueue, readfid: int): ref Tmsg.Read; }; Tmsgqueue.new(n: int): ref Tmsgqueue { t : Tmsgqueue; t.start = 0; t.end = 0; t.length = 0; t.a = array[n] of ref Tmsg.Read; return ref t; } Tmsgqueue.push(t: self ref Tmsgqueue,newt: ref Tmsg.Read): int { if (t.length >= len t.a) return -1; t.a[t.end] = newt; t.end++; if (t.end >= len t.a) t.end = 0; t.length++; return 0; } Tmsgqueue.pop(t: self ref Tmsgqueue, readfid: int): ref Tmsg.Read { if (t.length == 0) return nil; m := t.a[t.start]; if (readfid != -1 && readfid != m.fid) return nil; t.start++; if (t.start >= len t.a) t.start = 0; t.length--; return m; } noresponse(tchan: chan of ref Tmsg, srv: ref Styxservers->Styxserver, killchan : chan of int) { for (;;) alt { k := <- killchan => return; gm := <- tchan => print("noresponse: Returning Error\n",1); srv.reply(ref Rmsg.Error(gm.tag, "Could not connect to camera")); sys->sleep(100); } } photoread2(qid: big, m: ref Tmsg.Read, tree: ref Nametree->Tree, isthumb: int): array of byte { photonum := -1; data : array of byte; # sys->print("photoread: qid: %d resl: %d\n",int qid,reslength); for (i := 0; i < reslength; i++) { # sys->print("%d: %s %d\n",i, sconv(filelist[i].cf.dosname),int filelist[i].qid.path); if (!isthumb && qid == filelist[i].qid.path) { photonum = i; break; } else if (isthumb && int qid == filelist[i].cf.thumbqid) { photonum = i; break; } } if (photonum >= reslength || photonum < 0) { print(sys->sprint( "error: photonum = %d (reslength = %d)\n", photonum,reslength),1); return nil; } offset := int m.offset; dosname := filelist[photonum].cf.dosname; filelen := filelist[photonum].cf.filelength; for (k := 0; k < 5; k++) { if (filelen == 0) { get_file_size(photonum); print(sys->sprint("\tFilelen: %d => ",filelen),5); filelen = filelist[photonum].cf.filelength; print(sys->sprint("%d\n",filelen),5); tree.wstat(qid, dir(str->tolower(sconv(filelist[photonum].cf.dosname)), 8r444, filelen, int qid)); sys->sleep(1000); } else break; } if (filelen == 0 && !isthumb) return nil; # doesn't matter if filesize is wrong for thumbnail if (isthumb) filelen = filelist[photonum].cf.thumblength; if (usecache && cachesize(dosname, isthumb) == filelen) { # print(sys->sprint("Is cached!\n"); n := m.count; filesize := cachesize(dosname,isthumb); if (offset >= filesize) return nil; if (offset+m.count >= filesize) n = filesize - offset; data = array[n] of byte; fd := sys->open(cachename(dosname,isthumb), sys->OREAD); if (fd == nil) cachedel(dosname,isthumb); else { sys->seek(fd,m.offset,sys->SEEKSTART); sys->read(fd,data,len data); fd = nil; return data; } } # print(sys->sprint("Is NOT cached!\n"); if (photonum == ex.pnum && offset == ex.offset && ex.isthumb == isthumb) data = ex.data; else if (isthumb) data = getthumb(photonum, offset, m.count); else if (!isthumb) data = getpicture2(photonum, offset, m.count); if (len data > m.count) { ex.pnum = photonum; ex.offset = offset + m.count; ex.data = array[len data - m.count] of byte; ex.data[0:] = data[m.count:len data]; ex.isthumb = isthumb; data = data[:m.count]; } if (usecache) { fd : ref sys->FD; cname := cachename(dosname,isthumb); if (offset == 0) fd = sys->create(cname,sys->OWRITE,8r666); else { fd = sys->open(cname,sys->OWRITE); if (fd != nil) sys->seek(fd,big 0,sys->SEEKEND); } if (fd != nil) { i = sys->write(fd,data,len data); fd = nil; } (n, dir) := sys->stat(cname); if (n == 0) { cacheadd(dosname,isthumb,int dir.length); } } return data; } cachelist : list of (string, int, int); cacheprint() { tmp := cachelist; print("cache:\n",3); while (tmp != nil) { (dn,i1,i2) := hd tmp; print(sys->sprint("\t%s %d %d\n",dn,i1,i2),3); tmp = tl tmp; } } cacheclean() { tmp : list of (string, int,int); tmp = nil; while (cachelist != nil) { (dosnm,it,fl) := hd cachelist; for (i := 0; i < reslength; i++) { filelen := filelist[i].cf.filelength; if (it) filelen = filelist[i].cf.thumblength; if (sconv(filelist[i].cf.dosname) == dosnm && filelen == fl) { tmp = (dosnm,it,fl) :: tmp; break; } } cachelist = tl cachelist; } cachelist = tmp; } cacheadd(dosname1: array of byte, isthumb, filelen: int) { dosname := sconv(dosname1); tmp : list of (string, int,int); tmp = nil; updated := 0; while (cachelist != nil) { (dosnm,it,fl) := hd cachelist; if (dosname == dosnm && it == isthumb) { updated = 1; tmp = (dosnm,it,filelen) :: tmp; } else tmp = (dosnm,it,fl) :: tmp; cachelist = tl cachelist; } if (updated == 0) tmp = (dosname,isthumb,filelen) :: tmp; cachelist = tmp; } cachedel(dosname1: array of byte, isthumb: int) { dosname := sconv(dosname1); tmp : list of (string, int,int); tmp = nil; while (cachelist != nil) { (dosnm,it,filelen) := hd cachelist; if (dosname != dosnm || it != isthumb) tmp = (dosnm,it,filelen) :: tmp; cachelist = tl cachelist; } cachelist = tmp; } cachesize(dosname1: array of byte, isthumb: int): int { dosname := sconv(dosname1); tmp := cachelist; while (tmp != nil) { (dosnm,it,filelen) := hd tmp; if (dosname == dosnm && isthumb == it) return filelen; tmp = tl tmp; } return -1; } cachename(dosname: array of byte, isthumb: int): string { name := "/tmp/" + str->tolower(sconv(dosname)); if (isthumb) name = jpg2bit(name); name[len name - 1] = '~'; return name; } poll_and_wait(): int { print("poll and wait\n",7); write_n(C.fd, pwl, len pwl); # sys->sleep(100); if (read_n_to(C.fd, pak, len pak,TIMEOUT) < 0) { print("poll_and_wait: unexpected read failure, exiting...\n",1); return -1; } return 0; } send_packet(): int { # computing packet size to_write := C.bufbytes; # send the first packet pwl[0] = byte ((1<<5)|(1<<4)|(1<<3)|(1<<2)|(to_write>>8)); pwl[1] = byte (to_write&16rff); if (poll_and_wait() != 0) return -1; # pak[1] == byte 2; ? pak[1] = byte 2; wrote_here := write_n(C.fd, C.cdp, to_write); if (wrote_here != to_write) return -1; return 0; } send_message(): int { v:= 0; rc := chan of int; tc := chan of int; spawn timer2(tc,6000); tpid := <- tc; spawn write_message(rc); rpid := <- rc; try := 0; alt { <- tc => kill(rpid); print("error: write timeout\n",1); v = -2; break; v = <- rc => kill(tpid); break; } return v; } write_message(rc: chan of int) { print("writing msg...\n",6); rc <- = sys->pctl(0, nil); if (send_packet() != 0) { rc <-= -1; return; } pwl[0] = byte 0; pwl[1] = byte 0; wrote_here := write_n(C.fd, pwl, 2); if (wrote_here != 2) { rc <-= -1; return; } rc <-= 0; print("written\n",6); } extra: adt { pnum: int; offset: int; length: int; data: array of byte; isthumb: int; }; ex : extra; getthumb(photonum, offset, maxlength: int): array of byte { if (offset != 0) return nil; print("getting thumbnail\n",3); thumbdata: array of byte; err, h, w, ttype: int; file := filelist[photonum].cf; filesize := 13020; if (offset > 0) { filesize = file.thumblength; if (offset >= filesize) return nil; } for(;;){ print(sys->sprint("Filesize: %d offset: %d\n",filesize, offset),5); if (offset + maxlength > filesize) maxlength = filesize - offset; l := maxlength; C.command = cdp_get_file_data; C.bufbytes = build_cdp_header(C.cdp, 68); off := cdp_header_len; off = set_int(C.cdp[off:], file.driveno, off); off = set_fstring(C.cdp[off:], file.pathname, off); off = set_dosname(C.cdp[off:], file.dosname, off); off = set_int(C.cdp[off:], 1, off); off = set_int(C.cdp[off:], offset, off); off = set_int(C.cdp[off:], l, off); off = set_int(C.cdp[off:], filesize, off); print(sys->sprint( "getthumbdata %d %d %d\n", offset, maxlength, filesize),5); send_message(); # sys->sleep(2000); if ((err = receive_message()) != 0) { print(sys->sprint("Error %d\n", err),1); return nil; } off = cdp_header_len; print(sys->sprint( "bufbytes = %d\n", C.bufbytes),5); tmpoffset: int; (tmpoffset, off) = get_int(C.cdp[off:], off); (l, off) = get_int(C.cdp[off:], off); (filesize, off) = get_int(C.cdp[off:], off); print(sys->sprint( "getthumbdata returning %d %d %d\n", offset, l, filesize),5); if (offset == 0) { (filesize, off) = get_int(C.cdp[off:off+4], off); (h, off) = get_int(C.cdp[off:off+4], off); (w, off) = get_int(C.cdp[off:off+4], off); (ttype, off) = get_int(C.cdp[off:off+4], off); filelist[photonum].cf.thumblength = filesize; thumbdata = array[filesize] of byte; print(sys->sprint("Thumb (%d,%d) size: %d type: %d\n",w,h,filesize,ttype),5); } if (offset + l > filesize) l = filesize - offset; print(sys->sprint( "Making array of size: %d\n", l),5); thumbdata[offset:] = C.cdp[off:off+l]; offset += l; if (offset >= filesize) break; } return thumb2bit(thumbdata,w,h); } getpicture2(photonum, offset, maxlength: int): array of byte { file := filelist[photonum].cf; filesize := int file.filelength; print("getting image\n",3); print(sys->sprint("Filesize: %d offset: %d\n",filesize, offset),5); if (offset >= filesize) return nil; if (offset + maxlength > filesize) maxlength = filesize - offset; l := maxlength; C.command = cdp_get_file_data; C.bufbytes = build_cdp_header(C.cdp, 68); off := cdp_header_len; off = set_int(C.cdp[off:], file.driveno, off); off = set_fstring(C.cdp[off:], file.pathname, off); off = set_dosname(C.cdp[off:], file.dosname, off); off = set_int(C.cdp[off:], 0, off); off = set_int(C.cdp[off:], offset, off); off = set_int(C.cdp[off:], l, off); off = set_int(C.cdp[off:], filesize, off); print(sys->sprint( "getfiledata %d %d %d\n", offset, maxlength, filesize),5); send_message(); if ((err := receive_message()) != 0) { print(sys->sprint("Error %d\n", err),1); return nil; } off = cdp_header_len; print(sys->sprint( "bufbytes = %d\n", C.bufbytes),5); (offset, off) = get_int(C.cdp[off:], off); (l, off) = get_int(C.cdp[off:], off); (filesize, off) = get_int(C.cdp[off:], off); print(sys->sprint( "getfiledata returning %d %d %d\n", offset, maxlength, filesize),5); filedata := array[l] of byte; filedata[0:] = C.cdp[off:off+l]; return filedata; } erase_file(file: Cfile): int { C.command = cdp_erase_file; C.bufbytes = build_cdp_header(C.cdp, 52); off := cdp_header_len; off = set_int(C.cdp[off:], file.driveno, off); off = set_fstring(C.cdp[off:], file.pathname, off); off = set_dosname(C.cdp[off:], file.dosname, off); send_message(); # sys->sleep(1000); if (receive_message() != 0) return -1; return 0; } set_power_mode(): int { C.command = cdp_set_power_mode; C.bufbytes = build_cdp_header(C.cdp, 0); return (send_message()); } get_storage_status(): string { s := ""; C.command = cdp_get_storage_status; C.bufbytes = build_cdp_header(C.cdp, 0); send_message(); # sys->sleep(2000); if (receive_message() != 0) return ""; off := cdp_header_len; taken, available, raw : int; (taken, off) = get_int(C.cdp[off:], off); (available, off) = get_int(C.cdp[off:], off); (raw, off) = get_int(C.cdp[off:], off); s += sys->sprint("Picture Memory\n\tused:\t%d\n\tfree:\t%d",taken,available); if (raw == -1) s += "\n"; else s += sys->sprint(" (compressed)\n\t\t%d (raw)\n",raw); return s; } get_power_mode(): string { mode: int; C.command = cdp_get_power_mode; C.bufbytes = build_cdp_header(C.cdp, 0); send_message(); # sys->sleep(2000); if (receive_message() != 0) return "Could not read power mode"; off := cdp_header_len; (mode, off) = get_int(C.cdp[off:], off); return sys->sprint("Power Mode = %d\n", mode); } set_clock_data(s:string): int { err := 0; if (s == "") { tm := daytime->local(daytime->now()); off := cdp_header_len; C.cdp[cdp_header_len+0] = byte 0; C.cdp[cdp_header_len+1] = byte int2hex(tm.mon+1); C.cdp[cdp_header_len+2] = byte int2hex(tm.mday); C.cdp[cdp_header_len+3] = byte int2hex(tm.year); C.cdp[cdp_header_len+4] = byte 0; C.cdp[cdp_header_len+5] = byte int2hex(tm.hour); C.cdp[cdp_header_len+6] = byte int2hex(tm.min); C.cdp[cdp_header_len+7] = byte int2hex(tm.sec); } else { (n,datetime) := sys->tokenize(s," "); if (n != 2) return 1; off := 0; for (i := 0; i < 2; i++) { (n2,data) := sys->tokenize(hd datetime, "./:"); if (n2 != 3) return 1; off++; for (i2 := 0; i2 < 3; i2++) { C.cdp[cdp_header_len+off] = byte int2hex(int hd data); off++; data = tl data; } datetime = tl datetime; } } return 0; } set_clock(s:string): int { C.command = cdp_set_clock; C.bufbytes = build_cdp_header(C.cdp, 8); if (set_clock_data(s)) return 1; send_message(); if (receive_message() != 0) return 1; return 0; } addzeros(s: string): string { s[len s] = ' '; rs := ""; start := 0; isnum := 0; for (i := 0; i < len s; i++) { if (s[i] < '0' || s[i] > '9') { if (isnum && i - start < 2) rs[len rs] = '0'; rs += s[start:i+1]; start = i+1; isnum = 0; } else isnum = 1; } i = len rs - 1; while (i >= 0 && rs[i] == ' ') i--; return rs[:i+1]; } get_clock(): string { C.command = cdp_get_clock; C.bufbytes = build_cdp_header(C.cdp, 0); send_message(); if (receive_message() != 0) return "Could not read clock\n"; s := sys->sprint("%x/%x/%x %x:%x:%x", int C.cdp[13],int C.cdp[14], int C.cdp[15], int C.cdp[17], int C.cdp[18], int C.cdp[19]); return "date is "+addzeros(s)+"\n"; } get_file_list(): int { getoldfiledata(); print("getting file list\n",3); C.command = cdp_get_file_list; C.bufbytes = build_cdp_header(C.cdp, 56); setfiledata(); send_message(); if (receive_message() != 0) return -1; display_filelist(); return 0; } setfiledata() { off := cdp_header_len; off = set_int(C.cdp[off:], 1, off); # ascending order off = set_int(C.cdp[off:], 1, off); # drive a: internal RAM disk off = set_fstring(C.cdp[off:], array of byte "", off); # set pathname to null off = set_dosname(C.cdp[off:], array of byte "", off); # set Dos filename to null } get_file_size(i: int): int { C.command = cdp_get_file_list; C.bufbytes = build_cdp_header(C.cdp, 56); setfiledata2(i); send_message(); if (receive_message() != 0) return -1; display_filelist(); return 0; } setfiledata2(i: int) { off := cdp_header_len; off = set_int(C.cdp[off:], 1, off); # ascending order off = set_int(C.cdp[off:], 1, off); # drive a: internal RAM disk off = set_fstring(C.cdp[off:], filelist[i].cf.pathname, off); # set pathname off = set_dosname(C.cdp[off:], filelist[i].cf.dosname, off); # set Dos filename } set_interface_timeout() { print("Setting Interface timeout\n",3); C.command = cdp_set_interface_timeout; C.bufbytes = build_cdp_header(C.cdp, 8); off := cdp_header_len; off = set_int(C.cdp[off:], 100, off); off = set_int(C.cdp[off:], 5, off); send_message(); # sys->sleep(1000); receive_message(); } display_filelist(): string { off, i: int; off = cdp_header_len; (reslength, off) = get_int(C.cdp[off:], off); s := sys->sprint("Number of entries: %d\n", reslength); for (i = 0; i < reslength; i++) { (filelist[i].cf.driveno, off) = get_int(C.cdp[off:], off); (filelist[i].cf.pathname, off) = get_fstring(C.cdp[off:], off); (filelist[i].cf.dosname, off) = get_dosname(C.cdp[off:], off); (filelist[i].cf.filelength, off) = get_int(C.cdp[off:], off); (filelist[i].cf.filestatus, off) = get_int(C.cdp[off:], off); if (filelist[i].cf.filelength < 0 || filelist[i].cf.filelength > MAXFILESIZE) filelist[i].cf.filelength = 0; s += sys->sprint("\t%d, %s, %s, %d\n", filelist[i].cf.driveno, string filelist[i].cf.pathname, string filelist[i].cf.dosname, filelist[i].cf.filelength); } print(s,5); if (usecache) cacheclean(); return s; } get_camera_capabilities(): string { print("Get capabilities\n",3); C.command = cdp_get_camera_capabilities; C.bufbytes = build_cdp_header(C.cdp, 0); send_message(); # sys->sleep(500); if (receive_message() != -1) return capabilities(); print("Error recieving abilities message\n",1); return ""; } Capability: adt { pname: string; d: string; pick { List => t: list of (string, int); Range => min, max, default, current: int; } }; caplist: list of ref Capability; print_camera_capabilities(): string { rs := ""; # p : ref Capability; pick p := hd caplist{ List => rs += sys->sprint("Pname = %s ", p.pname); Range => rs += sys->sprint("Pname = %s min = %d max = %d default = %d ", p.pname, p.min, p.max, p.default); } # p := tl p; return rs; } capabilities(): string { off, i, ncaps, t: int; l, m, n: int; pname, desc: array of byte; s: array of byte; rs := ""; off = cdp_header_len; (ncaps, off) = get_int(C.cdp[off:], off); if (ncaps > 200) return "error reading capabilities\n"; rs += sys->sprint("i = %d\n", i); firsttime := 0; if (ignoreabls == nil) firsttime = 1; for (j := 0; j < ncaps; j++) { line := ""; (pname, off) = get_pname(C.cdp[off:], off); line += sys->sprint("%s, ", string pname); (t, off) = get_int(C.cdp[off:], off); (desc, off) = get_fstring(C.cdp[off:], off); line += sys->sprint("%s: ", string desc); fact := ""; case t { 1 => t: list of (string, int); (l, off) = get_int(C.cdp[off:], off); (m, off) = get_int(C.cdp[off:], off); line += sys->sprint("items: %d factory: %d\n", l, m); for (k := 0; k < l; k++) { (s, off) = get_fstring(C.cdp[off:], off); (n, off) = get_int(C.cdp[off:], off); line += sys->sprint(" %s: %d\n", string s, n); if (m == n) fact = sconv(s); t = (sconv(s), n) :: t; } cl := ref Capability.List (sconv(pname), sconv(desc), t); 2 => (l, off) = get_int(C.cdp[off:], off); (m, off) = get_int(C.cdp[off:], off); (n, off) = get_int(C.cdp[off:], off); line += sys->sprint("min: %d max: %d factory:%d\n", l, m, n); fact = string n; 3 => (l, off) = get_int(C.cdp[off:], off); case l { 7 => (s, off) = get_dosname(C.cdp[off:], off); 8 => (s, off) = get_fstring(C.cdp[off:], off); * => line += sys->sprint("Invalid type %d\n", l); break; } fact = string s; line += sys->sprint("%s\n", string s); 4 to 8 => break; 9 => break; * => line += sys->sprint("Invalid type %d\n", t); break; } if (firsttime) { if (!filterabls(sconv(pname), string desc)) defattr = (sconv(pname), int fact) :: defattr; } if (!isin(ignoreabls, string pname)) rs += line; } if (firsttime) { defaultattr = array[len defattr] of (string, int); currentattr = array[len defattr] of (string, int); i = 0; for (;defattr != nil; defattr = tl defattr) { defaultattr[i] = hd defattr; currentattr[i++] = hd defattr; } } return rs; } isin(los: list of string, s: string): int { for (;los !=nil; los = tl los) if (hd los == s) return 1; return 0; } set_capture_data(): int { C.cdp[cdp_header_len+0] = byte 0; C.cdp[cdp_header_len+1] = byte 0; C.cdp[cdp_header_len+2] = byte 0; C.cdp[cdp_header_len+3] = byte 0; return 4; } get_camera_state(pname: string,offset: int): string { if (offset != 0) return ""; print(sys->sprint( "get_camera_state(%s)\n", pname),3); C.command = cdp_get_camera_state; off := cdp_header_len; if (pname == "") C.bufbytes = build_cdp_header(C.cdp, 0); else { if (len pname != 4) return "Invalid command name: "+pname+"\n"; C.cdp[off+0] = byte pname[0]; C.cdp[off+1] = byte pname[1]; C.cdp[off+2] = byte pname[2]; C.cdp[off+3] = byte pname[3]; C.bufbytes = build_cdp_header(C.cdp, 4); } send_message(); if (receive_message() != 0) return "Could not read state: "+pname+"\n"; off = cdp_header_len; rlen: int; (rlen, off) = get_int(C.cdp[off:],off); s := ""; rlen = 1; if (pname == "") { for (q := off; q < len C.cdp; q++) { s[0] = int C.cdp[q]; if (s[0] > 0) print(sys->sprint("%s",s),5); } print("\n",5); } for (i := 0; i < rlen; i++) { name, data: array of byte; type1, tmp: int; (name,off) = get_pname(C.cdp[off:],off); (type1,off) = get_int(C.cdp[off:],off); print(sys->sprint( "%d: %s - %d\n", i,pname,type1),5); case type1 { 1 to 5 => (tmp,off) = get_int(C.cdp[off:],off); data = array of byte string tmp; 6 => (data,off) = get_pname(C.cdp[off:],off); 7 => (data,off) = get_dosname(C.cdp[off:],off); 8 => (data,off) = get_fstring(C.cdp[off:],off); * => data = array of byte "!ERROR!"; } # if (string data == "!ERROR!") return ""; # if (rlen == 1) # s = string data; # else s += sys->sprint("%s: %s\n",string name, string data); s += sys->sprint("%s: %s\n",string name, string data); } return s; } set_camera_state(pname: string, val: int): string { print(sys->sprint( "set_camera_state(%s, %d)\n", pname, val),3); if (len pname != 4) return "Command name must be 4 characters"; off := cdp_header_len; C.cdp[off+0] = byte pname[0]; C.cdp[off+1] = byte pname[1]; C.cdp[off+2] = byte pname[2]; C.cdp[off+3] = byte pname[3]; off += 4; off = set_int(C.cdp[off:], val, off); C.command = cdp_set_camera_state; C.bufbytes = build_cdp_header(C.cdp, 8); send_message(); # sys->sleep(1000); if ((e := receive_message()) == 0) { na := getattr(pname); if (na != -1) currentattr[na].t1 = val; return nil; } else return error_table[e]; } capture(): int { C.command = cdp_get_camera_status; C.bufbytes = build_cdp_header(C.cdp, 0); send_message(); # sys->sleep(1000); if (receive_message() != 0) return -1; d := set_capture_data(); C.command = cdp_start_capture; C.bufbytes = build_cdp_header(C.cdp, d); send_message(); # sys->sleep(3000); return receive_message(); } dump_message() { print(sys->sprint(" Message length = %d\n", C.bufbytes),5); print(sys->sprint(" CDP Length = %d\n", (int C.cdp[2]<<8)+(int C.cdp[3])),5); print(sys->sprint(" CDP Version = %d\n", int C.cdp[4]),5); print(sys->sprint(" CDP Command = %x\n", int ((C.cdp[8]<<8)|(C.cdp[9]))),5); print(sys->sprint(" CDP Result Code = %d\n", int ((C.cdp[10]<<8)|(C.cdp[11]))),5); } build_cdp_header(cdp: array of byte, x: int): int { cdp[4] = byte 0; cdp[5] = byte 0; cdp[6] = byte 0; cdp[7] = byte 0; cdp[8] = byte ((C.command>>8)&16rff); cdp[9] = byte (C.command&16rff); cdp[10] = byte 0; cdp[11] = byte 0; l := 8 + x; cdp[0] = byte ((l>>24)&16rff); cdp[1] = byte ((l>>16)&16rff); cdp[2] = byte ((l>>8)&16rff); cdp[3] = byte (l&16rff); return 12+x; } poll_and_reply(nak: int): int { print("poll and reply\n",7); if ((read_n_to(C.fd, pwl, len pwl,TIMEOUT) < 0) && nak) { pak[0] = byte 0; pak[1] = byte 2; # reject write_n(C.fd, pak, len pak); return 0; } pak[0] = byte 0; pak[1] = byte 1; write_n(C.fd, pak, len pak); return 1; } receive_packet(buf: array of byte): int { print("receive_packet\n",6); if (!poll_and_reply(!0)) { print("Poll and reply failed\n",1); return -1; } l := int (((int pwl[0]&3)<<8)|(int pwl[1])); C.bufbytes += l; r := read_n_to(C.fd, buf, l,TIMEOUT); if (r != l) { print(sys->sprint( "could not read packet (read %d, expected %d)\n", r, l),1); return -1; } return 0; } receive_message(): int { print("read_message\n",6); C.bufbytes = 0; if (receive_packet(C.cdp[0:]) != 0) { recon = 1; print("receive packet failed\n",1); return 3; # raise "error: receive packet failed"; } dump_message(); rc := int C.cdp[9]; if ((~rc&16rff) != (C.command&16rff)) { print("command & return are different\n",1); consume(C.fd); return 3; # raise "error: command and return command are not the same\n"; } message_len := (int C.cdp[2]<<8)+(int C.cdp[3]); while (C.bufbytes < message_len) { if (receive_packet(C.cdp[C.bufbytes:]) != 0) { print("Packet is too short\n",1); recon = 1; return 3; # raise "error: receive packet2 failed"; } } # sys->sleep(500); read_n_to(C.fd, pak, len pak, TIMEOUT); return (int ((C.cdp[10]<<8)|(C.cdp[11]))); # result code } reset(fd: ref Sys->FD) { sys->fprint(fd, "d1"); sys->sleep(20); sys->fprint(fd, "d0"); sys->fprint(fd, "b9600"); } kill(pid: int) { pctl := sys->open("/prog/" + string pid + "/ctl", Sys->OWRITE); if (pctl != nil) sys->write(pctl, array of byte "kill", len "kill"); } killg(pid: int) { if ((fd := sys->open("/prog/" + string pid + "/ctl", Sys->OWRITE)) != nil) sys->fprint(fd, "killgrp"); } #dump_buf(buf: array of byte, i: int) #{ # for (j := 0; j < i; j++) # sys->fprint(sys->fildes(2), "%x ", int buf[j]); # sys->fprint(sys->fildes(2), "\n"); #} serialport(port : int) : (ref Sys->FD, ref Sys->FD, string) { C.fd = nil; C.ctlfd = nil; C.mode = BEACON; serport := "/dev/eia" + string port; serctl := serport + "ctl"; for (i := 0; i < len statopt; i++) { statfd := sys->open("/dev/eia"+string port+statopt[i],sys->OREAD); if (statfd != nil) C.stat = i; statfd = nil; } readstat(); fd := sys->open(serport, Sys->ORDWR); if (fd == nil) return (nil, nil, sys->sprint("cannot read %s: %r", serport)); ctlfd := sys->open(serctl, Sys->OWRITE); if (ctlfd == nil) return (nil, nil, sys->sprint("cannot open %s: %r", serctl)); config := array [] of { "b9600", "l8", "p0", "m0", "s1", "r1", "i1", "f", }; for (i = 0; i < len config; i++) { if (sys->fprint(ctlfd,"%s", config[i]) < 0) print(sys->sprint("serial config (%s): %r\n", config[i]),3); } sys->sleep(100); consume(fd); sys->fprint(ctlfd, "d1"); sys->sleep(40); sys->fprint(ctlfd, "d0"); return (fd, ctlfd, nil); } consume(fd: ref sys->FD) { if (fd != nil) { print("Consuming...\n",6); read_n_to(fd, array[1000] of byte, 1000, 1000); } } beacon_intro(data: chan of array of byte, pchan: chan of int, fd: ref Sys->FD) { buf := array[64] of byte; cbuf: array of byte; pid := sys->pctl(0, nil); # print(sys->sprint("b_intro: starting %d\n",pid); pchan <-= pid; failed := array[len bintro] of { * => byte 0 }; # discard characters until lead in character reached print(sys->sprint("\tWaiting for: %d...\n",int bintro[0]),3); do { n := read_n_to(fd, buf, 1, TIMEOUT); if (n == -1) { data <- = failed; return; } print(sys->sprint("\tGot: %d\n",int buf[0]),5); } while (buf[0] != bintro[0]); print("Getting beacon\n",3); # read the next 6 bytes of beacon i := read_n_to(fd, buf[1:], 6,TIMEOUT); for (k := 0; k < i; k++) print(sys->sprint("\tRead %d: %d (wanted %d)\n",k+1, int buf[1+k], int bintro[1+k]),5); if (i != 6) { print("Error reading beacon\n",3); exit; } else { print("sending beacon\n",3); cbuf = buf[0:7]; data <- = cbuf; } } beacon_result(data: chan of array of byte, pchan: chan of int, fd: ref Sys->FD) { buf := array[64] of byte; cbuf: array of byte; pid := sys->pctl(0, nil); pchan <-= pid; # read the next 10 bytes of beacon p := 0; intro := 1; for (;;) { i := read_n_to(fd, buf[p:], 1, TIMEOUT); if (intro) { if (buf[p] != bintro[p]) { intro = 0; buf[0] = buf[p]; p = 1; } else { p++; if (p >= len bintro) p = 0; } } else p++; if (p == 10) break; } for (k := 0; k < p; k++) print(sys->sprint("\tRead %d: %d\n",k, int buf[k]),5); if (p != 10) { print("Error reading beacon result\n",3); exit; } else { print("reading beacon result\n",3); cbuf = buf[0:10]; data <- = cbuf; } } beacon_comp(buf: array of byte, C: Camera_adt): int { speed: string; case int buf[0] { 0 => C.baud = (int buf[2]<<24)|(int buf[3]<<16)|(int buf[4]<<8)|(int buf[5]); C.dfs = (int buf[6]<<8)|(int buf[7]); C.hfs = (int buf[8]<<8)|(int buf[9]); # do baud rate change here sys->sleep(1000); case C.baud { 115200 => speed = "b115200"; 57600 => speed = "b57600"; 38400 => speed = "b38400"; 19200 => speed = "b19200"; * => speed = "b9600"; } print(sys->sprint("Connection Details:\n Baud rate:\t%dbps\n",C.baud),3); print(sys->sprint(" Host frame size:\t%dbytes\n",C.hfs),3); print(sys->sprint(" Device frame size:\t%dbytes\n",C.dfs),3); if (sys->fprint(C.ctlfd,"%s", speed) < 0) { print(sys->sprint("Error setting baud rate %s\n", speed),3); return -1; } -1 => print("Incompatible Data Rate\n",1); return -1; -2 => print("Device does not support these modes\n",1); return -2; * => print(sys->sprint("I'm here!? buf[0] = %d\n",int buf[0]),1); return -1; } return 0; } read_n(fd: ref Sys->FD, buf: array of byte, n: int, res: chan of int) { pid := sys->pctl(0, nil); # print(sys->sprint("read_n: starting %d\n",pid); res <-= pid; print(sys->sprint( "read_n %d\n", n),7); nread := 0; while (nread < n) { i := sys->read(fd, buf[nread:], n-nread); sys->sleep(1); if (i <= 0) break; nread += i; } res <-= nread; # print(sys->sprint("read_n: ending %d\n",pid); } read_n2(fd: ref Sys->FD, buf: array of byte, n: int): int { print(sys->sprint( "read_n2 %d\n", n),7); nread := 0; while (nread < n) { i := sys->read(fd, buf[nread:], n-nread); sys->sleep(1); if (i <= 0) break; nread += i; } return nread; } read_n_to(fd: ref Sys->FD, buf: array of byte, n,t : int): int { v:= 0; rc := chan of int; tc := chan of int; spawn timer2(tc,t); tpid := <- tc; spawn read_n(fd, buf, n, rc); rpid := <- rc; try := 0; alt { <- tc => kill(rpid); print(sys->sprint( "error: read_n timeout\n"),1); recon = 1; return -1; v = <- rc => kill(tpid); break; } return v; } write_n(fd: ref Sys->FD, buf: array of byte, n: int): int { print(sys->sprint("write_n %d\n", n),7); nwrite := 0; while (nwrite < n) { i := sys->write(fd, buf[nwrite:], n-nwrite); sys->sleep(1); if (i <= 0) { print(sys->sprint("Error returned by write: %r\n"),1); readstat(); # recon = 1; return nwrite; } nwrite += i; } print(sys->sprint("write_n returning %d\n", nwrite),7); return nwrite; } readstat() { consume(C.fd); print("Serial status: ",5); statfd := sys->open("/dev/eia"+string C.port_num+statopt[C.stat], sys->OREAD); buf := array[100] of byte; if (statfd != nil) { for (;;) { k := sys->read(statfd,buf,len buf); if (k > 0) print(string buf[:k],2); else break; } print("\n",2); } else print("cannot read serial status\n",1); } beacon_ack(C: Camera_adt) { # set speed i := C.baud; bak[4] = byte ((i>>24)&16rff); bak[5] = byte ((i>>16)&16rff); bak[6] = byte ((i>>8)&16rff); bak[7] = byte (i&16rff); # set frame size to device i = C.dfs; bak[8] = byte ((i>>8)&16rff); bak[9] = byte (i&16rff); # set frame size to host i = C.hfs; bak[10] = byte ((i>>8)&16rff); bak[11] = byte (i&16rff); bak[12] = check_sum(bak, 12); if (write_n(C.fd, bak, len bak) != len bak) { print("Error writing beacon acknowledgement\n",3); exit; } print("beacon acknowledgement written\n",3); } # timer thread send tick <- = 0 to kill timer2(tick: chan of int, delay: int) { pid := sys->pctl(0, nil); tick <-= pid; sys->sleep(delay); tick <- = TOUT; } beacon_ok(buf: array of byte): int { for (i := 0; i < len bintro; i++) { if (buf[i] != bintro[i]) { print(sys->sprint("Beacon failed on byte %d: %d (wanted %d)\n",i,int buf[i],int bintro[i]),3); return 0; } } print("Beacon passed\n",3); return 1; } check_sum(buf: array of byte, l: int): byte { sum := 0; for (i := 0; i < l; i++) sum += int buf[i]; return byte (sum&16rff); } set_int(b: array of byte, i, off: int): int { b[0] = byte (i>>24&16rff); b[1] = byte (i>>16&16rff); b[2] = byte (i>>8&16rff); b[3] = byte (i&16rff); return (off+4); } set_fstring(b: array of byte, s: array of byte, off: int): int { for (i := 0; i < 32; i++) b[i] = byte 0; for (i = 0; i < len s; i++) b[i] = s[i]; return (off+32); } set_dosname(b: array of byte, s: array of byte, off: int): int { for (i := 0; i < 16; i++) b[i] = byte 0; for (i = 0; i < len s; i++) b[i] = s[i]; return (off+16); } get_tag(b: array of byte, off: int): (int, Partialtag) { tag: Partialtag; (off, tag.offset) = get_int(b, off); (off, tag.length) = get_int(b, off); (off, tag.filesize) = get_int(b, off); return (off, tag); } get_int(b: array of byte, off: int): (int, int) { return (get_int2(b), off+4); } get_int2(b: array of byte): int { i := (int b[0]<<24)|(int b[1]<<16)|(int b[2]<<8)|(int b[3]); return i; } get_pname(b: array of byte, off: int): (array of byte, int) { return get_string(b, off, 4); } get_dosname(b: array of byte, off: int): (array of byte, int) { return get_string(b, off, 16); } get_string(b: array of byte, off: int, l: int): (array of byte, int) { s := array[l] of byte; s[0:] = b[0:l]; return (s, off+l); } get_fstring(b: array of byte, off: int): (array of byte, int) { return get_string(b, off, 32); } sconv(b: array of byte): string { s := string b; i := len s-1; while (i >= 0 && s[i] == 0) i--; return s[0:i+1]; } name2dos(s: string): array of byte { return array of byte str->toupper(s); } getqid(i, ftype: int): int { qid := (i<<4) + ftype; return qid; } gettype(qid: int): int { ftype := qid & 15; return ftype; } cutdir(ab:array of byte): string { s := sconv(ab); for (i := 0; i < len s-1; i++) if (s[i] == '/') return s[i+1:len s - 1]; return ""; } convert_thumb(w,h: int, data: array of byte): array of byte { rgb := array[w * h * 3] of byte; index := 0; rgbi := 0; for (i := 0; i < (w * h) / 2; i++) { cb := real data[index]; y := real data[index+1]; cr := real data[index+2]; rb := conv(y + (1.77200 * (cb - 128.0))); gb := conv(y - (0.34414 * (cb - 128.0)) - (0.71414 * (cr - 128.0))); bb := conv(y + (1.4020 * (cr - 128.0))); for (loop := 0; loop < 2; loop++) { rgb[rgbi++] = rb; rgb[rgbi++] = gb; rgb[rgbi++] = bb; } index += 4; } return rgb; } conv(a: real): byte { r := int a; if (r < 0) r = -r; if (r > 255) r = 255; return byte r; } thumb2bit(buf: array of byte, w,h: int): array of byte { convbuf := convert_thumb(w,h,buf); # assume thumbs are small so we wont gain much by compressing them bitarray := array [60+len convbuf] of byte; # assume chans = RGB24 bitarray[:] = array of byte sys->sprint("%11s %11d %11d %11d %11d ", "r8g8b8", 0, 0, w, h); bitarray[60:] = convbuf; return bitarray; } jpg2bit(s: string): string { if (len s < 4) return s; if (s[len s - 4:] != ".jpg") return s; return s[:len s - 4]+".bit"; } oldfiles : list of (string, int, int); getoldfiledata() { oldfiles = nil; for(i := 0; i < reslength; i++) oldfiles = (str->tolower(sconv(filelist[i].cf.dosname)), int filelist[i].qid.path, filelist[i].cf.thumbqid) :: oldfiles; } updatetree(tree: ref Nametree->Tree) { for (i := 0; i < reslength; i++) { name := str->tolower(sconv(filelist[i].cf.dosname)); found := 0; tmp : list of (string, int, int) = nil; for (; oldfiles != nil; oldfiles = tl oldfiles) { (oldname, oldqid, oldthumbqid) := hd oldfiles; # sys->print("'%s' == '%s'?\n",name,oldname); if (name == oldname) { found = 1; filelist[i].qid = (big oldqid, 0, sys->QTFILE); filelist[i].cf.thumbqid = oldthumbqid; } else tmp = hd oldfiles :: tmp; } oldfiles = tmp; # sys->print("len oldfiles: %d\n",len oldfiles); if (found) updateintree(tree, name, i); else addtotree(tree, name, i); } for (; oldfiles != nil; oldfiles = tl oldfiles) { (oldname, oldqid, oldthumbqid) := hd oldfiles; # sys->print("remove from tree: %s\n",oldname); tree.remove(big oldqid); tree.remove(big oldthumbqid); } } updateintree(tree: ref Nametree->Tree, name: string, i: int) { # sys->print("update tree: %s\n",name); tree.wstat(filelist[i].qid.path, dir(name, 8r444, filelist[i].cf.filelength, int filelist[i].qid.path)); tree.wstat(big filelist[i].cf.thumbqid, dir(jpg2bit(name), 8r444, 13020, filelist[i].cf.thumbqid)); } addtotree(tree: ref Nametree->Tree, name: string, i: int) { # sys->print("addtotree: %s\n",name); nextjpgqid += 1<<4; filelist[i].qid = (big nextjpgqid, 0, sys->QTFILE); parentqid := Qjpgdir; tree.create(big parentqid, dir(name, 8r444, filelist[i].cf.filelength, nextjpgqid)); nexttmbqid += 1<<4; filelist[i].cf.thumbqid = nexttmbqid; tree.create(big Qthumbdir, dir(jpg2bit(name), 8r444, 13020, nexttmbqid)); } keepalive(alivechan: chan of int) { alivechan <-= sys->pctl(0,nil); for (;;) { sys->sleep(300000); now := daytime->now(); print(sys->sprint("Alive: %d idle seconds\n",now-wait),6); if (now < wait) wait = now - 300; if (now - wait >= 300) alivechan <-= 1; } } reconnect(n: int): int { attempt := 0; connected = 0; delay := 100; to5 := 0; for (;;) { print(sys->sprint( "Attempting to reconnect (attempt %d)\n",++attempt),2); sys->sleep(100); (C.fd, C.ctlfd, nil) = serialport(C.port_num); if (C.fd == nil || C.ctlfd == nil) print(sys->sprint("Could not open serial port\n"),3); else if (connect() == 0) { set_interface_timeout(); connected = 1; print("Reconnected!\n",2); break; } if (n != -1 && attempt >= n) break; if (++to5 >= 5) { delay *= 2; to5 = 0; if (delay > 600000) delay = 600000; } sys->sleep(delay); } recon = 0; return connected; } # 1: errors # 2: connection # 3: main procs print(s: string, v: int) { if (s != nil && s[len s - 1] == '\n') s = s[:len s - 1]; if (v <= verbosity) sys->fprint(sys->fildes(2), "%s (%s)\n",s,camname); } readinterface(qid : int, offset: big, size: int): (ref sys->Dir, array of byte) { i := qid >> 4; buf := array[size] of byte; fd := sys->open(interfacepaths[i], sys->OREAD); if (fd == nil) return (nil,nil); (n, dir) := sys->fstat(fd); if (offset >= dir.length) return (nil,nil); sys->seek(fd, offset, sys->SEEKSTART); i = sys->read(fd,buf,size); return (ref dir, buf[:i]); } readfile(f: string): string { fd := sys->open(f, sys->OREAD); if(fd == nil) return nil; buf := array[8192] of byte; n := sys->read(fd, buf, len buf); if(n < 0) return nil; return string buf[0:n]; }