source: trunk/MagicSoft/Control/SubsystemIO/Subsystem.plain.cxx@ 4485

Last change on this file since 4485 was 1054, checked in by casaldaliga, 23 years ago
changed .H to .hxx in includes to work with new naming
File size: 11.6 KB
Line 
1/* Copyright (C) 2001 Marc Casaldaliga Albisu <casaldaliga@ifae.es>
2================================================================
3
4 This code is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This code is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with Emacs (which is required to make this stuff work); if
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.
18==================================================================
19*/
20
21//it is a good idea to encapsulate all the configuration file dependence in one a wrapper class SubFormatSubsystem, and derive from it
22//#include "SubFormatSubsystem.hxx"
23#include "Subsystem.hxx"
24#include "PeriodicAction.hxx"
25#include "TCPListener.hxx"
26#include "TCPSender.hxx"
27#include "IONotifier.hxx"
28#include <string>
29//for signals/slots (Callbacks in C++, see http://libsigc.sourceforge.net/)
30#include <sigc++/signal_system.h>
31//libsigc must be installed
32#include <stdio.h>
33using namespace SigC;
34
35#include <unistd.h> //for usleep
36#include <sys/time.h>
37#include <sys/types.h>
38Subsystem::Subsystem (unsigned short int portCommandListener, unsigned long int reportPeriod, char * ccName, unsigned short int portReportListener , unsigned short int maxTimeoutCount_, char * specialReportOnStartup )
39 :
40 TCPListener(portCommandListener), reportSender(ccName,portReportListener), locked(false), reporting(false),maxTimeoutCount(maxTimeoutCount_),reportPeriod(reportPeriod)
41 {
42//the behaviour is the following: commandListener has been started as a being derived from TCPListener. When connection from cc is opened commands are processed in this->process()
43//when REPOR arrives reportSender(TCPSender) here tries to connect reportListener in CC. When this happens will start a periodic reporting
44
45
46//by now
47//demo report:
48 strcpy(reportString,"standby:11:44:20:11:01:6:34:12:6.0:6.1:6.05:11:01:36:34:12:10.6:6.0:6.0:00:00:30.0:00:00:4.6:0.1:0.05:0.004:0.0:0.001:0.003:guiding:0.1deg:on:3.1Hz:0.09deg:J2000:Mkn421:messagefromthedrive:");
49 pthread_mutex_init(&mutex4report,NULL);
50 pthread_mutex_init(&mutex4reporting,NULL);
51 }
52void * Subsystem::ReportingAndCheckingLoop()
53{
54#ifdef DEBUG
55 printf("Subsystem: ReportingAndChecking Thread created\n");
56
57#endif
58 timeoutCount=0;
59 acknowledgeReceivedForLastReport=true;
60
61 while(!reportSender.isTrialToConnectSuccesful()){
62#ifdef DEBUG
63 printf("Subsystem: retrying in %d usec\n",reportPeriod);
64#endif
65 usleep(reportPeriod);
66 }
67 fd_set read_fd_set;
68 FD_ZERO (&read_fd_set);
69 FD_SET(reportSender.IODescriptor(), &read_fd_set);
70 struct timeval tv;
71 tv.tv_sec = 0;
72 tv.tv_usec = (reportPeriod);
73 while(Reporting())
74 {
75 /* Block until input arrives, which is ack. */
76
77 if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, &tv) < 0)
78 {
79 perror("Subsystem: select");
80 exit (EXIT_FAILURE);
81 }
82
83 if (FD_ISSET(reportSender.IODescriptor(), &read_fd_set))
84 {
85//input arrived, which is the ack
86#ifdef DEBUG
87 printf("Subsystem: ack received\n");
88#endif
89 CheckReportAcknowledge();
90 FD_SET (reportSender.IODescriptor(), &read_fd_set);
91 continue;
92 //in linux, tv after select represents the time not slept, so we feed it again to select to complete the reportPeriod
93 }else{
94 //input didn't arrrive so it's time to report
95 if(!SendReport()){
96 //sending was not succesfull
97
98 //ResetConnectionToCC();
99 if(locked){
100 ULock();
101 }
102 reportSender.CloseConnection();
103
104#ifdef DEBUG
105 printf("Subsystem: ReportingAndChecking Thread exited on ack checking \n");
106#endif
107//TO DO!!!!!!!!!!!!!
108// TCPListener::ClosingChannel();
109
110 break;
111
112
113 }
114
115 FD_SET (reportSender.IODescriptor(), &read_fd_set);
116 tv.tv_sec = 0;
117 tv.tv_usec = reportPeriod;
118 }
119
120 }
121//if program reaches here is because it hasn't been able to report correctly
122#ifdef DEBUG
123 printf("Subsystem: ReportingAndChecking Thread finished\n");
124#endif
125return 0;
126
127}
128
129void Subsystem::SetReportString(char * report)
130{
131 SuspendComm();
132 strcpy(this->reportString,report);
133 ResumeComm();
134
135}
136
137bool Subsystem::SendSpecialReportContaining(char * specialReport)
138{
139 if(!acknowledgeReceivedForLastReport){
140 timeoutCount++;
141 if(timeoutCount==maxTimeoutCount){
142#ifdef DEBUG
143 printf("Subsystem: Timeout expired for report acknowledge. ResetConnectionToCC\n");
144#endif return false; //SendReport is not succesfull so this will stop Periodic action
145 }
146 }
147 //before writing the report or sending it make sure no other thread thouches it
148 pthread_mutex_lock(&mutex4report);
149// SubFormatSubsystem::ElaborateReport
150 //calls overriden method GenerateReport that will do the
151 //append the tag for specialReport in this protocol
152 sprintf(this->reportString,"SPECIAL:%s",specialReport);
153
154 //GenerateReport may have filled timestamp. Record it to checkreportacknowledge in future
155
156
157 ExtractTimeStampFromLastReportTo(lastTimeStamp);
158 reportSender.Send(this->reportString);
159#ifdef DEBUG
160 printf("Subsystem: Sending %s \n",this->reportString);
161#endif
162 pthread_mutex_unlock(&mutex4report);
163
164 acknowledgeReceivedForLastReport=false;
165//????????Order mutexes are lock/unlock????????????
166 return true; //if it goes here reporting was succesfull (Used in PeriodicAction reportingLoop)
167}
168
169void Subsystem::ClosingChannel()
170{
171// #ifdef DEBUG
172// printf("Subsystem: cancelling ReportingAndChecking\n");
173// #endif
174
175// pthread_cancel(reportThread);
176// #ifdef DEBUG
177// printf("Subsystem: cancelled ReportingAndChecking\n");
178// #endif
179
180 TCPListener::ClosingChannel();
181 if(locked){
182 ULock();
183 }
184#ifdef DEBUG
185 printf("Subsystem: resetting connection\n");
186#endif
187 SetReporting(false);
188#ifdef DEBUG
189 printf("Subsystem: waiting ReportingAndChecking Thread to finish\n");
190#endif
191 pthread_join(reportThread,NULL);
192#ifdef DEBUG
193 printf("Subsystem: ReportingAndChecking finished\n");
194#endif
195 reportSender.CloseConnection();
196}
197
198
199 void Subsystem::ResetConnectionToCC () {
200 if(locked){
201 ULock();
202 }
203#ifdef DEBUG
204 printf("Subsystem: resetting connection\n");
205#endif
206 SetReporting(false);
207#ifdef DEBUG
208 printf("Subsystem: waiting ReportingAndChecking Thread to finish\n");
209#endif
210 pthread_join(reportThread,NULL);
211#ifdef DEBUG
212 printf("Subsystem: ReportingAndChecking finished\n");
213#endif
214 reportSender.CloseConnection();
215 TCPListener::ClosingChannel(); //but still is waiting for new connections
216 }
217void Subsystem::process(){
218 if (!locked){
219 if(!Reporting()){
220
221 if ( !strcmp(TCPListener::receivedStream, "REPOR") ) {
222#ifdef DEBUG
223 printf("Subsystem: received REPOR\n");
224#endif
225 //before startreporting, the connection to cc by reportSender has to be stablished
226 pthread_create(&reportThread,NULL,&Subsystem::pthread_ReportingAndCheckingLoop,this);
227 SetReporting(true);
228 return;
229 }
230 } else { //already reporting
231 if ( !strcmp(TCPListener::receivedStream,"LOCK!") ) {
232 Lock();
233 return;
234 }
235 }
236
237 } else { //locked
238//as preliminary tests instead of commands, the new subsystem state is sent
239 if (! strncmp(TCPListener::receivedStream, "ULOCK", 5) ) {
240 ULock();
241 return;
242 }
243#ifdef DEBUG
244 printf("Subsystem: processing ... seting new state: %s \n", TCPListener::receivedStream);
245#endif
246 //calls overriden method thet will process the command itself
247 ProcessCmd(TCPListener::receivedStream);
248
249 //state=receivedStream;
250 return;
251
252 }
253
254//if program reaches here is because it hasn't Received REPOR & LOCK in the proper way. Network partner it's not (a properly working) CC. Closing the opened connection and waiting for new one
255 ResetConnectionToCC();
256}
257
258
259bool Subsystem::SendReport () {
260
261 if(!acknowledgeReceivedForLastReport){
262 timeoutCount++;
263 if(timeoutCount==maxTimeoutCount){
264#ifdef DEBUG
265 printf("Subsystem: Timeout expired for report acknowledge. ResetConnectionToCC\n");
266#endif
267 return false; //SendReport is not succesfull so this will stop Periodic action
268 }
269 }
270 //before writing the report or sending it make sure no other thread thouches it
271 pthread_mutex_lock(&mutex4report);
272// SubFormatSubsystem::ElaborateReport
273 //calls overriden method GenerateReport that will do the
274 GenerateReport();
275 //GenerateReport may have filled timestamp. Record it to checkreportacknowledge in future
276
277
278 ExtractTimeStampFromLastReportTo(lastTimeStamp);
279 reportSender.Send(this->reportString);
280#ifdef DEBUG
281 printf("Subsystem: Sending %s \n",this->reportString);
282#endif
283 pthread_mutex_unlock(&mutex4report);
284
285 acknowledgeReceivedForLastReport=false;
286
287 return true; //if it goes here reporting was succesfull (Used in PeriodicAction reportingLoop)
288 //acknowledge check is done elsewhere, when it arrives (asynchronously)
289}
290 void Subsystem::CheckReportAcknowledge()
291 {
292 reportSender.Receive();
293
294//incorporate lastTimeStamp in check
295 if (reportSender.ReturnNew() == "RECV@" ) {
296 acknowledgeReceivedForLastReport=true;
297 timeoutCount=0;
298 }else{
299 cerr<<"wrong ack!\n";
300 }
301 }
302
303 void Subsystem::Lock(){
304#ifdef DEBUG
305 printf("Subsystem: Locking to CC mode\n");
306#endif
307 locked=true;
308 }
309 void Subsystem::ULock(){
310#ifdef DEBUG
311 printf("Subsystem: UNLocking to CC mode\n");
312#endif
313
314 locked=false;
315 }
316 void Subsystem::SuspendComm()
317 {
318 pthread_mutex_lock(&mutex4report);
319 };
320 void Subsystem::ResumeComm()
321 {
322 pthread_mutex_unlock(&mutex4report);
323 };
324void Subsystem::ExtractTimeStampFromLastReportTo(char * lastTimeStamp)
325{
326 string report(this->reportString);
327 string::iterator it=report.begin();
328 //point it to the first appearence of :
329 it+=report.find(":");
330
331//cut the first field (between :) which is the status
332 report.erase(report.begin(),it);
333
334//#define TIMESTAMP_LEN 12
335//%02.2d:%02.2d:%02.2d:%03.3d
336 it=report.begin(); //back to the beginning
337 it+=12;
338//cut from the timestamp end to the rest
339 report.erase(it,report.end());
340 strcpy(lastTimeStamp,report.c_str());
341
342}
343void Subsystem::Shutdown()
344{}
345
346void Subsystem::WaitingForShutdown()
347{
348 sleep(6000);
349}
350
351
352//TO BE OVERRIDEN:
353
354 void Subsystem::ProcessCmd(char *)
355 {};
356 void Subsystem::GenerateReport()
357 {};
358 void Subsystem::HandleConnectionTimeoutIsOver()
359 {};
360
361
Note: See TracBrowser for help on using the repository browser.