/* * iPump - experimental controller for IntelliFlow pumps */ #define APRS485_API 1 #include "aprs485.h" #include "pa_iflo.h" char version[] = "@(#) iPump 0.03"; struct { u08_t cadr; /* this controllers address */ u08_t padr; /* pump address */ int ctrl; } gl; int str2i(char *str, char **rem) { int i, k; while (*str == ' ') str++; for (i = k = 0; *str >= '0' && *str <= '9'; str++) i = i * 10 + (*str - '0'), k++; if (rem) *rem = str; return k ? i : -1; } pa5_t *pa5_hdr(void *buf, u08_t cfi) { pa5_t *ph; bzero(ph=buf,sizeof(*ph)); ph->lpb = 0xa5; ph->dst = gl.padr; ph->src = gl.cadr; ph->cfi = cfi; return ph; } int pa5_snd(int bd, pa5_t *ps) { int n; u16_t sum; u08_t *b, *s, pa5[PA5SIZ]; for (b = pa5, n = 3; --n >= 0; *b++ = 0xff); b[-2] = 0; n = sizeof(*ps) + ps->len; for (sum = 0, s = &ps->lpb; --n >= 0; b++) sum += *b = *s++; *b++ = sum>>8; *b++ = sum; return write(bd,pa5,b-pa5); } pa5_t *pa5_rcv(int bd, void *buf, int tmo) { pa5_t *pr; u08_t *b, *c, *e; fd_set rfd; tmv_t tv; u16_t sum; int n, k; FD_ZERO(&rfd); FD_SET(bd,&rfd); tv.tv_usec = tmo * 1000; tv.tv_sec = tv.tv_usec/1000000; tv.tv_usec -= tv.tv_sec*1000000; if ((k = select(bd+1,&rfd,0,0,&tv)) <= 0) return 0; if ((n = read(bd,buf,PA5SIZ)) < sizeof(pa5_t)) return 0; for (e = (b = buf) + n; b < e && *b != 0xa5; b++); if ((e - b) < sizeof(pa5_t)) return 0; pr = (pa5_t *)b; if (((c = &pr->dat[pr->len]) + 2) < e || pr->dst != gl.cadr) return 0; for (sum = 0; b < c; sum += *b++); if (sum != ((c[0]<<8)+c[1])) return 0; return pr; } int pump_cmd(int bd, int cmd, int val) { pa5_t *ps, *pr; char snd[sizeof(pa5_t)+4], pa5[PA5SIZ]; ps = pa5_hdr(snd,cmd); ps->dat[ps->len++] = val; if (pa5_snd(bd,ps) <= 0) return -1; if ((pr = pa5_rcv(bd,pa5,500)) == 0) return -2; if (pr->src != ps->dst || pr->dst != ps->src) return -3; if (pr->cfi != ps->cfi || pr->len != ps->len) return -4; return pr->dat[0] == ps->dat[0] ? pr->dat[0] : -5; } int pump_reg(int bd, int adr, int val) { pa5_t *ps, *pr; char snd[sizeof(pa5_t)+4], pa5[PA5SIZ]; ps = pa5_hdr(snd,0x01); ps->dat[ps->len++] = adr>>8; ps->dat[ps->len++] = adr>>0; ps->dat[ps->len++] = val>>8; ps->dat[ps->len++] = val>>0; if (pa5_snd(bd,ps) <= 0) return -1; if ((pr = pa5_rcv(bd,pa5,500)) == 0) return -2; if (pr->src != ps->dst || pr->dst != ps->src) return -3; if (pr->cfi != ps->cfi || pr->len != 2) return -4; adr = (pr->dat[0]<<8)+pr->dat[1]; return adr == val ? val : -5; } iflsr_t *pump_stat(int bd, void *buf) { pa5_t *ps, *pr; int ctrl; char snd[sizeof(pa5_t)+4]; if ((ctrl = gl.ctrl) != IFLO_DSP_REM) { gl.ctrl = pump_cmd(bd,IFLO_DSP,IFLO_DSP_REM); if (gl.ctrl != IFLO_DSP_REM) return 0; } ps = pa5_hdr(snd,IFLO_SRG); pr = pa5_snd(bd,ps) <= 0 ? 0 : pa5_rcv(bd,buf,500); if (ctrl != IFLO_DSP_REM) gl.ctrl = pump_cmd(bd,IFLO_DSP,IFLO_DSP_LOC); if (pr == 0) return 0; if (pr->src != gl.padr || pr->dst != gl.cadr) return 0; if (pr->cfi != ps->cfi || pr->len != sizeof(iflsr_t)) return 0; return (iflsr_t *)&pr->dat; } void pr_pstat(iflsr_t *p) { if (p == 0) printf("no status!\n"); else { printf("run=%02x",p->run); printf(" mod=%02x",p->mod); printf(" pmp=%02x",p->pmp); printf(" pwr=%d",ntohs(p->pwr)); printf(" rpm=%d",ntohs(p->rpm)); printf(" gpm=%d",p->gpm); printf(" ppc=%d",p->ppc); printf(" err=%02x",p->err); printf(" tmr=%d",p->tmr); printf(" %02d:%02d\n",p->clk[0],p->clk[1]); } } typedef struct { int rep; int run; int rr; int gpm; } ltc_t; void ltic6(int bd, ltc_t *l) { iflsr_t *p; int k; char pa5[PA5SIZ]; if (l->run == 0 && l->rr == 0) return; while ((k = 1)) { if (l->rr != 6) break; if ((gl.ctrl = pump_cmd(bd,IFLO_DSP,IFLO_DSP_REM)) != IFLO_DSP_REM) break; if (pump_reg(bd,IFLO_REG_SPGPM,l->gpm) != l->gpm) break; if (pump_cmd(bd,IFLO_MOD,IFLO_MOD_FEATR1) != IFLO_MOD_FEATR1) break; if (pump_cmd(bd,IFLO_RUN,IFLO_RUN_STRT) != IFLO_RUN_STRT) break; if ((p = pump_stat(bd,pa5)) == 0) break; if (p->err) break; if (p->run != IFLO_RUN_STRT) break; l->run = l->rr; k = 0; break; } if (k) { /* shut it down */ pump_cmd(bd,IFLO_RUN,IFLO_RUN_STOP); pump_cmd(bd,IFLO_MOD,IFLO_MOD_MANUAL); gl.ctrl = pump_cmd(bd,IFLO_DSP,IFLO_DSP_LOC); l->run = l->rr = 0; } } int uifc(int bd) { fd_set rfd; tmv_t tv; ltc_t *l, ltc; int don, tic, n, k; char buf[16], pa5[PA5SIZ]; bzero(l=<c,sizeof(*l)); l->rep = 16; l->gpm = 20; for (tic = don = 0; !don; ) { if (--tic < 0) { switch (gl.ctrl) { case IFLO_DSP_REM: case IFLO_DSP_LOC: ltic6(bd,l); tic = l->run >= 0 ? (l->rep-1) : 0; break; default: gl.ctrl = pump_cmd(bd,IFLO_DSP,IFLO_DSP_LOC); tic = 0; break; } } printf("\r%s ",version+5); printf(l->run==0?"-- ":"%2d ",tic+1); printf(gl.ctrl==IFLO_DSP_REM?"R> ": gl.ctrl==IFLO_DSP_LOC?"L> ": "?> "); fflush(stdout); tv.tv_sec = 1; tv.tv_usec = 0; FD_ZERO(&rfd); FD_SET(0,&rfd); FD_SET(bd,&rfd); if ((n = select(bd+1,&rfd,0,0,&tv)) < 0 && errno != EINTR) break; if (n <= 0) continue; if (FD_ISSET(bd,&rfd)) { if ((n = read(bd,pa5,sizeof(pa5))) == 2 && pa5[0] == EOT) printf("\rEOT from hub \n"); else printf("\rWe are not alone on the bus...\n"); break; } if (!FD_ISSET(0,&rfd)) continue; if (read(0,buf,sizeof(buf)) <= 0) continue; switch (buf[0]) { case 'q': don = 1; break; case 's': pr_pstat(pump_stat(bd,pa5)); break; case 'S': l->rr = 0, tic = 0; break; case 'R': l->rr = 6, tic = 0; break; case 'f': /* this puposefully suspends tick! */ printf("gpm [%d]: ",l->gpm); fflush(stdout); if ((n = read(0,buf,sizeof(buf))) <= 0) break; if ((k = str2i(buf,0)) >= 15 && k <= 130) l->gpm = k; break; default: printf("q - quit\n"); printf("s - pump status\n"); printf("S - stop\n"); printf("R - run\n"); printf("f - set flow rate\n"); break; } } return errno; } int main(int ac, char **av) { int bd; char msg[128]; bzero(&gl,sizeof(gl)); gl.cadr = 0x11; /* standard is 0x10 */ gl.padr = 0x60; gl.ctrl = -1; bd = hub_at(ac>1?av[1]:0,msg); printf("%s: %s\n",av[0],msg); if (bd < 0) return -1; uifc(bd); hub_dt(bd); return 0; }