1 | #ifndef SUBSYSTEM
|
---|
2 | #define SUBSYSTEM
|
---|
3 |
|
---|
4 | #include "PeriodicAction.H"
|
---|
5 | #include "TCPListener.H"
|
---|
6 | #include "PeriodicAction.H"
|
---|
7 | #include "TCPSender.H"
|
---|
8 | #define TIMESTAMP_LEN 12
|
---|
9 | //%02.2d:%02.2d:%02.2d:%03.3d
|
---|
10 | //in Makefile#define MAXMSG 4096
|
---|
11 | /**
|
---|
12 | * Base class for MAGIC Subsystem's communication with CC
|
---|
13 | *
|
---|
14 | * It implements commandListener (see MAGIC-TDAS 00-07) as a TCPListener
|
---|
15 | * derived class, to be able to custom the behaviour by overriding its
|
---|
16 | * methods
|
---|
17 | *
|
---|
18 | * Missing properties: Special Report in a GenerateSpecialReport method, also
|
---|
19 | * a final implementation of CheckReportAcknowledge (CC sends back
|
---|
20 | * "RECV:timestamp", with timestamp the one extracted from subsystem
|
---|
21 | * report. So subsystem has to have a member lastReportTimestamp to compare).
|
---|
22 | * Timeout in CheckReportAcknowledge?????.
|
---|
23 | *
|
---|
24 | * @short Base class for MAGIC Subsystem's communication with CC
|
---|
25 | * @author Marc Casaldaliga
|
---|
26 | * @version 0.9
|
---|
27 | * @see TCPListener
|
---|
28 | */
|
---|
29 | class Subsystem: public TCPListener
|
---|
30 | {
|
---|
31 |
|
---|
32 | public:
|
---|
33 |
|
---|
34 | /**
|
---|
35 | * Set the string to be sent in the next report that will be sent to
|
---|
36 | * CC (with timestamp but without protocol specific item,
|
---|
37 | * e.g. trailing \n). The timestamp is the data one, the time when
|
---|
38 | * data was taken (the relevant for analysis), nothing to do with the
|
---|
39 | * the time the report will be sent.
|
---|
40 | *
|
---|
41 | * It takes care internally of suspending and resuming communications
|
---|
42 | * not to send something is being modified etc
|
---|
43 | *
|
---|
44 | * @param report CString with pure report (without "\n" ...)
|
---|
45 | */
|
---|
46 | void SetReportString(char * report);
|
---|
47 |
|
---|
48 | /**
|
---|
49 | * Class unique constructor with the parameters which specify
|
---|
50 | * Subsystem configuration.
|
---|
51 | *
|
---|
52 | * @param portCommandListener TCP/IP port Subsystem will open to
|
---|
53 | * listen to cc commands
|
---|
54 | *
|
---|
55 | * @param reportPeriod Aproximate (+- 500ms) time in microsec,
|
---|
56 | * between each report is sent to CC
|
---|
57 | *
|
---|
58 | * @param ccName C string with CC machine name
|
---|
59 | *
|
---|
60 | * @param portReportListener TCP/IP port opened in CC which Subsystem
|
---|
61 | * will contact to send reports
|
---|
62 | *
|
---|
63 | * @param maxTimeoutCount_. Times subsystem tries to reconnect CC
|
---|
64 | * (with reportPeriod) periodicity, before it considers CC not
|
---|
65 | * available. After this count is reached Subsystem has to react some
|
---|
66 | * way (parking itself, ...). This is done by
|
---|
67 | * Subsystem::HandleConnectionTimeoutIsOver
|
---|
68 | *
|
---|
69 | * @param specialReportOnStartup When connection with CC is
|
---|
70 | * stablished for first time after a Subsystem startup a special
|
---|
71 | * report to CC with subsystem setup must be sent to ensure any setup
|
---|
72 | * changes (which may have happened while CC was down) are
|
---|
73 | * recorded. This C string only contains report content without any
|
---|
74 | * protocol dependent character
|
---|
75 | *
|
---|
76 | * @see #HandleConnectionTimeoutIsOver
|
---|
77 | *
|
---|
78 | */
|
---|
79 | Subsystem (unsigned short int portCommandListener, unsigned long int
|
---|
80 | reportPeriod, char * ccName, unsigned short int
|
---|
81 | portReportListener, unsigned short int maxTimeoutCount_, char *
|
---|
82 | specialReportOnStartup );
|
---|
83 |
|
---|
84 | /**
|
---|
85 | * Send (immediately) a special report which a part from
|
---|
86 | * protocol specific items (e.g. trailing \n and special report
|
---|
87 | * identifier) contains the argument specialReport
|
---|
88 | *
|
---|
89 | * ??? timestamp ????
|
---|
90 | *
|
---|
91 | * It takes care internally of suspending and resuming communications
|
---|
92 | * not to send something is being modified etc
|
---|
93 | *
|
---|
94 | * @param specialReport CString with pure special report (without
|
---|
95 | * "\n" ...)
|
---|
96 | *
|
---|
97 | * @return Returns whether sending will be succesful (true) or not
|
---|
98 | * (false)
|
---|
99 | */
|
---|
100 | bool SendSpecialReportContaining(char * specialReport);
|
---|
101 |
|
---|
102 | /**
|
---|
103 | * Blocks main thread until Subsystem::Shutdown is called
|
---|
104 | */
|
---|
105 | void WaitingForShutdown();
|
---|
106 |
|
---|
107 | /**
|
---|
108 | * Subsystem communications will be shutdown definitely. Call this
|
---|
109 | * inside ProcessCmd or HandleConnectionTimeoutIsOver when your
|
---|
110 | * subsystem has to be stopped. If you only want to go standalone but
|
---|
111 | * still in contact with CC, you have to Ulock it but not this.
|
---|
112 | *
|
---|
113 | * This call unblocks WaitingForShutdown in main, so your subsystem
|
---|
114 | * application can finish.
|
---|
115 | */
|
---|
116 | void Shutdown();
|
---|
117 |
|
---|
118 | protected:
|
---|
119 | /**
|
---|
120 | * Field with the report that will be sent to CC (with timestamp but
|
---|
121 | * without protocol specific item, e.g. trailing \n)
|
---|
122 | *
|
---|
123 | * To be modified only within GenerateReport
|
---|
124 | */
|
---|
125 | char reportString[MAXMSG];
|
---|
126 |
|
---|
127 | /** To be overriden. It has to do all the job of interpreting CC
|
---|
128 | * commands: (not the ones
|
---|
129 | * regarding starting connection, locking ...) but the ones for the
|
---|
130 | * subsystem function (This way we separate the protocol dependent
|
---|
131 | * stuff).
|
---|
132 | *
|
---|
133 | * Compares Subsystem::ccCmd with known commands from cc and executes
|
---|
134 | * the appropiate function
|
---|
135 | *
|
---|
136 | * This method is automatically called when a command from cc is
|
---|
137 | * received, after checking it is not a communication/locking command
|
---|
138 | *
|
---|
139 | * If receiving a nonsense command call to ResetConnectionToCC()
|
---|
140 | * (Network partner it's not -a properly working- CC). In principle
|
---|
141 | * this will close and open again, but let's leave it this way so that
|
---|
142 | * it is not protocol dependent
|
---|
143 | *
|
---|
144 | * @param ccCmd CString with pure CC command (without "\n" ...)
|
---|
145 | */
|
---|
146 | virtual void ProcessCmd(char *ccCmd);
|
---|
147 |
|
---|
148 | /** GenerateReport (to be overriden) This next method is automatically
|
---|
149 | * called before sending a report.
|
---|
150 | *
|
---|
151 | * According to state and data this should write
|
---|
152 | * Subsystem::reportString (it
|
---|
153 | * should include the timestamp of the data sent, but without any
|
---|
154 | * trailing \n--this is part of the protocol)
|
---|
155 | *
|
---|
156 | * After it, this Subsystem::reportString plus any protocol dependent
|
---|
157 | * thing is sent. This GenerateReport and send is periodically
|
---|
158 | * repeated with reportPeriod
|
---|
159 | *
|
---|
160 | * Alternatively, one may leave GenerateReport empty and from outside
|
---|
161 | * call to Subsystem::SetReportString when hardware info is updated
|
---|
162 | * (probably what one what like to do).
|
---|
163 | */
|
---|
164 | virtual void GenerateReport();
|
---|
165 |
|
---|
166 | /** HandleConnectionTimeoutIsOver. Does what the subsystem is suposed
|
---|
167 | * to do when it has lost definitely connection to CC. To be
|
---|
168 | * overriden.
|
---|
169 | *
|
---|
170 | * After Subsystem::maxTimeoutCount times of reconnection tries CC is
|
---|
171 | * considered not available. Subsystem has to react some way (parking
|
---|
172 | * itself, ... ) depending on its autonomy. This is done by
|
---|
173 | * overriding this method with the desired behaviour.
|
---|
174 | *
|
---|
175 | * After HandleConnectionTimeoutIsOver is done Subsystem will listen
|
---|
176 | * to CC again and start all communication process.
|
---|
177 | *
|
---|
178 | * see #maxTimeoutCount
|
---|
179 | */
|
---|
180 | virtual void HandleConnectionTimeoutIsOver();
|
---|
181 |
|
---|
182 | /** SuspendComm. Suspend communication threads
|
---|
183 | *
|
---|
184 | * To prevent Subsystem to access its resources (e.g. send
|
---|
185 | * reportString) when we are about to access them externally (fill
|
---|
186 | * reportString with actual data), one can call to this method and
|
---|
187 | * suspend subsystem activity.
|
---|
188 | * To resume it call to Subsystem::ResumeComm.
|
---|
189 | *
|
---|
190 | * Always paired with a ResumeComm.
|
---|
191 | *
|
---|
192 | * If Subsystem is at that time accessing the resources, SuspendComm
|
---|
193 | * will wait for them to be released and then will lock them.
|
---|
194 | *
|
---|
195 | * @see #ResumeComm
|
---|
196 | *
|
---|
197 | */
|
---|
198 | void SuspendComm();
|
---|
199 |
|
---|
200 | /** ResumeComm. Resume communication threads
|
---|
201 | *
|
---|
202 | * After calling SuspendComm() and having access to Subsystem
|
---|
203 | * resources (e.g. fill reportString with actual data) allow
|
---|
204 | * Subsystem to access them again and resume it's activity. we are
|
---|
205 | * about to access them externally (fill reportString with actual
|
---|
206 | * data), one can call to this method and suspend subsystem activity.
|
---|
207 | *
|
---|
208 | * @see #SuspendComm
|
---|
209 | *
|
---|
210 | */
|
---|
211 | void ResumeComm();
|
---|
212 |
|
---|
213 | /**
|
---|
214 | * Resets communication to CC, to be used when a nonsense command
|
---|
215 | * arrives from CC
|
---|
216 | * @see #ProcessCmd
|
---|
217 | */
|
---|
218 | void ResetConnectionToCC();
|
---|
219 |
|
---|
220 |
|
---|
221 |
|
---|
222 | private:
|
---|
223 | /**
|
---|
224 | * C string with CC machine name
|
---|
225 | */
|
---|
226 | char* ccName;
|
---|
227 | /**
|
---|
228 | * Aproximate (+- 500ms) time in microsec, between each report is sent
|
---|
229 | * to CC
|
---|
230 | */
|
---|
231 | unsigned long int reportPeriod;
|
---|
232 |
|
---|
233 | unsigned short int portCommandListener;
|
---|
234 | unsigned short int portReportListener;
|
---|
235 |
|
---|
236 | //we implement commandListener as a TCPListener derived class, to be
|
---|
237 | //able to custom the behaviour by overriding it's methods, namely
|
---|
238 | //process
|
---|
239 |
|
---|
240 | /* maxTimeoutCount. Times subsystem tries to reconnect CC (with reportPeriod)
|
---|
241 | * periodicity, before it considers CC not available.
|
---|
242 | *
|
---|
243 | * After this count is reached Subsystem has to react some way
|
---|
244 | * (parking itself, ...). This is done by
|
---|
245 | * Subsystem::HandleConnectionTimeoutIsOver
|
---|
246 | *
|
---|
247 | * @see #HandleConnectionTimeoutIsOver
|
---|
248 | *
|
---|
249 | */
|
---|
250 |
|
---|
251 | short int maxTimeoutCount;
|
---|
252 |
|
---|
253 |
|
---|
254 | bool locked;
|
---|
255 | bool reporting;
|
---|
256 | pthread_mutex_t mutex4reporting;
|
---|
257 | inline bool Reporting(){
|
---|
258 | pthread_mutex_lock(&mutex4reporting);
|
---|
259 | bool ret=reporting;
|
---|
260 | pthread_mutex_unlock(&mutex4reporting);
|
---|
261 | return ret;
|
---|
262 | }
|
---|
263 | inline void SetReporting(bool trueValue)
|
---|
264 | {
|
---|
265 | pthread_mutex_lock(&mutex4reporting);
|
---|
266 | reporting=trueValue;
|
---|
267 | pthread_mutex_unlock(&mutex4reporting);
|
---|
268 | }
|
---|
269 |
|
---|
270 | //we implement reportSender as an instance of class TCPSender
|
---|
271 | TCPSender reportSender;
|
---|
272 | //reporting and trying connections to cc are implemented as
|
---|
273 | //PeriodicActions
|
---|
274 |
|
---|
275 | pthread_mutex_t mutex4report;
|
---|
276 | virtual void process();
|
---|
277 | virtual void ClosingChannel();
|
---|
278 |
|
---|
279 | bool SendReport();
|
---|
280 | void CheckReportAcknowledge();
|
---|
281 | //to be able to checkreportacknowledge on has to have the timestamp of
|
---|
282 | //the last report sent
|
---|
283 | char lastTimeStamp[TIMESTAMP_LEN];
|
---|
284 | void ExtractTimeStampFromLastReportTo(char *);
|
---|
285 | pthread_t reportThread;
|
---|
286 | inline static void * pthread_ReportingAndCheckingLoop(void* self)
|
---|
287 | {
|
---|
288 | return (void *) ( ((Subsystem* )self)->ReportingAndCheckingLoop() );
|
---|
289 | }
|
---|
290 |
|
---|
291 |
|
---|
292 | void * ReportingAndCheckingLoop();
|
---|
293 |
|
---|
294 | bool acknowledgeReceivedForLastReport;
|
---|
295 | short int timeoutCount;
|
---|
296 | void Lock();
|
---|
297 | void ULock();
|
---|
298 |
|
---|
299 | };
|
---|
300 |
|
---|
301 | #endif
|
---|