/*---------- features, filled in by record, used by features.c ----------*/
-typedef struct {
+#define FEATURESADDR_TRANSMITS 4
+ /* 0..2 are func0to4 func5to8 func9to12 and speed cmd
+ * pi.l is 0 if not transmitting */
+
+typedef struct FeaturesAddr {
+ struct FeaturesAddr *next;
int addr, cbitmap;
- RetransmitRelaxedNode rn[4]; /* nmra feat setting cmds and speed cmd */
+ RetransmitRelaxedNode rn[FEATURESADDR_TRANSMITS];
} FeaturesAddr;
typedef struct {
int speedstep; /* -ve means backwards; 0 means not to use motor for feat */
} FeaturesFeature;
-typedef struct {
+typedef struct FeaturesTarget {
+ struct FeaturesTarget *next;
char *pname;
- char *featchs; /* null-terminated for convenience; _ means unused */
- FeaturesFeature *feats; /* same order as featchs */
+ char *featchs; /* null-terminated */
+ FeaturesFeature **feats; /* same order as featchs */
} FeaturesTarget;
extern int n_trains;
extern Train *trains;
extern Segment *segments;
-extern int n_feattargs;
+
extern FeaturesTarget *feattargs;
+extern FeaturesAddr *feataddrs;
/*---------- global variables, in realtime.c ----------*/
void record_train_home(Train *tra, int backw, Segment *seg);
void record_seg_has(Segment *seg, int backw, Train *tra);
void record_seg_at(Segment *seg, const char *movposcomb_pname);
+void record_feature_nmrafeat(FeaturesFeature*, FeaturesAddr*, int num);
+void record_feature_motor(FeaturesFeature*, FeaturesAddr*, int speed);
Train *record_pname2train(const char *pname);
Segment *record_pname2seg(const char *pname);
+FeaturesFeature *record_pname2feature(const char *pname, const char *letter);
+FeaturesAddr *record_feataddr(int addr);
char *record_tempzone_strdup(const char *s);
void record_yyerror(const char *m);
void record_tempzone_clear(void);
train { STR TRAIN; }
seg { STR SEG; }
+feature { STR FEATURE; }
is { STR IS; }
at { STR AT; }
has { STR HAS; }
/* new keywords must be added to %token<name> and ident: in record-y.y */
[A-Za-z][A-Za-z0-9_]+ { STR IDENT; }
+[a-z] { STR FEATLETTER; }
[0-9]{0,8} { record_yylval.num= strtoul(yytext,0,10); return NUM; }
[0-9]{9} { record_yyerror("number too long"); }
const char *name;
Train *train;
Segment *seg;
+ FeaturesFeature *feature;
+ FeaturesAddr *feataddr;
int num;
}
-%token <name> TRAIN SEG IS AT HAS STEP HOME END IDENT
+%token <name> TRAIN FEATURE SEG IS AT HAS STEP HOME END IDENT FEATLETTER
%token <name> NL
%token <num> NUM
-%type <name> ident
-%type <train> train
-%type <seg> seg
-%type <num> backwards
+%type <name> ident
+%type <train> train
+%type <seg> seg
+%type <num> backwards
+%type <feature> feature
+%type <feataddr> feataddr
%defines
%error-verbose
| SEG seg AT ident
{ if ($2) record_seg_at($2,$4);
}
+ | FEATURE feature IS feataddr NUM
+ { if ($2) record_feature_nmrafeat($2,$4,$5);
+ }
+ | FEATURE feature IS feataddr STEP NUM
+ { if ($2) record_feature_motor($2,$4,$6);
+ }
backwards: /* empty */ { $$= 0; }
| '-' { $$= 1; }
segments: { cur_train= (void*)-1; }
| backwards seg { record_train_home(cur_train,$1,$2); } segments
-ident: TRAIN | SEG | IS | AT | HAS | STEP | HOME | END | IDENT
+ident: TRAIN | SEG | IS | AT | HAS | STEP | HOME | END
+ | IDENT | FEATLETTER
seg: ident { $$= record_pname2seg($1); }
train: ident { $$= record_pname2train($1); }
+feature: ident FEATLETTER { $$= record_pname2feature($1,$2); }
+feataddr: NUM { $$= record_feataddr($1); }
end: END NL
#include "record-i.h"
#include "record-l.h"
+FeaturesTarget *feattargs;
+FeaturesAddr *feataddrs;
+
/*---------- input and error handling ----------*/
static const char *filename;
return 0; /* silently discard data for segments no longer in the layout */
}
+#define SLIST_FIND_OR_INSERT(head,search,node,found,fillin) do{ \
+ for ((search)= &(head); \
+ ((node)=*(search)) && !(found); \
+ (search)= &(node)->next); \
+ if (!(node)) { \
+ *(search)= (node)= mmalloc(sizeof(*(node))); \
+ fillin; \
+ } \
+ }while(0)
+
+FeaturesAddr *record_feataddr(int num) {
+ FeaturesAddr **search, *node;
+
+ if (num<1 || num>0x3ff) record_yyerror("feature address out of range");
+
+ SLIST_FIND_OR_INSERT
+ (feataddrs,search,node, node->addr == num, ({
+ int i;
+ node->next= 0;
+ node->addr= num;
+ node->cbitmap= 0;
+ for (i=0; i<4; i++) node->rn[i].pi.l= 0;
+ }));
+
+ return node;
+}
+
+FeaturesFeature *record_pname2feature(const char *name, const char *letter) {
+ FeaturesTarget **search, *node;
+ FeaturesFeature *feat;
+ char *p;
+ int l;
+
+ if (!trains) return 0; /* 2nd pass only */
+ assert(letter[0] && !letter[1]);
+
+ SLIST_FIND_OR_INSERT
+ (feattargs,search,node, !strcmp(name,node->pname), ({
+ node->pname= mstrdup(name);
+ node->featchs= 0;
+ node->feats= 0;
+ }));
+
+ l= node->featchs ? strlen(node->featchs) : 0;
+ if (l) {
+ p= strchr(node->featchs, letter[0]);
+ if (p) return node->feats[p - node->featchs];
+ }
+
+ node->featchs= mrealloc(node->featchs,l+2);
+ node->featchs[l]= letter[0];
+ node->featchs[l+1]= 0;
+
+ node->feats= mrealloc(node->feats, (l+1)*sizeof(*node->feats));
+ node->feats[l]= feat= mmalloc(sizeof(*feat));
+
+ feat->a= 0;
+ feat->bitval= 0;
+ feat->speedstep= 0;
+
+ return feat;
+}
+
/*---------- zone allocator for strings ----------*/
typedef struct TempZoneBlock TempZoneBlock;
seg->movposcomb= poscomb;
}
+/*---------- features ----------*/
+
+static void record_feature_addr(FeaturesFeature *feat, FeaturesAddr *addr) {
+ if (feat->a && feat->a != addr)
+ record_yyerror("feature includes multiple decoder addresses");
+ feat->a= addr;
+}
+
+void record_feature_nmrafeat(FeaturesFeature *feat, FeaturesAddr *addr,
+ int num) {
+ int bitval;
+
+ record_feature_addr(feat,addr);
+
+ if (num<0 || num>12) record_yyerror("NMRA function out of range 0..12");
+ bitval= 1<<num;
+
+ if (feat->bitval & bitval)
+ record_yyerror("feature bit respecified unnecessarily");
+
+ feat->bitval |= bitval;
+}
+
+void record_feature_motor(FeaturesFeature *feat, FeaturesAddr *addr,
+ int speed) {
+ record_feature_addr(feat,addr);
+
+ if (speed<-126 || speed>126) record_yyerror("motor speed out of range");
+ if (!speed) record_yyerror("zero motor speed?!");
+
+ if (feat->speedstep) record_yyerror("feature specifies multiple speeds");
+ feat->speedstep= speed;
+}
+
/*---------- speed curves ----------*/
static SpeedCurveEntry *curvebuf;