Repository for import to local machine
Dependencies: DMBasicGUI DMSupport
ServiceInterval.cpp
- Committer:
- jmitc91516
- Date:
- 2017-07-31
- Revision:
- 8:26e49e6955bd
- Parent:
- 1:a5258871b33d
File content as of revision 8:26e49e6955bd:
/* These classes do what the name implies - handle service intervals. These are measured either in instrument cycles (i.e. runs), or time - in the latter case, the interval is always twelve months. Each ServiceInterval object deals with one (and only one) service interval, allowing the caller to specify its description (a text string). Note that the caller must 'poll' the ServiceInterval object to find out whether or not it has expired - it does not raise an interrupt, or call a callback function, or do anything unsolicited. */ #include "ServiceInterval.h" #include "SettingsHandler.h" #include "EasyGUITouchAreaIndices.h" #include "GCRealTimeClock.h" // Static members // Have to manually make sure we have the correct number of NULLs here - we do not want any invalid pointer values ServiceInterval* ServiceInterval::serviceIntervalArray[SERVICE_INTERVAL_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; // Static member functions /* Sets up all our service intervals. This is effectively a 'static constructor' - but it has to be called manually before the ServiceInterval objects can be used ******************************************************************************* */ void ServiceInterval::SetupAllServiceIntervals(void) { // For the service intervals based on numbers of cycles, set some default values for the cycle counts CyclesServiceInterval* cyclesServiceInterval = new CyclesServiceInterval("Column", COMPONENT_1_SERVICED); cyclesServiceInterval->SetDurationInNumberOfInstrumentCycles(2); // *** Unrealistic value - testing only *** serviceIntervalArray[0] = cyclesServiceInterval; cyclesServiceInterval = new CyclesServiceInterval("Liner", COMPONENT_2_SERVICED); cyclesServiceInterval->SetDurationInNumberOfInstrumentCycles(3); // *** Unrealistic value - testing only *** serviceIntervalArray[1] = cyclesServiceInterval; cyclesServiceInterval = new CyclesServiceInterval("Septa", COMPONENT_3_SERVICED); cyclesServiceInterval->SetDurationInNumberOfInstrumentCycles(4); // *** Unrealistic value - testing only *** serviceIntervalArray[2] = cyclesServiceInterval; // TODO: fill the rest of the array with TwelveMonthServiceInterval objects, // one for each component that actually does require to be replaced every twelve months serviceIntervalArray[3] = new TwelveMonthServiceInterval("Detector", COMPONENT_4_SERVICED); serviceIntervalArray[4] = new TwelveMonthServiceInterval("O-ring", COMPONENT_5_SERVICED); serviceIntervalArray[5] = new TwelveMonthServiceInterval("Amplifier fan", COMPONENT_6_SERVICED); // If we add more ServiceInterval objects (of either derived class), need to increase SERVICE_INTERVAL_COUNT enum value - see header } /* Start all the service intervals */ void ServiceInterval::StartAllServiceIntervals(void) { for (int index = 0; index < SERVICE_INTERVAL_COUNT; ++index) { if(serviceIntervalArray[index] != NULL) { serviceIntervalArray[index]->Start(); } } } /* Returns a pointer to one of the service interval objects, specified by its index, or NULL if there is no such interval (e.g. the index is invalid). Args: the index of the service interval required. The allowed range is from zero to (count of service intervals - 1). Call GetServiceIntervalCount to find out how many service intervals there are Returns a pointer to the specified service interval object, or NULL if there is no such interval. Caller must check for NULL. ************************** */ ServiceInterval* ServiceInterval::GetServiceInterval(int serviceIntervalIndex) { if((serviceIntervalIndex >= 0) && (serviceIntervalIndex < SERVICE_INTERVAL_COUNT)) { return serviceIntervalArray[serviceIntervalIndex]; } // 'else' index invalid return NULL; } /* Tell all our service interval objects that the instrument has performed another cycle */ void ServiceInterval::TellAllServiceIntervalsInstrumentHasCycled(void) { for (int index = 0; index < SERVICE_INTERVAL_COUNT; ++index) { if(serviceIntervalArray[index] != NULL) { serviceIntervalArray[index]->InstrumentHasCycled(); } } } /* Tells the caller if at least one service interval has expired. (It is then up to the caller to find out how many have expired, and which ones, by calling the 'GetNextExpiredServiceInterval' function.) No args. Returns true if at least one service interval has expired, false if not. */ bool ServiceInterval::AtLeastOneServiceIntervalHasExpired(void) { for (int index = 0; index < SERVICE_INTERVAL_COUNT; ++index) { if(serviceIntervalArray[index] != NULL) { if(serviceIntervalArray[index]->HasExpired()) { return true; } } } // 'else' - none have expired return false; } /* Given a pointer to a ServiceInterval object that has expired, this function looks for the next ServiceInterval object that has expired, and returns a pointer to it, or NULL if there are no more expired service intervals. If the pointer passed to it - i.e. 'thisExpiredInterval' - is NULL, this function starts at the beginning of the array. Note that it does not check that 'thisExpiredInterval' (if not NULL) actually has expired. The idea is that you first call this function with 'thisExpiredInterval' set to NULL, then (if it did not return NULL) you call it again, passing it the ServiceInterval pointer it returned, and you keep on doing this until it returns NULL. The ServiceInterval pointers that it returned during this sequence, are the ones that have expired. Args: a pointer to the 'current' expired ServiceInterval - it starts its search at the next object after that. If this is NULL, it starts at the beginning of the array. Returns a pointer to the next ServiceInterval that has expired, or NULL if there are no more. *** Caller must check for NULL (obviously) *** */ ServiceInterval* ServiceInterval::GetNextExpiredServiceInterval(ServiceInterval* thisExpiredInterval) { int startIndex = 0; if(thisExpiredInterval != NULL) { for (int index = 0; index < SERVICE_INTERVAL_COUNT; ++index) { if(serviceIntervalArray[index] != NULL) { if(serviceIntervalArray[index] == thisExpiredInterval) { startIndex = index + 1; break; } } } } for (int index = startIndex; index < SERVICE_INTERVAL_COUNT; ++index) { if(serviceIntervalArray[index] != NULL) { if(serviceIntervalArray[index]->HasExpired()) { return serviceIntervalArray[index]; } } } return NULL; } /* Saves the states of all our ServiceInterval objects to QSPI settings, so that they can be restored later. */ void ServiceInterval::SaveAllServiceIntervalsToQSPISettings(void) { for (int index = 0; index < SERVICE_INTERVAL_COUNT; ++index) { if(serviceIntervalArray[index] != NULL) { serviceIntervalArray[index]->SaveToQSPISettings(); } } } /* Restores the states of all our ServiceInterval objects from QSPI settings, to their values at the last 'SaveAllServiceIntervalsToQSPISettings' call. */ void ServiceInterval::ReadAllServiceIntervalsFromQSPISettings(void) { for (int index = 0; index < SERVICE_INTERVAL_COUNT; ++index) { if(serviceIntervalArray[index] != NULL) { serviceIntervalArray[index]->ReadFromQSPISettings(); } } } /* Tells the caller whether or not a particular touch area is a "this component has been serviced" touch area. Args: the index of the touch area in question Returns true if the specified touch area corresponds to the "this component has been serviced" touch area index of any of our ServiceInterval objects. */ bool ServiceInterval::IsServicedTouchArea(int touchAreaIndex) { for (int index = 0; index < SERVICE_INTERVAL_COUNT; ++index) { if(serviceIntervalArray[index] != NULL) { if(serviceIntervalArray[index]->servicedTouchArea == touchAreaIndex) { return true; } } } // 'else' - no matching touch area found return false; } /* If a specified touch area corresponds to one of our "this component has been serviced" touch areas, deals with it by restarting that component's service interval Args: the index of the touch area in question Returns true if the specified touch area corresponded to the "this component has been serviced" touch area index of any of our ServiceInterval objects, and we have therefore restarted it - false if not, and we have therefore done nothing */ bool ServiceInterval::DealWithServicedTouchArea(int touchAreaIndex) { for (int index = 0; index < SERVICE_INTERVAL_COUNT; ++index) { if(serviceIntervalArray[index] != NULL) { if(serviceIntervalArray[index]->servicedTouchArea == touchAreaIndex) { serviceIntervalArray[index]->Start(); return true; } } } // 'else' - no matching touch area found return false; } // End of static member functions // ServiceInterval class members // ***************************** /* Create a new ServiceInterval object, with the specified description. Note that the service interval does not start its 'countdown' at this point. Args: the interval description, as a null-terminated string */ ServiceInterval::ServiceInterval(char *intervalDescription, int touchAreaIndex) { // Do not use up more memory than we need for the description int descriptionLength = strlen(intervalDescription); description = new char[descriptionLength + 1]; strcpy(description, intervalDescription); intervalHasStarted = false; servicedTouchArea = touchAreaIndex; } /* Destroy this service interval cleanly - free up allocated memory */ ServiceInterval::~ServiceInterval() { if(description != NULL) { delete [] description; description = NULL; } } /* Tells the caller how long the description is, so that the caller can make sure it has enough memory for its own copy of the description. Note that the length value returned does *not* include the terminating zero byte. No arguments Returns the number of characters in the description string, not including the terminating zero byte. */ int ServiceInterval::GetDescriptionLength(void) { return strlen(description); } /* Returns the interval description, as a null-terminated string, in a buffer provided by the caller. Args: a pointer to the buffer which is to contain the description. Note that it is up to the caller to make sure that this is long enough to contain the description, plus the null terminator */ void ServiceInterval::GetDescription(char *buffer) { strcpy(buffer, description); } // CyclesServiceInterval class members // *********************************** /* CyclesServiceInterval keeps its description in the base class */ CyclesServiceInterval::CyclesServiceInterval(char *intervalDescription, int touchAreaIndex) : ServiceInterval(intervalDescription, touchAreaIndex) { durationInNumberOfInstrumentCycles = 0; countOfRemainingCycles = -1; // Not yet set intervalHasExpired = false; } /* Sets the service interval duration to the number of instrument cycles (i.e. runs) specified. Note that this function does not start the 'countdown' - the 'Start' function does that. Args: the number of cycles that represents a new service interval */ void CyclesServiceInterval::SetDurationInNumberOfInstrumentCycles(int newDurationInNumberOfInstrumentCycles) { durationInNumberOfInstrumentCycles = newDurationInNumberOfInstrumentCycles; } /* Start the next service interval now. No arguments, no return code */ void CyclesServiceInterval::Start(void) { countOfRemainingCycles = durationInNumberOfInstrumentCycles; intervalHasExpired = false; intervalHasStarted = true; } /* Caller is telling us that the instrument either is about to perform another cycle, or has just completed another cycle - it does not matter which, as long as this function is called once, and only once, per cycle. This function then works out if this service interval has now expired - caller must call this class' 'HasExpired()' member function (see header file) to find out. No arguments, no return code */ void CyclesServiceInterval::InstrumentHasCycled(void) { if(intervalHasStarted && (!intervalHasExpired)) { --countOfRemainingCycles; if(countOfRemainingCycles <= 0) { // Make sure the cycle count has a legal value countOfRemainingCycles = 0; intervalHasExpired = true; intervalHasStarted = false; } } } /* Save the current state of this service interval to QSPI settings, so that we can later read the state from QSPI, and restore it exactly as it was No arguments, no return code */ void CyclesServiceInterval::SaveToQSPISettings(void) { int descriptionLength = GetDescriptionLength(); char descriptionBuff[descriptionLength + 10]; GetDescription(descriptionBuff); char settingNameBuff[descriptionLength + 100]; sprintf(settingNameBuff, "%s%s", descriptionBuff, ".intervalHasStarted"); SettingsHandler::PutIntegerValueToQSPISettings(settingNameBuff, intervalHasStarted ? 1 : 0); sprintf(settingNameBuff, "%s%s", descriptionBuff, ".durationInNumberOfInstrumentCycles"); SettingsHandler::PutIntegerValueToQSPISettings(settingNameBuff, durationInNumberOfInstrumentCycles); sprintf(settingNameBuff, "%s%s", descriptionBuff, ".countOfRemainingCycles"); SettingsHandler::PutIntegerValueToQSPISettings(settingNameBuff, countOfRemainingCycles); sprintf(settingNameBuff, "%s%s", descriptionBuff, ".intervalHasExpired"); SettingsHandler::PutIntegerValueToQSPISettings(settingNameBuff, intervalHasExpired ? 1 : 0); } /* Reads the state of this service interval from QSPI settings. No arguments, no return code */ void CyclesServiceInterval::ReadFromQSPISettings(void) { int descriptionLength = GetDescriptionLength(); char descriptionBuff[descriptionLength + 10]; GetDescription(descriptionBuff); char settingNameBuff[descriptionLength + 100]; sprintf(settingNameBuff, "%s%s", descriptionBuff, ".intervalHasStarted"); intervalHasStarted = (SettingsHandler::GetIntegerValueFromQSPISettings(settingNameBuff, 0) != 0); sprintf(settingNameBuff, "%s%s", descriptionBuff, ".durationInNumberOfInstrumentCycles"); durationInNumberOfInstrumentCycles = SettingsHandler::GetIntegerValueFromQSPISettings(settingNameBuff, 0); sprintf(settingNameBuff, "%s%s", descriptionBuff, ".countOfRemainingCycles"); countOfRemainingCycles = SettingsHandler::GetIntegerValueFromQSPISettings(settingNameBuff, 0); sprintf(settingNameBuff, "%s%s", descriptionBuff, ".intervalHasExpired"); intervalHasExpired = (SettingsHandler::GetIntegerValueFromQSPISettings(settingNameBuff, 0) != 0); } // TwelveMonthServiceInterval class members // **************************************** // Static function /* Gets the current local time as a 'tm' structure. Provided so that we do this the same way everywhere (we may need to apply a correction to the value returned by the time() function). Args: pointer to a 'tm' structure to receive the local time *** This must not be NULL *** No return code. */ void TwelveMonthServiceInterval::GetCurrentLocalTime(struct tm *currentLocalTime) { time_t seconds = time(NULL); // Get current time *currentLocalTime = *(localtime(&seconds)); } // Non-static functions /* TwelveMonthServiceInterval keeps its description in the base class */ TwelveMonthServiceInterval::TwelveMonthServiceInterval(char *intervalDescription, int touchAreaIndex) : ServiceInterval(intervalDescription, touchAreaIndex) { } /* Start the next service interval now. No arguments, no return code */ void TwelveMonthServiceInterval::Start(void) { GetCurrentLocalTime(&startTime); intervalHasStarted = true; } /* This function does nothing in this class - we are not interested in machine cycles, only in elapsed time. Provided so that the caller does not need to know the type of this object before calling this function */ void TwelveMonthServiceInterval::InstrumentHasCycled(void) { } /* Tell the caller whether or not this service interval has expired - i.e. whether twelve full months (at least) have gone by since the interval started. */ bool TwelveMonthServiceInterval::HasExpired(void) { if(intervalHasStarted) { struct tm currentTime; GetCurrentLocalTime(¤tTime); int yearsGoneBy = currentTime.tm_year - startTime.tm_year; if((yearsGoneBy) > 1) { // Twelve month service interval has expired intervalHasStarted = false; return true; } if(yearsGoneBy == 1) { int monthsGoneBy = currentTime.tm_mon - startTime.tm_mon + 12; if(monthsGoneBy > 12) { // Twelve month service interval has expired intervalHasStarted = false; return true; } if(monthsGoneBy == 12) { if(currentTime.tm_mday > startTime.tm_mday) { // Twelve month service interval has expired intervalHasStarted = false; return true; } } } // If we get here, the twelve month service interval has not expired } // 'else' - either the interval has not expired, or has not even started return false; } /* Save the current state of this service interval to QSPI settings, so that we can later read the state from QSPI, and restore it exactly as it was No arguments, no return code */ void TwelveMonthServiceInterval::SaveToQSPISettings(void) { int descriptionLength = GetDescriptionLength(); char descriptionBuff[descriptionLength + 10]; GetDescription(descriptionBuff); char settingNameBuff[descriptionLength + 100]; // We are only interested in the year, month and day of the month values in the start time - // we do not use the other values sprintf(settingNameBuff, "%s%s", descriptionBuff, ".startTime.tm_year"); SettingsHandler::PutIntegerValueToQSPISettings(settingNameBuff, startTime.tm_year); sprintf(settingNameBuff, "%s%s", descriptionBuff, ".startTime.tm_mon"); SettingsHandler::PutIntegerValueToQSPISettings(settingNameBuff, startTime.tm_mon); sprintf(settingNameBuff, "%s%s", descriptionBuff, ".startTime.tm_mday"); SettingsHandler::PutIntegerValueToQSPISettings(settingNameBuff, startTime.tm_mday); } /* Read the state of this service interval from QSPI settings No arguments, no return code */ void TwelveMonthServiceInterval::ReadFromQSPISettings(void) { int descriptionLength = GetDescriptionLength(); char descriptionBuff[descriptionLength + 10]; GetDescription(descriptionBuff); char settingNameBuff[descriptionLength + 100]; // We are only interested in the year, month and day of the month values in the start time - // we do not use the other values sprintf(settingNameBuff, "%s%s", descriptionBuff, ".startTime.tm_year"); startTime.tm_year = SettingsHandler::GetIntegerValueFromQSPISettings(settingNameBuff, 0); sprintf(settingNameBuff, "%s%s", descriptionBuff, ".startTime.tm_mon"); startTime.tm_mon = SettingsHandler::GetIntegerValueFromQSPISettings(settingNameBuff, 0); sprintf(settingNameBuff, "%s%s", descriptionBuff, ".startTime.tm_mday"); startTime.tm_mday = SettingsHandler::GetIntegerValueFromQSPISettings(settingNameBuff, 0); }