From 50b4af8b34033ccc825d5fe3c9051bafb51d1930 Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 15 Apr 2008 21:35:56 +0000 Subject: [PATCH] features in record etc.; about to redo safety lay tran speed etc. etc. --- hostside/realtime.h | 19 ++++++--- hostside/record-i.h | 4 ++ hostside/record-l.l | 2 + hostside/record-y.y | 25 ++++++++--- hostside/record.c | 100 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 138 insertions(+), 12 deletions(-) diff --git a/hostside/realtime.h b/hostside/realtime.h index 497e44d..04dafe4 100644 --- a/hostside/realtime.h +++ b/hostside/realtime.h @@ -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 ----------*/ diff --git a/hostside/record-i.h b/hostside/record-i.h index 0da12a7..568f81b 100644 --- a/hostside/record-i.h +++ b/hostside/record-i.h @@ -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); diff --git a/hostside/record-l.l b/hostside/record-l.l index 1422456..578f51f 100644 --- a/hostside/record-l.l +++ b/hostside/record-l.l @@ -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 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"); } diff --git a/hostside/record-y.y b/hostside/record-y.y index 8d50a68..903fefd 100644 --- a/hostside/record-y.y +++ b/hostside/record-y.y @@ -11,17 +11,21 @@ static Train *cur_train; const char *name; Train *train; Segment *seg; + FeaturesFeature *feature; + FeaturesAddr *feataddr; int num; } -%token TRAIN SEG IS AT HAS STEP HOME END IDENT +%token TRAIN FEATURE SEG IS AT HAS STEP HOME END IDENT FEATLETTER %token NL %token NUM -%type ident -%type train -%type seg -%type backwards +%type ident +%type train +%type seg +%type backwards +%type feature +%type 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 diff --git a/hostside/record.c b/hostside/record.c index 363350d..9b54706 100644 --- a/hostside/record.c +++ b/hostside/record.c @@ -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<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; -- 2.30.2