/*
+ * realtime
* nmra retransmission
*/
-#include "hostside.h"
+#include "realtime.h"
-void retransmit_queue(RetransmitNode *rn) {
+/*
+ * There are two kinds of messages: urgent and relaxed.
+ *
+ * Urgent messages may be due for speedy transmission. The due urgent
+ * message with the highest priority is always transmitted as soon as
+ * a slot is available. This is known as `speedy transmission'.
+ *
+ * When no urgent messages are due for speedy transmission, messages
+ * (urgent or relaxed) are transmitted in a round-robin fashion. This
+ * round-robin transmission is completely independent of the speedy
+ * transmission.
+ *
+ * Each urgent message is due for speedy transmission as follows:
+ * - When it is first queued and has not yet been
+ * speedily transmitted:
+ * immediately due, with maximum priority
+ * - Following each speedy transmission:
+ * due after an interval since the previous
+ * transmission; this interval increases exponentially
+ * for each transmission
+ * with priority which decreases with later transmissions
+ * until it has been speedily transmitted a certain number of times
+ * - Thereafter:
+ * no longer ever due; subject to round-robin transmission only.
+ * Intervals are measured in messages regardless of length.
+ */
+/*
+ * Implementation:
+ * All messages are on the single relaxed queue.
+ * There is one queue for each speady retransmission; messages are on
+ * it in chronological order of dueness.
+ */
+
+#include "realtime.h"
+#include "nmra.h"
+#include "retransmit-table.h"
+
+#define RETRANSMIT_TIME_SIGNED_MAX ((~(Retransmit__Time)0) >> 1)
+
+static PicInsn linefill;
+
+static DLIST2_HEAD(RetransmitRelaxedNode) relaxed;
+static Retransmit__Time elapsed;
+static PerSpeedyTrans speedies[] = SPEEDIESINIT;
+
+static void retransmit_this(const PicInsn *pi) {
+ serial_transmit(pi);
+ elapsed++;
+}
+
+void retransmit_start(void) {
+ Nmra n;
+
+ enco_nmra_idle(&n);
+ nmra_addchecksum(&n);
+ nmra_encodeforpic(&n, &linefill);
+
+ retransmit_something();
+ retransmit_something();
+ retransmit_something();
}
-void retransmit_cancel(RetransmitNode *rn) {
+void retransmit_something(void) {
+ PerSpeedyTrans *spd;
+ RetransmitUrgentNode *urg;
+ RetransmitRelaxedNode *rlx;
+ int ix;
+
+ for (ix=0, spd=speedies;
+ ix < SPEEDYCOUNT;
+ ix++, spd++) {
+ urg= spd->queue.head;
+ if (!urg) continue;
+ if (elapsed - urg->u.when > RETRANSMIT_TIME_SIGNED_MAX) continue;
+
+ /* found one to transmit: */
+ DLIST2_REMOVE(spd->queue,urg,u.queue);
+ if (++ix < SPEEDYCOUNT) {
+ urg->u.ix= ix;
+ urg->u.when= elapsed + spd->interval;
+ spd++;
+ DLIST2_APPEND(spd->queue,urg,u.queue);
+ } else {
+ urg->u.ix= -1;
+ }
+ retransmit_this(&urg->pi);
+ return;
+ }
+
+ rlx= relaxed.head;
+ if (rlx) {
+ DLIST2_REMOVE(relaxed,rlx,rr);
+ DLIST2_APPEND(relaxed,rlx,rr);
+ retransmit_this(&rlx->pi);
+ return;
+ }
+
+ serial_transmit(&linefill);
+}
+
+void retransmit_relaxed_queue(RetransmitRelaxedNode *rn, Nmra *n) {
+ if (n) { nmra_addchecksum(n); nmra_encodeforpic(n, &rn->pi); }
+ DLIST2_PREPEND(relaxed,rn,rr);
+}
+void retransmit_relaxed_requeue(RetransmitRelaxedNode *rn, Nmra *n) {
+ retransmit_relaxed_cancel(rn);
+ retransmit_relaxed_queue(rn, n);
+}
+void retransmit_relaxed_cancel(RetransmitRelaxedNode *rlx) {
+ DLIST2_REMOVE(relaxed,rlx,rr);
+}
+
+void retransmit_urgent_queue(RetransmitUrgentNode *urg, Nmra *n) {
+ retransmit_relaxed_queue(&urg->u.relaxed, n);
+ urg->u.ix= 0;
+ urg->u.when= elapsed;
+ DLIST2_APPEND(speedies[0].queue,urg,u.queue);
+}
+void retransmit_urgent_queue_relaxed(RetransmitUrgentNode *urg, Nmra *n){
+ retransmit_relaxed_queue(&urg->u.relaxed, n);
+ urg->u.ix= -1;
+ urg->u.when= elapsed;
+}
+void retransmit_urgent_requeue(RetransmitUrgentNode *rn, Nmra *n) {
+ retransmit_urgent_cancel(rn);
+ retransmit_urgent_queue(rn, n);
+}
+void retransmit_urgent_cancel(RetransmitUrgentNode *urg) {
+ if (urg->u.ix >= 0)
+ DLIST2_REMOVE(speedies[urg->u.ix].queue,urg,u.queue);
+ retransmit_relaxed_cancel(&urg->u.relaxed);
}