chiark / gitweb /
can fit 139 lines on an atp -B page
[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 speady 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 retransmit_this(const PicInsn *pi) {
58   serial_transmit(pi);
59   elapsed++;
60 }
61
62 void retransmit_start(void) {
63   Nmra n;
64
65   enco_nmra_idle(&n);
66   nmra_addchecksum(&n);
67   nmra_encodeforpic(&n, &linefill);
68
69   retransmit_something();
70   retransmit_something();
71   retransmit_something();
72 }
73
74 void retransmit_something(void) {
75   PerSpeedyTrans *spd;
76   RetransmitUrgentNode *urg;
77   RetransmitRelaxedNode *rlx;
78   int ix;
79   
80   for (ix=0, spd=speedies;
81        ix < SPEEDYCOUNT;
82        ix++, spd++) {
83     urg= spd->queue.head;
84     if (!urg) continue;
85     if (elapsed - urg->u.when > RETRANSMIT_TIME_SIGNED_MAX) continue;
86
87     /* found one to transmit: */
88     DLIST2_REMOVE(spd->queue,urg,u.queue);
89     if (++ix < SPEEDYCOUNT) {
90       urg->u.ix= ix;
91       urg->u.when= elapsed + spd->interval;
92       spd++;
93       DLIST2_APPEND(spd->queue,urg,u.queue);
94     } else {
95       urg->u.ix= -1;
96     }
97     retransmit_this(&urg->pi);
98     return;
99   }
100
101   for (ix=0; ix<2; ix++) {
102     int qn= last_relaxed_qn ^ ix ^ 1;
103     rlx= relaxed[qn].head;
104     if (!rlx) continue;
105     
106     DLIST2_REMOVE(relaxed[qn],rlx,rr);
107     DLIST2_APPEND(relaxed[qn],rlx,rr);
108     retransmit_this(&rlx->pi);
109     last_relaxed_qn= qn;
110     return;
111   }
112
113   serial_transmit(&linefill);
114 }
115
116 static void relaxed_queue(int qn, RetransmitRelaxedNode *rn, Nmra *n) {
117   if (n) { nmra_addchecksum(n); nmra_encodeforpic(n, &rn->pi); }
118   DLIST2_PREPEND(relaxed[qn],rn,rr);
119 }
120 static void relaxed_cancel(int qn, RetransmitRelaxedNode *rlx) {
121   DLIST2_REMOVE(relaxed[qn],rlx,rr);
122 }
123
124 void retransmit_relaxed_queue(RetransmitRelaxedNode *rn, Nmra *n) {
125   relaxed_queue(1,rn,n);
126 }
127 void retransmit_relaxed_cancel(RetransmitRelaxedNode *rlx) {
128   relaxed_cancel(1,rlx);
129 }
130
131 void retransmit_urgent_queue(RetransmitUrgentNode *urg, Nmra *n) {
132   relaxed_queue(0, &urg->u.relaxed, n);
133   urg->u.ix= 0;
134   urg->u.when= elapsed;
135   DLIST2_APPEND(speedies[0].queue,urg,u.queue);
136 }
137 void retransmit_urgent_queue_relaxed(RetransmitUrgentNode *urg, Nmra *n){
138   relaxed_queue(0, &urg->u.relaxed, n);
139   urg->u.ix= -1;
140   urg->u.when= elapsed;
141 }
142 void retransmit_urgent_requeue(RetransmitUrgentNode *rn, Nmra *n) {
143   retransmit_urgent_cancel(rn);
144   retransmit_urgent_queue(rn, n);
145 }
146 void retransmit_urgent_cancel(RetransmitUrgentNode *urg) {
147   if (urg->u.ix >= 0)
148     DLIST2_REMOVE(speedies[urg->u.ix].queue,urg,u.queue);
149   relaxed_cancel(0, &urg->u.relaxed);
150 }
151
152
153 void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
154   assert(objnum);
155   if (sta_state == Sta_Run || sta_state == Sta_Manual)
156     while (objnum--)
157       retransmit_something();
158   else
159     if (sta_state > Sta_Settling)
160       die("PIC sent NMRADONE in %s", stastatelist[sta_state]);
161 }