chiark / gitweb /
can fit 139 lines on an atp -B page
[trains.git] / hostside / trackloc.c
1 /*
2  */
3
4 #include <assert.h>
5
6 #include "realtime.h"
7
8 /*---------- constructors/initialisers ----------*/
9
10 void trackloc_set_maxinto(TrackLocation *tloc, Segment *seg, int backwards) {
11   tloc->seg= seg;
12   tloc->backwards= backwards;
13   tloc->remain= 0;
14 }
15
16 int trackloc_set_exactinto(TrackLocation *t, TrackAdvanceContext *c,
17                            Segment *seg, int backwards, int into) {
18   const SegPosCombInfo *pci;
19   int r;
20
21   t->seg= seg;
22   t->backwards= backwards;
23   t->remain= 0;
24
25   r= trackloc_getlink(t,c,&pci,0,-1);
26   if (r) return r;
27   assert(pci);
28   
29   t->remain= pci->dist - into;
30   return 0;
31 }
32
33 /*---------- enquirers ----------*/
34
35 int trackloc_getlink(TrackLocation *t, TrackAdvanceContext *c,
36                      const SegPosCombInfo **pci_r,
37                      const SegmentLinkInfo **link_r,
38                      MovPosComb mpc) {
39   const SegPosCombInfo *pci;
40   int r;
41
42   if (mpc<0)
43     mpc= t->seg->movposcomb;
44
45   if (c && c->getmovpos) {
46     r= c->getmovpos(t,c,&mpc);
47     if (r) return r;
48   }
49   if (mpc<0) {
50     if (pci_r) *pci_r=0;
51     if (link_r) *link_r=0;
52     return 0;
53   }
54   assert(mpc >= 0);
55   assert(mpc < t->seg->i->n_poscombs);
56 //fprintf(stderr,"trackloc_getlink returning %s %d %d\n",t->seg->i->pname,mpc,
57 //      t->backwards);
58   pci= &t->seg->i->poscombs[mpc];
59 //fprintf(stderr,"trackloc_getlink returning  %s\n",pci->pname);
60   if (pci_r) *pci_r= pci;
61   if (link_r) *link_r= &pci->link[t->backwards];
62   return 0;
63 }
64
65 /*---------- mutator ----------*/
66
67 static int nextseg(TrackLocation *t, TrackAdvanceContext *c,
68                    const SegPosCombInfo **pci_r,
69                    const SegmentLinkInfo **link_r,
70                    const TrackLocation *leaving) {
71   MovPosComb mpc_nego;
72   int r;
73
74   mpc_nego= t->seg->movposcomb;
75
76   if (c->nextseg) {
77     r= c->nextseg(t,c, &mpc_nego, leaving);
78     if (r) return r;
79   }
80
81   r= trackloc_getlink(t,c, pci_r,link_r, mpc_nego);
82   return r;
83 }
84
85 int trackloc_advance(TrackLocation *t, TrackAdvanceContext *c) {
86   Segment *next;
87   SegmentNum nextnum;
88   const SegPosCombInfo *pci;
89   const SegmentLinkInfo *link;
90   TrackLocation leaving;
91   int r;
92
93   r= nextseg(t,c, &pci,&link, 0);
94   if (r) return r;
95
96 //fprintf(stderr,"advance start getlink %s%s/%s -> %s\n",
97 //      t->backwards?"-":"", t->seg->i->pname,
98 //      pci ? pci->pname : "?",
99 //      link && SOMEP(link->next) ? info_segments[link->next].pname : "?");
100
101   for (;;) {
102     if (!c->distance) return 0;
103
104     if (t->remain) {
105       int use= t->remain < c->distance ? t->remain : c->distance;
106       t->remain -= use;
107       c->distance -= use;
108       continue;
109     }
110
111     nextnum= link->next;
112
113     if (!SOMEP(nextnum)) {
114       if (c->trackend) return c->trackend(t,c);
115       return 0;
116     }
117     next= &segments[nextnum];
118
119     leaving= *t;
120
121     t->seg= next;
122     t->backwards ^= link->next_backwards;
123     t->remain= -1;
124
125     r= nextseg(t,c, &pci,&link, &leaving);
126     if (r) { *t= leaving; return r; }
127
128 //fprintf(stderr,"advance ran getlink %s/%s -> %s\n",leaving->i->pname,
129 //      pci ? pci->pname : "?",
130 //      link && SOMEP(link->next) ? info_segments[link->next].pname : "?");
131
132     t->remain= pci->dist;
133   }
134 }
135
136 static int interfering_movposcomb(TrackAdvanceContext *c, Segment *seg) {
137   MovPosComb mpc;
138   int r;
139
140   mpc= seg->movposcomb;
141   if (c && c->getmovpos) {
142     TrackLocation t;
143     t.seg= seg;
144     t.backwards= 0;
145     t.remain= 0;
146
147     r= c->getmovpos(&t,c,&mpc);
148     if (r) return 1;
149   }
150
151   if (mpc < 0) return 1;
152   return seg->i->interferes_movposcomb_map & (1u << mpc);
153 }
154
155 Segment *segment_interferes(TrackAdvanceContext *c, Segment *base) {
156   SegmentNum intern;
157   Segment *inter;
158
159   intern= base->i->interferes;
160
161   if (!SOMEP(intern)) return 0;
162   if (!interfering_movposcomb(c,base)) return 0;
163
164   inter= &segments[intern];
165
166   assert(base->i == &info_segments[inter->i->interferes]);
167   if (!interfering_movposcomb(c,inter)) return 0;
168
169   return inter;
170 }
171
172 int trackloc_reverse_exact(TrackLocation *t, TrackAdvanceContext *c) {
173   const SegPosCombInfo *pci;
174   int r;
175   
176   r= trackloc_getlink(t,c,&pci,0,-1);
177   if (r) return r;
178   assert(pci);
179   t->remain= pci->dist - t->remain;
180   t->backwards ^= 1;
181   return 0;
182 }