*/
#include "realtime.h"
+#include "nmra.h"
+
+/*---------- polarity ----------*/
static PicInsn polarityinsn= { { 0x90 }, 0 };
void actual_inversions_done(void) {
serial_transmit(&polarityinsn);
}
+
+/*---------- features ----------*/
+
+static void feat_updated_cmd(FeaturesAddr *a, int ix, Nmra *n /*destroyed*/) {
+ assert(a->rn[ix].pi.l);
+ retransmit_relaxed_cancel(&a->rn[ix]);
+ retransmit_relaxed_queue(&a->rn[ix], n);
+}
+
+static void feat_updated_funcs(FeaturesAddr *a, int ix,
+ void (*enco)(Nmra *n, int addr, unsigned map),
+ unsigned thiscmd) {
+ Nmra n;
+ if (!(a->all & thiscmd)) return;
+ enco(&n,a->addr,a->current);
+ feat_updated_cmd(a,ix,&n);
+}
+
+void features_updated(FeaturesAddr *a) {
+ /* idempotent; call this after updating a->current */
+
+ feat_updated_funcs(a,0, enco_nmra_funcs0to4, 0x0001f);
+ feat_updated_funcs(a,1, enco_nmra_funcs5to8, 0x001e0);
+ feat_updated_funcs(a,2, enco_nmra_funcs9to12, 0x01e00);
+
+ if (a->all & FEATURES_SPEEDSTEP_BIT) {
+ Nmra n;
+ enco_nmra_speed126(&n, a->addr,
+ a->current & FEATURES_SPEEDSTEP_BIT
+ ? a->speedstep : 0,
+ !!(a->all & FEATURES_SPEEDSTEP_REVERSE));
+ feat_updated_cmd(a,3, &n);
+ }
+}
+
+void features_start_xmit(void) {
+ FeaturesAddr *a;
+ Nmra n;
+ int ix;
+
+ for (a=feataddrs_head; a; a=a->next) {
+ for (ix=0; ix<FEATURESADDR_TRANSMITS; ix++) {
+ RetransmitRelaxedNode *rn= &a->rn[ix];
+ if (!rn->pi.l) {
+ enco_nmra_idle(&n);
+ retransmit_relaxed_queue(rn,&n);
+ }
+ }
+ features_updated(a);
+ }
+}
feature shinkansen head-red is 1 6
feature shinkansen tail is 1 7
feature shinkansen tail-red is 1 8
+feature - is 1 4
feature santafe head is 2 5
feature santafe tail is 2 6
+feature - is 2 4
feature bavarian head is 4 5
feature bavarian tail is 4 6
+feature - is 4 4
feature hoover motor is 5 step 60
/* 0..2 are func0to4 func5to8 func9to12 and speed cmd
* pi.l is 0 if not transmitting */
+#define FEATURES_SPEEDSTEP_BIT 0x4000u /* in a->current, a->all, f->bits */
+#define FEATURES_SPEEDSTEP_REVERSE 0x8000u /* in a->all */
+
typedef struct FeaturesAddr {
struct FeaturesAddr *next;
- int addr, cbitmap;
+ int addr, speedstep;
+ unsigned current, all;
RetransmitRelaxedNode rn[FEATURESADDR_TRANSMITS];
} FeaturesAddr;
typedef struct {
char *pname; /* first, for pname1st_compar */
FeaturesAddr *a;
- int bitval; /* may have no or several bits set */
- int speedstep; /* -ve means backwards; 0 means not to use motor for feat */
+ unsigned bits; /* may have no or several bits set */
} FeaturesFeature;
typedef struct FeaturesTarget {
/* this belongs in {au,skel}proto-pic.[ch] really but it's
* more convenient here. */
+void features_start_xmit(void);
+void features_updated(FeaturesAddr *a);
+
/*---------- from movpos.c ----------*/
void points_turning_on(void);
{ if ($2) record_seg_at($2,$4);
}
| FEATURE feature IS feataddr NUM
- { if ($2) record_feature_nmrafeat($2,$4,$5);
+ { if (trains) record_feature_nmrafeat($2,$4,$5);
}
| FEATURE feature IS feataddr STEP NUM
- { if ($2) record_feature_motor($2,$4,$6);
+ { if (trains) record_feature_motor($2,$4,$6);
}
backwards: /* empty */ { $$= 0; }
seg: ident { $$= record_pname2seg($1); }
train: ident { $$= record_pname2train($1); }
feature: ident ident { $$= record_pname2feature($1,$2); }
+ | '-' { $$= 0; }
feataddr: NUM { $$= record_feataddr($1); }
end: END NL
* seg <segpn> at <movposcomb>
* feature <trainorfeatpn> <featpn> is <addr> <nmranum>
* feature <trainorfeatpn> <featpn> is <addr> step [-]<nmranum>
+ * feature - is <addr> <nmranum> } prevents enabling feature;
+ * feature - is <addr> step [-]<nmranum> } xmits turning it off
*
* speed is floating point in m/s
*/
int i;
node->next= 0;
node->addr= num;
- node->cbitmap= 0;
+ node->speedstep= 0;
+ node->current= node->all= 0;
for (i=0; i<4; i++) node->rn[i].pi.l= 0;
}));
int i;
FeaturesTarget *targ;
FeaturesFeature *feat;
- if (!trains) return 0; /* 2nd pass only */
ARY_FIND_OR_APPEND
(feattargs,n_feattargs,i,targ, !strcmp(targ->pname, targpn), ({
(targ->feats,targ->n_feats,i,feat, !strcmp(feat->pname, featpn), ({
feat->pname= mstrdup(featpn);
feat->a= 0;
- feat->bitval= 0;
- feat->speedstep= 0;
+ feat->bits= 0;
}));
return feat;
/*---------- features ----------*/
-static void record_feature_addr(FeaturesFeature *feat, FeaturesAddr *addr) {
+static void record_feature_bits(FeaturesFeature *feat, FeaturesAddr *addr,
+ unsigned bits) {
+ if (!feat) /* `-' feature */
+ return;
if (feat->a && feat->a != addr)
record_yyerror("feature includes multiple decoder addresses");
feat->a= addr;
+ feat->bits |= bits;
+ addr->all |= bits;
}
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;
+ if (addr->all & bitval)
+ record_yyerror("feature bit respecified");
+
+ record_feature_bits(feat,addr,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 (addr->speedstep) record_yyerror("feature specifies multiple speeds");
+
+ record_feature_bits(feat,addr,FEATURES_SPEEDSTEP_BIT);
- if (feat->speedstep) record_yyerror("feature specifies multiple speeds");
- feat->speedstep= speed;
+ addr->speedstep= speed;
+ if (addr->speedstep<0) {
+ addr->all |= FEATURES_SPEEDSTEP_REVERSE;
+ addr->speedstep= -addr->speedstep;
+ }
}
static int pname1st_compar(const void *av, const void *bv) {
case Sta_Resolving:
resolve_begin();
points_turning_on();
+ features_start_xmit();
enco_pic_on(&piob);
break;
case Sta_Finalising: