chiark / gitweb /
features in record etc.; about to redo safety lay tran speed etc. etc.
authorian <ian>
Tue, 15 Apr 2008 21:35:56 +0000 (21:35 +0000)
committerian <ian>
Tue, 15 Apr 2008 21:35:56 +0000 (21:35 +0000)
hostside/realtime.h
hostside/record-i.h
hostside/record-l.l
hostside/record-y.y
hostside/record.c

index 497e44d26d89a06f0407fbcb312aa0d23acc1b82..04dafe4eec3cfe6c69cd992b0261f5cba0c7f72c 100644 (file)
@@ -76,9 +76,14 @@ void retransmit_urgent_cancel(RetransmitUrgentNode *rn);
 
 /*---------- 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 {
@@ -87,17 +92,19 @@ 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 ----------*/
 
index 0da12a78110ef5d8435923f1d20a78abb0eb4f67..568f81ba50f8b89807a562c6a2532fc5ea4cf554 100644 (file)
@@ -14,9 +14,13 @@ void record_train_step_count(void);
 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);
index 1422456bb26c1a5320dd6984854b0c92c268b296..578f51f08c11bfeb4a01daa22b022a83f70d2f0c 100644 (file)
@@ -19,6 +19,7 @@
 
 train          { STR TRAIN; }
 seg            { STR SEG; }
+feature                { STR FEATURE; }
 is             { STR IS; }
 at             { STR AT; }
 has            { STR HAS; }
@@ -28,6 +29,7 @@ end           { STR END; }
  /* 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"); }
index 8d50a682a51f246d856f4ac97112e1afe2ec09b5..903fefd45de33ea0be22dcd3b38d25d603945318 100644 (file)
@@ -11,17 +11,21 @@ static Train *cur_train;
   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
@@ -52,16 +56,25 @@ line:               /* empty */
        |       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
 
index 363350daa8bdcc94905dd795abded8c1ef86e900..9b5470699dfbb535d3a1dfd7e220a98220260dcb 100644 (file)
@@ -21,6 +21,9 @@
 #include "record-i.h"
 #include "record-l.h"
 
+FeaturesTarget *feattargs;
+FeaturesAddr *feataddrs;
+
 /*---------- input and error handling ----------*/
 
 static const char *filename;
@@ -60,6 +63,69 @@ Segment *record_pname2seg(const char *pname) {
   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;
@@ -150,6 +216,40 @@ found:
   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;