chiark / gitweb /
Merge and end branch-hostside-wip-2008-01-25 PROPERLY; cvs up -j branch-hostside...
[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 the single relaxed queue.
37  *  There is one queue for each speady retransmission; messages are on
38  *  it in chronological order of dueness.
39  */
40
41 #include "realtime.h"
42 #include "nmra.h"
43 #include "retransmit-table.h"
44
45 #define RETRANSMIT_TIME_SIGNED_MAX ((~(Retransmit__Time)0) >> 1)
46
47 static PicInsn linefill;
48
49 static DLIST2_HEAD(RetransmitRelaxedNode) relaxed;
50 static Retransmit__Time elapsed;
51 static PerSpeedyTrans speedies[] = SPEEDIESINIT;
52
53 static void retransmit_this(const PicInsn *pi) {
54   serial_transmit(pi);
55   elapsed++;
56 }
57
58 void retransmit_start(void) {
59   Nmra n;
60
61   enco_nmra_idle(&n);
62   nmra_addchecksum(&n);
63   nmra_encodeforpic(&n, &linefill);
64
65   retransmit_something();
66   retransmit_something();
67   retransmit_something();
68 }
69
70 void retransmit_something(void) {
71   PerSpeedyTrans *spd;
72   RetransmitUrgentNode *urg;
73   RetransmitRelaxedNode *rlx;
74   int ix;
75   
76   for (ix=0, spd=speedies;
77        ix < SPEEDYCOUNT;
78        ix++, spd++) {
79     urg= spd->queue.head;
80     if (!urg) continue;
81     if (elapsed - urg->u.when > RETRANSMIT_TIME_SIGNED_MAX) continue;
82
83     /* found one to transmit: */
84     DLIST2_REMOVE(spd->queue,urg,u.queue);
85     if (++ix < SPEEDYCOUNT) {
86       urg->u.ix= ix;
87       urg->u.when= elapsed + spd->interval;
88       spd++;
89       DLIST2_APPEND(spd->queue,urg,u.queue);
90     } else {
91       urg->u.ix= -1;
92     }
93     retransmit_this(&urg->pi);
94     return;
95   }
96
97   rlx= relaxed.head;
98   if (rlx) {
99     DLIST2_REMOVE(relaxed,rlx,rr);
100     DLIST2_APPEND(relaxed,rlx,rr);
101     retransmit_this(&rlx->pi);
102     return;
103   }
104
105   serial_transmit(&linefill);
106 }
107
108 void retransmit_relaxed_queue(RetransmitRelaxedNode *rn, Nmra *n) {
109   if (n) { nmra_addchecksum(n); nmra_encodeforpic(n, &rn->pi); }
110   DLIST2_PREPEND(relaxed,rn,rr);
111 }
112 void retransmit_relaxed_requeue(RetransmitRelaxedNode *rn, Nmra *n) {
113   retransmit_relaxed_cancel(rn);
114   retransmit_relaxed_queue(rn, n);
115 }
116 void retransmit_relaxed_cancel(RetransmitRelaxedNode *rlx) {
117   DLIST2_REMOVE(relaxed,rlx,rr);
118 }
119
120 void retransmit_urgent_queue(RetransmitUrgentNode *urg, Nmra *n) {
121   retransmit_relaxed_queue(&urg->u.relaxed, n);
122   urg->u.ix= 0;
123   urg->u.when= elapsed;
124   DLIST2_APPEND(speedies[0].queue,urg,u.queue);
125 }
126 void retransmit_urgent_queue_relaxed(RetransmitUrgentNode *urg, Nmra *n){
127   retransmit_relaxed_queue(&urg->u.relaxed, n);
128   urg->u.ix= -1;
129   urg->u.when= elapsed;
130 }
131 void retransmit_urgent_requeue(RetransmitUrgentNode *rn, Nmra *n) {
132   retransmit_urgent_cancel(rn);
133   retransmit_urgent_queue(rn, n);
134 }
135 void retransmit_urgent_cancel(RetransmitUrgentNode *urg) {
136   if (urg->u.ix >= 0)
137     DLIST2_REMOVE(speedies[urg->u.ix].queue,urg,u.queue);
138   retransmit_relaxed_cancel(&urg->u.relaxed);
139 }