chiark / gitweb /
hostside: more length for bavarian
[trains.git] / hostside / retransmit.c
1 /*
2  * realtime
3  * nmra retransmission
4  */
5
6 #include "realtime.h"
7
8 /*
9  * There are two kinds of messages: urgent and relaxed.
10  *
11  * Urgent messages may be due for speedy transmission.  The due urgent
12  * message with the highest priority is always transmitted as soon as
13  * a slot is available.  This is known as `speedy transmission'.
14  * 
15  * When no urgent messages are due for speedy transmission, messages
16  * (urgent or relaxed) are transmitted in a round-robin fashion.  This
17  * round-robin transmission is completely independent of the speedy
18  * transmission.
19  *
20  * Each urgent message is due for speedy transmission as follows:
21  *   - When it is first queued and has not yet been
22  *     speedily transmitted:
23  *         immediately due, with maximum priority
24  *   - Following each speedy transmission:
25  *         due after an interval since the previous
26  *           transmission; this interval increases exponentially
27  *           for each transmission
28  *         with priority which decreases with later transmissions
29  *         until it has been speedily transmitted a certain number of times
30  *   - Thereafter:
31  *         no longer ever due; subject to round-robin transmission only.
32  * Intervals are measured in messages regardless of length.
33  */
34 /*
35  * Implementation:
36  *  All messages are on one of the relaxed queues; urgent messages
37  *  are on the relaxed[0] queue and messages which are explicitly
38  *  relaxed are on the relaxed[1] queue.  This gives the previously-
39  *  urgent messages 50% of the bandwidth.
40  *  There is one queue for each speedy retransmission; messages are on
41  *  it in chronological order of dueness.
42  */
43
44 #include "realtime.h"
45 #include "nmra.h"
46 #include "retransmit-table.h"
47
48 #define RETRANSMIT_TIME_SIGNED_MAX ((~(Retransmit__Time)0) >> 1)
49
50 static PicInsn linefill;
51
52 static DLIST2_HEAD(RetransmitRelaxedNode) relaxed[2];
53 static int last_relaxed_qn;
54 static Retransmit__Time elapsed;
55 static PerSpeedyTrans speedies[] = SPEEDIESINIT;
56
57 static void debug_hex(const Byte *d, int l) {
58   int i;
59   for (i=0; i<l; i++) DPRINTFA(" %02x", d[i]);
60 }
61
62 static void debug_message(const PicInsn *pi, const Nmra *n) {
63   DPRINTFA(" :"); debug_hex(pi->d, pi->l);
64   if (n) { DPRINTFA(" <="); debug_hex(n->d, n->l); }
65   DPRINTFA(".\n");
66 }
67
68 static void retransmit_this(const PicInsn *pi) {
69   if (DEBUGP(retransmit,message)) debug_message(pi, 0);
70   serial_transmit(pi);
71   elapsed += pi->l;
72 }
73
74 void retransmit_start(void) {
75   Nmra n;
76
77   enco_nmra_idle(&n);
78   nmra_addchecksum(&n);
79   nmra_encodeforpic(&n, &linefill);
80
81   retransmit_something();
82   retransmit_something();
83   retransmit_something();
84 }
85
86 void retransmit_something(void) {
87   PerSpeedyTrans *spd;
88   RetransmitUrgentNode *urg;
89   RetransmitRelaxedNode *rlx;
90   int ix, DP;
91
92   DPRINTF1(retransmit,message,"xmit ");
93
94   for (ix=0, spd=speedies;
95        ix < SPEEDYCOUNT;
96        ix++, spd++) {
97     urg= spd->queue.head;
98     if (!urg) { DPRINTF2("-"); continue; }
99     if (elapsed - urg->u.when > RETRANSMIT_TIME_SIGNED_MAX)
100       { DPRINTF2("<"); continue; }
101
102     DPRINTF2("%*s spd%-2d", SPEEDYCOUNT-ix,"", ix);
103
104     /* found one to transmit: */
105     DLIST2_REMOVE(spd->queue,urg,u.queue);
106     if (++ix < SPEEDYCOUNT) {
107       DPRINTF2(" ->spd%-2d =%p",ix, urg);
108       urg->u.ix= ix;
109       urg->u.when= elapsed + spd->interval;
110       spd++;
111       DLIST2_APPEND(spd->queue,urg,u.queue);
112     } else {
113       DPRINTF2(" ->rlx   =%p", urg);
114       urg->u.ix= -1;
115     }
116     retransmit_this(&urg->pi);
117     return;
118   }
119
120   for (ix=0; ix<2; ix++) {
121     int qn= last_relaxed_qn ^ ix ^ 1;
122     rlx= relaxed[qn].head;
123     if (!rlx) { DPRINTF2("%d",qn); continue; }
124     
125     DPRINTF2("%-*s rlx%d        =%p", 2-ix,"", qn, rlx);
126
127     DLIST2_REMOVE(relaxed[qn],rlx,rr);
128     DLIST2_APPEND(relaxed[qn],rlx,rr);
129
130     last_relaxed_qn= qn;
131     retransmit_this(&rlx->pi);
132     return;
133   }
134
135   serial_transmit(&linefill);
136 }
137
138 static void relaxed_queue(int qn, RetransmitRelaxedNode *rn, Nmra *n,
139                           const char *debugwhat) {
140   int DP;
141   if (n) { nmra_addchecksum(n); nmra_encodeforpic(n, &rn->pi); }
142   DPRINTF1(retransmit,queue, "%s %p", debugwhat, rn);
143   if (DP) debug_message(&rn->pi, n);
144   DLIST2_PREPEND(relaxed[qn],rn,rr);
145 }
146 static void relaxed_cancel(int qn, RetransmitRelaxedNode *rlx,
147                            const char *debugwhat) {
148   if (debugwhat) DPRINTF(retransmit,queue, "%s %p\n", debugwhat, &rlx->pi);
149   DLIST2_REMOVE(relaxed[qn],rlx,rr);
150 }
151
152 void retransmit_relaxed_queue(RetransmitRelaxedNode *rn, Nmra *n) {
153   relaxed_queue(1,rn,n, "retransmit_relaxed_queue");
154 }
155 void retransmit_relaxed_cancel(RetransmitRelaxedNode *rlx) {
156   relaxed_cancel(1,rlx, "retransmit_relaxed_cancel");
157 }
158
159 static void urgent_queue(RetransmitUrgentNode *urg, Nmra *n,
160                          const char *debugwhat) {
161   relaxed_queue(0, &urg->u.relaxed, n, debugwhat);
162   urg->u.ix= 0;
163   urg->u.when= elapsed;
164   DLIST2_APPEND(speedies[0].queue,urg,u.queue);
165 }
166 static void urgent_cancel(RetransmitUrgentNode *urg,
167                           const char *debugwhat) {
168   if (urg->u.ix >= 0)
169     DLIST2_REMOVE(speedies[urg->u.ix].queue,urg,u.queue);
170   relaxed_cancel(0, &urg->u.relaxed, debugwhat);
171 }
172
173 void retransmit_urgent_queue(RetransmitUrgentNode *urg, Nmra *n) {
174   urgent_queue(urg,n, "retransmit_urgent_queue");
175 }
176 void retransmit_urgent_queue_relaxed(RetransmitUrgentNode *urg, Nmra *n){
177   relaxed_queue(0, &urg->u.relaxed, n, "retransmit_urgent_queue_relaxed");
178   urg->u.ix= -1;
179   urg->u.when= elapsed;
180 }
181 void retransmit_urgent_requeue(RetransmitUrgentNode *rn, Nmra *n) {
182   urgent_cancel(rn, 0);
183   urgent_queue(rn, n, "retransmit_urgent_requeue");
184 }
185 void retransmit_urgent_cancel(RetransmitUrgentNode *urg) {
186   urgent_cancel(urg, "retransmit_urgent_cancel");
187 }
188
189
190 void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
191   assert(objnum);
192   if (sta_state == Sta_Run || sta_state == Sta_Manual)
193     while (objnum--)
194       retransmit_something();
195   else
196     if (sta_state > Sta_Settling)
197       die("PIC sent NMRADONE in %s", stastatelist[sta_state]);
198 }