Files
Last update 2 years 9 months
by
eddyluursema
Accessories.cpp/********************************************************************** Accessories.cpp COPYRIGHT (c) 2013-2016 Gregg E. Berman Part of DCC++ BASE STATION for the Arduino **********************************************************************/ /********************************************************************** DCC++ BASE STATION can keep track of the direction of any turnout that is controlled by a DCC stationary accessory decoder. All turnouts, as well as any other DCC accessories connected in this fashion, can always be operated using the DCC BASE STATION Accessory command: <a ADDRESS SUBADDRESS ACTIVATE> However, this general command simply sends the appropriate DCC instruction packet to the main tracks to operate connected accessories. It does not store or retain any information regarding the current status of that accessory. To have this sketch store and retain the direction of DCC-connected turnouts, as well as automatically invoke the required <a> command as needed, first define/edit/delete such turnouts using the following variations of the "T" command: <T ID ADDRESS SUBADDRESS>: creates a new turnout ID, with specified ADDRESS and SUBADDRESS if turnout ID already exists, it is updated with specificed ADDRESS and SUBADDRESS returns: <O> if successful and <X> if unsuccessful (e.g. out of memory) <T ID>: deletes definition of turnout ID returns: <O> if successful and <X> if unsuccessful (e.g. ID does not exist) <T>: lists all defined turnouts returns: <H ID ADDRESS SUBADDRESS THROW> for each defined turnout or <X> if no turnouts defined where ID: the numeric ID (0-32767) of the turnout to control ADDRESS: the primary address of the decoder controlling this turnout (0-511) SUBADDRESS: the subaddress of the decoder controlling this turnout (0-3) Once all turnouts have been properly defined, use the <E> command to store their definitions to EEPROM. If you later make edits/additions/deletions to the turnout definitions, you must invoke the <E> command if you want those new definitions updated in the EEPROM. You can also clear everything stored in the EEPROM by invoking the <e> command. To "throw" turnouts that have been defined use: <T ID THROW>: sets turnout ID to either the "thrown" or "unthrown" position returns: <H ID THROW>, or <X> if turnout ID does not exist where ID: the numeric ID (0-32767) of the turnout to control THROW: 0 (unthrown) or 1 (thrown) When controlled as such, the Arduino updates and stores the direction of each Turnout in EEPROM so that it is retained even without power. A list of the current directions of each Turnout in the form <H ID THROW> is generated by this sketch whenever the <s> status command is invoked. This provides an efficient way of initializing the directions of any Turnouts being monitored or controlled by a separate interface or GUI program. **********************************************************************/ #include "Accessories.h" #include "SerialCommand.h" #include "DCCpp_Uno.h" #include "EEStore.h" #include <EEPROM.h> #include "Comm.h" /////////////////////////////////////////////////////////////////////////////// void Turnout::activate(int s){ char c[20]; data.tStatus=(s>0); // if s>0 set turnout=ON, else if zero or negative set turnout=OFF sprintf(c,"a %d %d %d",data.address,data.subAddress,data.tStatus); SerialCommand::parse(c); if(num>0) EEPROM.put(num,data.tStatus); INTERFACE.print("<H"); INTERFACE.print(data.id); if(data.tStatus==0) INTERFACE.print(" 0>"); else INTERFACE.print(" 1>"); } /////////////////////////////////////////////////////////////////////////////// Turnout* Turnout::get(int n){ Turnout *tt; for(tt=firstTurnout;tt!=NULL && tt->data.id!=n;tt=tt->nextTurnout); return(tt); } /////////////////////////////////////////////////////////////////////////////// void Turnout::remove(int n){ Turnout *tt,*pp; for(tt=firstTurnout;tt!=NULL && tt->data.id!=n;pp=tt,tt=tt->nextTurnout); if(tt==NULL){ INTERFACE.print("<X>"); return; } if(tt==firstTurnout) firstTurnout=tt->nextTurnout; else pp->nextTurnout=tt->nextTurnout; free(tt); INTERFACE.print("<O>"); } /////////////////////////////////////////////////////////////////////////////// void Turnout::show(int n){ Turnout *tt; if(firstTurnout==NULL){ INTERFACE.print("<X>"); return; } for(tt=firstTurnout;tt!=NULL;tt=tt->nextTurnout){ INTERFACE.print("<H"); INTERFACE.print(tt->data.id); if(n==1){ INTERFACE.print(" "); INTERFACE.print(tt->data.address); INTERFACE.print(" "); INTERFACE.print(tt->data.subAddress); } if(tt->data.tStatus==0) INTERFACE.print(" 0>"); else INTERFACE.print(" 1>"); } } /////////////////////////////////////////////////////////////////////////////// void Turnout::parse(char *c){ int n,s,m; Turnout *t; switch(sscanf(c,"%d %d %d",&n,&s,&m)){ case 2: // argument is string with id number of turnout followed by zero (not thrown) or one (thrown) t=get(n); if(t!=NULL) t->activate(s); else INTERFACE.print("<X>"); break; case 3: // argument is string with id number of turnout followed by an address and subAddress create(n,s,m,1); break; case 1: // argument is a string with id number only remove(n); break; case -1: // no arguments show(1); // verbose show break; } } /////////////////////////////////////////////////////////////////////////////// void Turnout::load(){ struct TurnoutData data; Turnout *tt; for(int i=0;i<EEStore::eeStore->data.nTurnouts;i++){ EEPROM.get(EEStore::pointer(),data); tt=create(data.id,data.address,data.subAddress); tt->data.tStatus=data.tStatus; tt->num=EEStore::pointer(); EEStore::advance(sizeof(tt->data)); } } /////////////////////////////////////////////////////////////////////////////// void Turnout::store(){ Turnout *tt; tt=firstTurnout; EEStore::eeStore->data.nTurnouts=0; while(tt!=NULL){ tt->num=EEStore::pointer(); EEPROM.put(EEStore::pointer(),tt->data); EEStore::advance(sizeof(tt->data)); tt=tt->nextTurnout; EEStore::eeStore->data.nTurnouts++; } } /////////////////////////////////////////////////////////////////////////////// Turnout *Turnout::create(int id, int add, int subAdd, int v){ Turnout *tt; if(firstTurnout==NULL){ firstTurnout=(Turnout *)calloc(1,sizeof(Turnout)); tt=firstTurnout; } else if((tt=get(id))==NULL){ tt=firstTurnout; while(tt->nextTurnout!=NULL) tt=tt->nextTurnout; tt->nextTurnout=(Turnout *)calloc(1,sizeof(Turnout)); tt=tt->nextTurnout; } if(tt==NULL){ // problem allocating memory if(v==1) INTERFACE.print("<X>"); return(tt); } tt->data.id=id; tt->data.address=add; tt->data.subAddress=subAdd; tt->data.tStatus=0; if(v==1) INTERFACE.print("<O>"); return(tt); } /////////////////////////////////////////////////////////////////////////////// Turnout *Turnout::firstTurnout=NULL;