From 9aad2407d5d138e29cce732a6a9fe8fb5e1b1331 Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 5 Jun 2006 00:37:47 +0000 Subject: [PATCH] new nmra retransmit alg designed impln wip; some header file cleanups; send warning re countermands from safety; glue detection to safety wip --- hostside/realtime.h | 31 ++++++++++-- hostside/retransmit.c | 111 ++++++++++++++++++++++++++++++++++++++++-- hostside/safety.c | 8 +-- hostside/safety.h | 7 +-- hostside/startup.c | 14 ++++-- 5 files changed, 150 insertions(+), 21 deletions(-) diff --git a/hostside/realtime.h b/hostside/realtime.h index 473f415..2aa2b3b 100644 --- a/hostside/realtime.h +++ b/hostside/realtime.h @@ -1,5 +1,5 @@ /* - * declarations for multiplexer daemon + * declarations for realtime daemon */ #ifndef REALTIME_H @@ -17,10 +17,28 @@ #include #include +/*---------- from retransmit.c ----------*/ + typedef struct RetransmitNode RetransmitNode; +struct RetransmitNode { + /* set by caller: */ + PicInsn pi; + /* internal: */ + unsigned long speedyduetime; + struct { RetransmitNode *back, *next; } relaxed, speedy; +}; + +void retransmit_queue(RetransmitNode *rn); +void retransmit_cancel(RetransmitNode *rn); + +/*---------- global variables, in realtime.c ----------*/ extern CommandInput cmdi; +#define UPO (&(cmdi.out)) + +/*---------- from/for startup.c ----------*/ + typedef enum { /* sta_toev ping_toev */ Sta_Flush, /* R 300 I ? */ Sta_Off, /* I ? I ? */ @@ -31,16 +49,19 @@ typedef enum { /* sta_toev ping_toev */ Sta_Run /* I ? R set */ } StartupState; -#define UPO (&(cmdi.out)) +void sta_startup(void); +void serial_moredata(PicInsn *buf); + +extern StartupState sta_state; + +/*---------- from/for realtime.c ----------*/ void oupicio(const char *dirn, const PicInsnInfo *pii, int objnum); void ouhex(const char *word, const Byte *command, int length); -void serial_moredata(PicInsn *buf); void serial_transmit(const PicInsn *pi); -void sta_startup(void); -extern StartupState sta_state; +/*---------- tbi ----------*/ void abandon_run(void); diff --git a/hostside/retransmit.c b/hostside/retransmit.c index 54c4fda..9306209 100644 --- a/hostside/retransmit.c +++ b/hostside/retransmit.c @@ -1,11 +1,116 @@ /* + * 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. + */ + +#define RETRANS_SPEEDYCOUNT 20 +#define RETRANS_SPEEDYEXP 1.3 + +#define HALFWAY ((~(Retransmit__Time)0) >> 1) + +typedef struct { + DLIST2_HEAD(RetransmitUrgentNode) queue; /* msgs transmitted ix times */ + Retransmit__Time interval; /* interval after this retransmission */ +} PerSpeedyTrans; + +static const PicInsn linefill= { { 0xff, 0x7f }, 2 }; + +static DLIST2_HEAD(RetransmitRelaxedNode) relaxed; +static elapsed; +static PerSpeedyTrans speedies[RETRANS_SPEEDYCOUNT]; + +static void retransmit_this(const PicInsn *pi) { + serial_transmit(pi); + elapsed++; } -void retransmit_cancel(RetransmitNode *rn) { +static void retransmit_something() { + PerSpeedyTrans *spd; + RetransmitUrgentNode *urg; + RetransmitRelaxedNode *rlx; + + for (ix=0, spd=speedies; + ix < RETRANS_SPEEDYCOUNT; + ix++, spd++) { + urg= spd->head; + if (!urg) continue; + if (elapsed - urg->u.when > HALFWAY) continue; + + /* found one to transmit: */ + DLIST2_REMOVE(spd->queue,urg,u.queue); + if (++ix < RETRANS_SPEEDYCOUNT) { + urg->u.ix= ix; + urg->u.when= elapsed + spd->interval; + spd++; + DLIST2_APPEND(spd->queue,urg,u.queue); + } else { + urg->d.urgent_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 *rlx) { + DLIST2_PREPEND(relaxed,rn,rr); +} +void retransmit_relaxed_cancel(RetransmitRelaxedNode *rlx) { + DLIST2_REMOVE(relaxed,rlx,rr); +} + +void retransmit_urgent_queue(RetransmitUrgentNode *urg) { + urg->u.ix= 0; + urg->u.when= elapsed; + DLIST2_APPEND(speedies[0].queue,urg,u.queue); + retransmit_relaxed_queue(&urg->u.relaxed); +} +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); } diff --git a/hostside/safety.c b/hostside/safety.c index d9b48ae..41c1618 100644 --- a/hostside/safety.c +++ b/hostside/safety.c @@ -283,6 +283,8 @@ void safety_requestspeed(TrainNum tran, long newspeed) { logmsg(ec, tran, NOTA(Segment), "countermanded motion start"); } setspeed(tran, oldspeed); + oprintf(UPO, "countermanded %s %l %l\n", + info_trains[tran].pname, oldspeed, newspeed); ec= lay_train(tran, 0); if (ec) safety_panic(tran, NOTA(Segment), "countermanding" @@ -292,9 +294,3 @@ void safety_requestspeed(TrainNum tran, long newspeed) { setspeed(tran, newspeed); } - - -int main(void) { - printf("%d\n",(int)sizeof(State)); - return 0; -} diff --git a/hostside/safety.h b/hostside/safety.h index 2408248..26788d2 100644 --- a/hostside/safety.h +++ b/hostside/safety.h @@ -78,17 +78,18 @@ ErrorCode safety_problem(TrainNum tran, SegmentNum segn, const char *fmt,...) void safety_emergencystop(TrainNum); /* Callable directly in response to application command. */ +void safety_setdirection(TrainNum tran, int sense_fixme_define_this_properly); void safety_requestspeed(TrainNum tran, long newspeed); /* To be called only by the speed manager, thus indirectly from * user request. * Will result in a call to speedmanager_speedchange_notify (and of - * course to actual_setspeed. Speed manager must apply accel/decel + * course to actual_setspeed). Speed manager must apply accel/decel * curve so that if safety.c agrees the command, the actual speed of * the train changes straight away (at least for decel). */ void safety_notify_detection(SegmentNum segn); - /* To be called by actual.c when new train detection occurs. */ + /* Called by startup.c when new train detection occurs in state Run. */ /*========== speedmgr.c ==========*/ @@ -102,7 +103,7 @@ void speedmanager_speedchange_notify(TrainNum tran); * repeating the NMRA commands and redacting detection information. * * In general, when State information is shared between actual.c - * and safety.c, actual.c is responsible for modifying State, and + * and safety.c, safety.c is responsible for modifying State, and * will then call an actual_... function to notify the change. */ diff --git a/hostside/startup.c b/hostside/startup.c index 64c53d3..8a5b98b 100644 --- a/hostside/startup.c +++ b/hostside/startup.c @@ -185,6 +185,16 @@ void on_pic_hello(const PicInsnInfo *pii, const PicInsn *pi, int objnum) void on_pic_aaargh(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { abort(); } +void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int segn) { + if (segn >= NUM_SEGMENTS) die("PIC sent detect @#%d out of range",segn); + if (sta_state < Sta_Run) { + oprintf(UPO, "warning fixme ignored non-Run detection @%s\n", + info_segments[segn].pname); + return; + } + safety_notify_detection(segn); +} + /*---------- fixme move these to where they want to go ----------*/ void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { @@ -196,10 +206,6 @@ void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { void on_pic_detect0(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { } -void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { - /* fixme do something here */ -} - void abandon_run(void) { /* fixme do something here */ } -- 2.30.2