static void __sxReader( void* threadinst ) { iOThread th = (iOThread)threadinst; iOMttmFcc fcc = (iOMttmFcc)ThreadOp.getParm( th ); iOMttmFccData data = Data(fcc); byte buffer[256]; TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "SX reader started." ); ThreadOp.sleep( 1000 ); TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "trying to get the FCC version..." ); buffer[0] = 0x81; if( __transact(data, buffer, 1, buffer, 7 ) ) { TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "FCC version %d.%d", buffer[5], buffer[4] ); } ThreadOp.sleep( 100 ); while( data->run ) { byte cmd[2]; Boolean ok = True; ThreadOp.sleep( 50 ); if( ok ) { cmd[0] = 0x78; cmd[1] = 0x03; /*loopback test __transact( data, buffer, 224, NULL, 0);*/ ok = __transact( data, cmd, 2, buffer, 226); if(ok) { MemOp.copy( data->sx1[0], buffer, 113 ); MemOp.copy( data->sx1[1], buffer+113, 113 ); } } ThreadOp.sleep( 50 ); if( ok ) { cmd[0] = 0x78; cmd[1] = 0xC0; /*loopback test __transact( data, buffer, 190, NULL, 0);*/ ok = __transact( data, cmd, 2, buffer, 192); if(ok) { MemOp.copy( data->sx2[0], buffer, 96 ); MemOp.copy( data->sx2[1], buffer+96, 96 ); } } if( ok ) { __evaluateFB( data ); __updateSlots( data ); } }; TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "SX reader ended." ); }
static iONode _cmd( obj inst ,const iONode cmd ) { iOMttmFccData data = Data(inst); unsigned char out[32]; unsigned char in [32]; int insize = 0; iONode reply = NULL; MemOp.set( in, 0x00, sizeof( in ) ); if( cmd != NULL ) { if( StrOp.equals( NodeOp.getName( cmd ), wSwitchList.name() ) ) { int cnt = NodeOp.getChildCnt(cmd); int i; for( i = 0; i < cnt; i++ ) { /* build the point map */ __getPoint(data, NodeOp.getChild(cmd, i) ); } data->swInited = False; } else { int size = __translate( data, cmd, out, &insize ); TraceOp.dump( NULL, TRCLEVEL_BYTE, (char*)out, size ); if( __transact( data, out, size, in, insize ) ) { } } } /* Cleanup Node1 */ cmd->base.del(cmd); return reply; }
static void __swTimeWatcher( void* threadinst ) { iOThread th = (iOThread)threadinst; iOP50 p50 = (iOP50)ThreadOp.getParm( th ); iOP50Data o = Data(p50); ThreadOp.sleep( 100 ); TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "Switch time watcher started." ); do { ThreadOp.sleep( 10 ); if( o->lastSwCmd != -1 && o->lastSwCmd >= o->swtime ) { unsigned char out[2]; out[0] = 32; TraceOp.trc( name, TRCLEVEL_DEBUG, __LINE__, 9999, "swTimeWatcher() END SWITCHTIME %dms", o->lastSwCmd ); if( __transact( o, (char*)out, 1, NULL, 0 ) ) { o->lastSwCmd = -1; } else TraceOp.trc( name, TRCLEVEL_EXCEPTION, __LINE__, 9999, "swTimeWatcher() Could not send reset byte!" ); } if( o->lastSwCmd != -1 ) { o->lastSwCmd += 10; } } while( o->run ); TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "Switch time watcher ended." ); }
static void __feedbackReader( void* threadinst ) { iOThread th = (iOThread)threadinst; iOP50 p50 = (iOP50)ThreadOp.getParm( th ); iOP50Data o = Data(p50); unsigned char* fb = allocMem(256); ThreadOp.sleep( 100 ); TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "Feedback reader started." ); do { unsigned char out[256]; unsigned char in [512]; ThreadOp.sleep( o->psleep ); if( o->fbmod == 0 ) continue; out[0] = (unsigned char)(128 + o->fbmod); if( __transact( o, (char*)out, 1, (char*)in, o->fbmod * 2 ) ) { if( memcmp( fb, in, o->fbmod * 2 ) != 0 ) { /* inform listener */ __evaluateState( o, fb, in, o->fbmod * 2); memcpy( fb, in, o->fbmod * 2 ); } } } while( o->run ); TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "Feedback reader ended." ); }
static iONode _cmd( obj inst, const iONode nodeA ) { iOP50Data o = Data(inst); unsigned char out[256]; unsigned char in [512]; int insize = 0; iONode nodeB = NULL; if( nodeA != NULL ) { int size = __translate( o, nodeA, out, &insize ); if( __transact( o, (char*)out, size, (char*)in, insize ) ) { /* Inform timer. */ if( StrOp.equals( NodeOp.getName( nodeA ), wSwitch.name() ) ) { o->lastSwCmd = 0; ThreadOp.sleep( 100 ); } /* inform listener */ if( insize > 0 ) { char* s = StrOp.byteToStr( in, insize ); nodeB = NodeOp.inst( NodeOp.getName( nodeA ), NULL, ELEMENT_NODE ); wResponse.setdata( nodeB, s ); StrOp.free(s); } } /* Cleanup Node1 */ nodeA->base.del(nodeA); } /* return Node2 */ return nodeB; }
static void _halt( obj inst, Boolean poweroff ) { iOP50Data data = Data(inst); unsigned char p50[2]; data->run = False; if( poweroff ) { p50[0] = (unsigned char)97; __transact( data, (char*)p50, 1, NULL, 0 ); } SerialOp.close( data->serial ); TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "Shutting down <%s>...", data->iid ); }
static void _halt( obj inst, Boolean poweroff ) { iOSprogData data = Data(inst); data->run = False; TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "Shutting down [%s]...", data->iid ); if( poweroff ) { char outa[32]; StrOp.fmtb( outa, "-\r" ); data->power = False; __transact( (iOSprog)inst, outa, StrOp.len(outa), NULL, 0, 1 ); } ThreadOp.sleep(1000); data->commOK = False; SerialOp.close( data->serial ); return; }
static iONode _cmd( obj inst ,const iONode nodeA ) { iOSprogData data = Data(inst); iONode nodeB = NULL; char outa[100] = {'\0'}; char ina[100] = {'\0'}; int insize = 0; if( nodeA != NULL ) { int repeat = __translate( (iOSprog)inst, nodeA, outa, &insize ); if( StrOp.len(outa) > 0 ) { __transact( (iOSprog)inst, outa, StrOp.len(outa), ina, insize, repeat ); } /* Cleanup Node1 */ nodeA->base.del(nodeA); } /* return Node2 */ return nodeB; }
static int __translate( iOMttmFccData data, iONode node, byte* out, int *insize ) { *insize = 0; if( StrOp.equals( NodeOp.getName( node ), wFbInfo.name() ) ) { __updateFB( data, node ); data->fbInited = False; } /* Switch command. */ else if( StrOp.equals( NodeOp.getName( node ), wSwitch.name() ) ) { int bus = wSwitch.getbus( node ) & 0x01; int addr = wSwitch.getaddr1( node ) & 0x7F; byte pin = 0x01 << ( wSwitch.getport1( node ) - 1 ); byte mask = ~pin; iOPoint point = __getPoint(data, node); if( point != NULL ) { point->lastcmd = SystemOp.getTick(); } out[0] = bus; out[1] = addr | 0x80; out[2] = 0x01 << ( wSwitch.getport1( node ) - 1 ); /* reset pin to 0: */ out[2] = data->swstate[bus][addr] & mask; if( StrOp.equals( wSwitch.getcmd( node ), wSwitch.turnout ) ) out[2] |= pin; /* save new state: */ data->swstate[bus][addr] = out[2]; *insize = 1; return 3; } /* Output command */ else if( StrOp.equals( NodeOp.getName( node ), wOutput.name() ) ) { int bus = wOutput.getbus( node ) & 0x01; int addr = wOutput.getaddr( node ); int port = wOutput.getport( node ); int gate = wOutput.getgate( node ); int action = StrOp.equals( wOutput.getcmd( node ), wOutput.on ) ? 0x01:0x00; byte pin = 0x01 << ( port - 1 ); byte mask = ~pin; out[0] = bus; out[1] = addr | 0x80; /* reset pin to 0: */ out[2] = data->swstate[bus][addr] & mask; if( action ) out[2] |= pin; /* save new state: */ data->swstate[bus][addr] = out[2]; *insize = 1; return 3; } /* System command. */ /* Gleisspannung ein (SX1/2-Bus 0): Vom PC: 0x00 0xFF 0x01 Gleisspannung aus (SX1/2-Bus 0): Vom PC: 0x00 0xFF 0x00 Gleisspannung ein (SX1/2-Bus 1): Vom PC: 0x01 0xFF 0x01 Gleisspannung aus (SX1/2-Bus 1): Vom PC: 0x01 0xFF 0x00 Zum PC: 0x00 Zum PC: 0x00 Zum PC: 0x00 Zum PC: 0x00 */ else if( StrOp.equals( NodeOp.getName( node ), wSysCmd.name() ) ) { const char* cmd = wSysCmd.getcmd( node ); if( StrOp.equals( cmd, wSysCmd.stop ) || StrOp.equals( cmd, wSysCmd.ebreak ) ) { out[0] = 0x00; out[1] = 0xFF; out[2] = 0x00; *insize = 1; /* Return code from FCC. */ TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "Power OFF" ); return 3; } else if( StrOp.equals( cmd, wSysCmd.go ) ) { out[0] = 0x00; out[1] = 0xFF; out[2] = 0x01; *insize = 1; /* Return code from FCC. */ TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "Power ON" ); return 3; } } /* Loc command.*/ else if( StrOp.equals( NodeOp.getName( node ), wLoc.name() ) ) { int speed = 0; byte in = 0; Boolean fn = wLoc.isfn( node ); int dir = wLoc.isdir( node ); int spcnt = wLoc.getspcnt( node ); byte horn; int index = 0; iOSlot slot = __getSlot(data, node ); if( slot == NULL ) { TraceOp.trc( name, TRCLEVEL_WARNING, __LINE__, 9999, "could not get slot for loco %s", wLoc.getid(node) ); return 0; } if( data->dummyio ) { __updateSlots(data); } spcnt = slot->steps; if( wLoc.getV( node ) != -1 ) { if( StrOp.equals( wLoc.getV_mode( node ), wLoc.V_mode_percent ) ) speed = (wLoc.getV( node ) * spcnt) / 100; else if( wLoc.getV_max( node ) > 0 ) speed = (wLoc.getV( node ) * spcnt) / wLoc.getV_max( node ); } if( slot->ebreak && speed > 0 ) { speed++; } TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "loc=%s addr=%d speed=%d steps=%d lights=%s dir=%s", wLoc.getid(node), wLoc.getaddr(node), speed, spcnt, fn?"on":"off", dir?"forwards":"reverse" ); if( slot->sx1 ) { /* native selectrix SX1 */ TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "SX1 loco command for %s", wLoc.getid(node) ); out[0] = wLoc.getbus(node)&0x01; out[1] = wLoc.getaddr(node); out[1] |= 0x80; /* SX1-Loks werden wie bisher direkt über die entsprechenden SX1-Kanäle des SX1/2-Bus- Systems 0 gesteuert. Die Kanalbelegung ist: Bits 0 bis 4: Fahrstufen von 0 bis 31 Bit 5: Fahrtrichtung (0 entspricht vorwaerts, 1 entspricht rueckwaerts) Bit 6: Licht (0 bedeutet Licht aus, 1 bedeutet Licht ein) Bit 7: Horn (0 bedeutet Horn aus, 1 bedeutet Horn ein) */ out[2] = speed & 0x1F; out[2] |= (wLoc.isdir(node) ? 0x00:0x20); out[2] |= (wLoc.isfn(node) ? 0x40:0x00); if (!slot->sx1aux1 && !slot->sx1aux2) horn = slot->f1_8 & 0x01; /* Horn at F1 */ else if (slot->sx1aux1 && !slot->sx1aux2) horn = slot->f9_16 & 0x01; /* Horn at F9 */ else horn = 0x00; out[2] |= ((horn & 0x01) ? 0x80:0x00); slot->speed = speed; slot->dir = wLoc.isdir(node); slot->lights = wLoc.isfn(node); slot->lastcmd = SystemOp.getTick(); *insize = 1; return 3; } index = slot->index; /* Lights ON : 0x79 0x05 Index 0x02 0x00 OFF: 0x79 0x05 Index 0x00 0x00 */ out[0] = 0x79; out[1] = 0x05; out[2] = index; out[3] = fn?0x02:0x00; out[4] = 0x00; __transact( data, out, 5, &in, 1 ); /* Verändern der Fahrstufe einer SX2-, DCC- oder MM-Lok: Vom PC: 0x79 0x03 Index FS 0x00 Zum PC: gleich 0x00 (im Erfolgsfalle) ungleich 0x00 (im Fehlerfalle) Verändern der Fahrstufe und der Fahrtrichtung einer SX2-, DCC- oder MM-Lok: Vom PC: 0x79 0x13 Index FSFR 0x00 Zum PC: gleich 0x00 ungleich 0x00 Index ist der bei der Anmeldung der betreffenden Lok an die FCC-Digitalzentrale zurückgegebene Wert. FSFR ist der, gemäß der oben stehenden Tabelle, umgerechnete Wert der neuen Fahrstufe, wobei das höchstwertige Bit die neue Fahrtrichtung bestimmt! */ out[0] = 0x79; out[1] = 0x13; out[2] = index; out[3] = speed + (dir?0x00:0x80); out[4] = 0x00; *insize = 1; /* Return code from FCC. */ return 5; } /* Function command. */ else if( StrOp.equals( NodeOp.getName( node ), wFunCmd.name() ) ) { Boolean f1 = wFunCmd.isf1 ( node ); Boolean f2 = wFunCmd.isf2 ( node ); Boolean f3 = wFunCmd.isf3 ( node ); Boolean f4 = wFunCmd.isf4 ( node ); Boolean f5 = wFunCmd.isf5 ( node ); Boolean f6 = wFunCmd.isf6 ( node ); Boolean f7 = wFunCmd.isf7 ( node ); Boolean f8 = wFunCmd.isf8 ( node ); Boolean f9 = wFunCmd.isf9 ( node ); Boolean f10 = wFunCmd.isf10( node ); Boolean f11 = wFunCmd.isf11( node ); Boolean f12 = wFunCmd.isf12( node ); Boolean f13 = wFunCmd.isf13( node ); Boolean f14 = wFunCmd.isf14( node ); Boolean f15 = wFunCmd.isf15( node ); Boolean f16 = wFunCmd.isf16( node ); byte in = 0; iOSlot slot = __getSlot(data, node ); if( slot == NULL ) { TraceOp.trc( name, TRCLEVEL_WARNING, __LINE__, 9999, "could not get slot for loco %s", wLoc.getid(node) ); return 0; } if( slot->sx1 ) { /* native selectrix SX1 */ int addr = wFunCmd.getaddr( node ); if (slot->sx1aux2) { out[0] = wLoc.getbus(node)&0x01; out[1] = slot->sx1aux2; out[1] |= 0x80; out[2] = (f9 << 0 | f10 << 1 | f11 << 2 | f12 << 3 | f13 << 4 | f14 << 5 | f15 << 6 | f16 << 7); TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "SX1 Auxchannel 2 command for loco [%s]", wLoc.getid(node) ); slot->f9_16 = out[2]; slot->lastcmd = SystemOp.getTick(); __transact( data, out, 3, &in, 1 ); } if (slot->sx1aux1) { out[0] = wLoc.getbus(node)&0x01; out[1] = slot->sx1aux1; out[1] |= 0x80; out[2] = (f1 << 0 | f2 << 1 | f3 << 2 | f4 << 3 | f5 << 4 | f6 << 5 | f7 << 6 | f8 << 7); TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "SX1 Auxchannel 1 command for loco [%s]", wLoc.getid(node) ); slot->f1_8 = out[2]; slot->lastcmd = SystemOp.getTick(); __transact( data, out, 3, &in, 1 ); } TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "SX1 function command for %s", wLoc.getid(node) ); out[0] = wLoc.getbus(node)&0x01; out[1] = wLoc.getaddr(node); out[1] |= 0x80; out[2] = slot->speed & 0x1F; out[2] |= (slot->dir ? 0x00:0x20); slot->lights = wLoc.isfn(node); /* save light function */ out[2] |= (slot->lights ? 0x40:0x00); if (!slot->sx1aux1 && !slot->sx1aux2) { out[2] |= (f1 ? 0x80:0x00); /* Horn at F1 */ slot->f1_8 = f1 ? 0x01:0x00; } else if (slot->sx1aux1 && !slot->sx1aux2) { out[2] |= (f9 ? 0x80:0x00); /* Horn at F9 */ slot->f9_16 = f9 ? 0x01 : 0x00; } /* No else */ slot->lastcmd = SystemOp.getTick(); *insize = 1; return 3; } else { TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "function command for %s", wLoc.getid(node) ); out[0] = 0x79; out[1] = 0x16; out[2] = slot->index; out[3] = (f1 << 0 | f2 << 1 | f3 << 2 | f4 << 3 | f5 << 4 | f6 << 5 | f7 << 6 | f8 << 7); out[4] = (f9 << 0 | f10 << 1 | f11 << 2 | f12 << 3 | f13 << 4 | f14 << 5 | f15 << 6 | f16 << 7); out[5] = 0x00; slot->f1_8 = out[3]; slot->f9_16 = out[4]; *insize = 1; return 6; } } /* Program command. */ else if( StrOp.equals( NodeOp.getName( node ), wProgram.name() ) ) { if( wProgram.getcmd( node ) == wProgram.set ) { int cv = wProgram.getcv( node ); int value = wProgram.getvalue( node ); int addr = wProgram.getaddr( node ); if( wProgram.ispom(node) ) { TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "POM: set CV%d of SX2 loc %d to %d...", cv, addr, value ); /* SX2: 0x7A Adresse (High) Adresse (Low) PA (High) PA (Low) Wert */ out[0] = 0x7A; out[1] = addr/256; out[2] = addr%256; out[3] = cv/256; out[4] = cv%256; out[5] = value; *insize = 1; return 6; } else { TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "set CV%d of SX2 loc %d to %d...", cv, addr, value ); /* SX2: 0x83 0xCA High Low Wert */ out[0] = 0x83; out[1] = 0xCA; out[2] = cv/256; out[3] = cv%256; out[4] = value; *insize = 3; return 5; } } else if( wProgram.getcmd( node ) == wProgram.get ) { int cv = wProgram.getcv( node ); int addr = wProgram.getaddr( node ); if( wProgram.ispom(node) ) { TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "*** not supported *** POM: read CV%d of loc %d...", cv, addr ); } else { TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "read CV%d of SX2 loc %d...", cv, addr ); /* SX2: 0x83 0xC2 High Low 0x00 */ out[0] = 0x83; out[1] = 0xC2; out[2] = cv/256; out[3] = cv%256; out[4] = 0; *insize = 3; return 5; } } } return 0; }
static iOSlot __getSlot(iOMttmFccData data, iONode node) { int steps = wLoc.getspcnt(node); int addr = wLoc.getaddr(node); int fncnt = wLoc.getfncnt(node); Boolean ebreak = True; Boolean sx1 = False; byte index = 0xFF; iOSlot slot = NULL; byte cmd[32] = {0x79, 0x01}; slot = (iOSlot)MapOp.get( data->lcmap, wLoc.getid(node) ); if( slot != NULL ) { TraceOp.trc( name, TRCLEVEL_DEBUG, __LINE__, 9999, "slot exist for %s", wLoc.getid(node) ); return slot; } if( StrOp.equals( wLoc.prot_S, wLoc.getprot(node) ) ) { steps = 31; sx1 = True; ebreak = False; TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "sx1, steps=%d, fncnt=%d", steps, fncnt ); } /* Die DCC-Lok mit der langen Adresse 1234 und 126 Fahrstufen soll an die FCC- Digitalzentrale angemeldet werden: Bestimmung: 1234 (binär: 00010011010010) DCC-Lokadresse: 00010011010010 00 entspricht 0x1348 Es ist daher Folgendes an die FCC-Digitalzentrale zu senden: Vom PC: 0x79 0x01 0x13 0x48 0x07 */ else if( StrOp.equals( wLoc.prot_N, wLoc.getprot(node) ) ) { /* short DCC */ addr = addr << 2; cmd[4] = steps > 100 ? 0x05:(steps > 14 ? 0x81:0x91); steps = steps > 100 ? 126:(steps > 14 ? 28:14); TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "short DCC, steps=%d, fncnt=%d", steps, fncnt ); } else if( StrOp.equals( wLoc.prot_L, wLoc.getprot(node) ) ) { /* long DCC */ addr = addr << 2; cmd[4] = steps > 100 ? 0x07:(steps > 14 ? 0x83:0x93); steps = steps > 100 ? 126:(steps > 14 ? 28:14); TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "long DCC, steps=%d, fncnt=%d", steps, fncnt ); } else if( StrOp.equals( wLoc.prot_M, wLoc.getprot(node) ) ) { /* MM */ /* Die MM-Lok mit der Adresse 218 soll an die FCC-Digitalzentrale angemeldet werden: Bestimmung: 218 (binär: 00000011011010) MM-Lokadresse: 00000011011010 00 entspricht 0x0368 Es ist daher Folgendes an die FCC-Digitalzentrale zu senden: Vom PC: 0x79 0x01 0x03 0x68 0x02 */ addr = addr << 2; cmd[4] = fncnt == 4 ? 0x82:0x92; steps = 14; TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "MM, steps=%d, fncnt=%d", steps, fncnt ); } else { /* Die SX2-Lok mit der Adresse 5678 soll an die FCC-Digitalzentrale angemeldet werden: Rechnung: 5678 / 100 = 56 (binär: 0111000) Rest 78 (binär: 1001110) SX2-Lokadresse: 0111000 1001110 00 entspricht 0x7138 Es ist daher Folgendes an die FCC-Digitalzentrale zu senden: Vom PC: 0x79 0x01 0x71 0x38 0x04 */ addr = (wLoc.getaddr(node) / 100) << 9; addr = addr + ((wLoc.getaddr(node) % 100) << 2); /* default SX2 */ cmd[4] = 0x04; steps = 127; ebreak = False; TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "default SX2, steps=%d, fncnt=%d", steps, fncnt ); } cmd[2] = addr / 256; cmd[3] = addr % 256; if( sx1 || __transact( data, cmd, 5, &index, 1 ) ) { TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "got index %d for %s", index, wLoc.getid(node) ); slot = allocMem( sizeof( struct slot) ); slot->addr = addr; slot->index = index; slot->protocol = cmd[4]; slot->steps = steps; slot->ebreak = ebreak; slot->sx1 = sx1; if (sx1) { slot->sx1aux1 = slot->sx1aux2 = 0; if (fncnt > 0) { slot->sx1aux1 = addr+1; /* First SX1 auxchannel at loco address + 1 */ TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "SX1 Auxchannel 1 Addr=%d", slot->sx1aux1 ); } if (fncnt > 8) { slot->sx1aux2 = addr+2; /* Second SX1 auxchannel at loco address + 2 */ TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "SX1 Auxchannel 2 Addr=%d", slot->sx1aux2 ); } } slot->bus = wLoc.getbus(node); slot->id = StrOp.dup(wLoc.getid(node)); if( MutexOp.wait( data->lcmux ) ) { MapOp.put( data->lcmap, wLoc.getid(node), (obj)slot); MutexOp.post(data->lcmux); } TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "slot created for %s", wLoc.getid(node) ); } return slot; }
static void __sprogReader( void* threadinst ) { iOThread th = (iOThread)threadinst; iOSprog sprog = (iOSprog)ThreadOp.getParm( th ); iOSprogData data = Data(sprog); char in[256] = {0}; int idx = 0; int retry = 0; TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "SPROG reader started." ); ThreadOp.sleep( 1000 ); StrOp.fmtb( in, "?\r" ); __transact( sprog, in, StrOp.len(in), NULL, 0, 1 ); do { ThreadOp.sleep( 10 ); if( data->run && data->commOK && MutexOp.wait( data->mux ) ) { int available = SerialOp.available(data->serial); if( available > 0 ) { if( SerialOp.read(data->serial, &in[idx], 1) ) { TraceOp.dump( NULL, TRCLEVEL_DEBUG, (char*)in, StrOp.len(in) ); if( idx > 254 ) { in[idx] = 0; TraceOp.trc( name, TRCLEVEL_WARNING, __LINE__, 9999, "reader overflow [%d]\n%s", idx, in ); idx = 0; } else if( in[idx] == '\r' || in[idx] == '\n' ) { in[idx+1] = '\0'; StrOp.replaceAll( in, '\n', '\0' ); StrOp.replaceAll( in, '\r', '\0' ); if( StrOp.len(in) > 0 ) { TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "SPROG read: [%s]", in ); __handleResponse(sprog, in); } idx = 0; in[idx] = '\0'; } else if( StrOp.equals( in, "P> ") || StrOp.equals( in, " P>") || StrOp.equals( in, " P> ") ) { idx = 0; in[idx] = '\0'; /* ignore prompt */ } else { idx++; } } } else if( available == -1 || SerialOp.getRc(data->serial) > 0 ) { /* device error */ data->commOK = False; SerialOp.close(data->serial); TraceOp.trc( name, TRCLEVEL_EXCEPTION, __LINE__, 9999, "device error" ); } /* Release the mutex. */ MutexOp.post( data->mux ); } else if(!data->commOK) { retry++; if( retry >= 500 ) { retry = 0; data->commOK = SerialOp.open( data->serial ); if(data->commOK) { SerialOp.setDTR(data->serial, True); SerialOp.setRTS(data->serial, True); } } } } while(data->run); TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "SPROG reader ended." ); ThreadOp.base.del(th); }
static void __sprogWriter( void* threadinst ) { iOThread th = (iOThread)threadinst; iOSprog sprog = (iOSprog)ThreadOp.getParm( th ); iOSprogData data = Data(sprog); int slotidx = 0; TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "SPROG writer started." ); while(data->run) { ThreadOp.sleep(25); if( data->power ) { if( data->slots[slotidx].addr > 0 ) { byte dcc[12]; char cmd[32] = {0}; char out[64] = {0}; char in [64] = {0}; TraceOp.trc( name, TRCLEVEL_DEBUG, __LINE__, 9999, "slot refresh for %d", data->slots[slotidx].addr ); if( data->slots[slotidx].V == data->slots[slotidx].V_prev && data->slots[slotidx].changedfgrp == 0 ) { if( data->slots[slotidx].idle + 8000 < SystemOp.getTick() ) { TraceOp.trc( name, TRCLEVEL_MONITOR, __LINE__, 9999, "slot %d purged for loco address %d", slotidx, data->slots[slotidx].addr ); data->slots[slotidx].addr = 0; data->slots[slotidx].idle = 0; data->slots[slotidx].fgrp = 0; data->slots[slotidx].changedfgrp = 0; data->slots[slotidx].V_prev = 0; data->slots[slotidx].V = 0; slotidx++; continue; } } else { data->slots[slotidx].V_prev = data->slots[slotidx].V; data->slots[slotidx].fgrp = data->slots[slotidx].changedfgrp; data->slots[slotidx].changedfgrp = 0; data->slots[slotidx].idle = SystemOp.getTick(); } if( data->slots[slotidx].steps > 28 ) { int size = speedStep128Packet(dcc, data->slots[slotidx].addr, data->slots[slotidx].longaddr, data->slots[slotidx].V, data->slots[slotidx].dir ); __byteToStr( cmd, dcc, size ); StrOp.fmtb( out, "O %s\r", cmd ); TraceOp.trc( name, TRCLEVEL_BYTE, __LINE__, 9999, "128 DCC out: %s", out ); __transact( sprog, out, StrOp.len(out), in, 3, 1 ); } else if( data->slots[slotidx].steps == 28 ) { int size = speedStep28Packet(dcc, data->slots[slotidx].addr, data->slots[slotidx].longaddr, data->slots[slotidx].V, data->slots[slotidx].dir ); __byteToStr( cmd, dcc, size ); StrOp.fmtb( out, "O %s\r", cmd ); TraceOp.trc( name, TRCLEVEL_BYTE, __LINE__, 9999, "28 DCC out: %s", out ); __transact( sprog, out, StrOp.len(out), in, 3, 1 ); } else { int size = speedStep14Packet(dcc, data->slots[slotidx].addr, data->slots[slotidx].longaddr, data->slots[slotidx].V, data->slots[slotidx].dir, data->slots[slotidx].lights ); __byteToStr( cmd, dcc, size ); StrOp.fmtb( out, "O %s\r", cmd ); TraceOp.trc( name, TRCLEVEL_BYTE, __LINE__, 9999, "14 DCC out: %s", out ); __transact( sprog, out, StrOp.len(out), in, 3, 1 ); } if( data->slots[slotidx].fgrp > 0 ) { int size = 0; ThreadOp.sleep(25); if( data->slots[slotidx].fgrp == 1 ) { size = function0Through4Packet(dcc, data->slots[slotidx].addr, data->slots[slotidx].longaddr, data->slots[slotidx].fn[0], data->slots[slotidx].fn[1], data->slots[slotidx].fn[2], data->slots[slotidx].fn[3], data->slots[slotidx].fn[4] ); } else if( data->slots[slotidx].fgrp == 2 ) { size = function5Through8Packet(dcc, data->slots[slotidx].addr, data->slots[slotidx].longaddr, data->slots[slotidx].fn[5], data->slots[slotidx].fn[6], data->slots[slotidx].fn[7], data->slots[slotidx].fn[8] ); } else if( data->slots[slotidx].fgrp == 3 ) { size = function9Through12Packet(dcc, data->slots[slotidx].addr, data->slots[slotidx].longaddr, data->slots[slotidx].fn[9], data->slots[slotidx].fn[10], data->slots[slotidx].fn[11], data->slots[slotidx].fn[12] ); } else if( data->slots[slotidx].fgrp == 4 || data->slots[slotidx].fgrp == 5 ) { size = function13Through20Packet(dcc, data->slots[slotidx].addr, data->slots[slotidx].longaddr, data->slots[slotidx].fn[13], data->slots[slotidx].fn[14], data->slots[slotidx].fn[15], data->slots[slotidx].fn[16], data->slots[slotidx].fn[17], data->slots[slotidx].fn[18], data->slots[slotidx].fn[19], data->slots[slotidx].fn[20] ); } else if( data->slots[slotidx].fgrp == 6 || data->slots[slotidx].fgrp == 7 ) { size = function21Through28Packet(dcc, data->slots[slotidx].addr, data->slots[slotidx].longaddr, data->slots[slotidx].fn[21], data->slots[slotidx].fn[22], data->slots[slotidx].fn[23], data->slots[slotidx].fn[24], data->slots[slotidx].fn[25], data->slots[slotidx].fn[26], data->slots[slotidx].fn[27], data->slots[slotidx].fn[28] ); } __byteToStr( cmd, dcc, size ); StrOp.fmtb( out, "O %s\r", cmd ); TraceOp.trc( name, TRCLEVEL_BYTE, __LINE__, 9999, "function group %d DCC out: %s", data->slots[slotidx].changedfgrp, out ); __transact( sprog, out, StrOp.len(out), in, 3, 1 ); } slotidx++; } else { slotidx = 0; } } }; TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "SPROG writer ended." ); ThreadOp.base.del(th); }