1 /******************************************************************************* 2 Copyright(c) 2011 Jasem Mutlaq. All rights reserved. 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Library General Public 6 License version 2 as published by the Free Software Foundation. 7 8 This library is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 Library General Public License for more details. 12 13 You should have received a copy of the GNU Library General Public License 14 along with this library; see the file COPYING.LIB. If not, write to 15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 16 Boston, MA 02110-1301, USA. 17 *******************************************************************************/ 18 19 #pragma once 20 21 #include "basedevice.h" 22 #include "indidriver.h" 23 #include "indilogger.h" 24 25 #include <stdint.h> 26 27 namespace Connection 28 { 29 class Interface; 30 class Serial; 31 class TCP; 32 } 33 /** 34 * @brief COMMUNICATION_TAB Where all the properties required to connect/disconnect from 35 * a device are located. Usually such properties may include port number, IP address, or 36 * any property necessarily to establish a connection to the device. 37 */ 38 extern const char *COMMUNICATION_TAB; 39 40 /** 41 * @brief MAIN_CONTROL_TAB Where all the primary controls for the device are located. 42 */ 43 extern const char *MAIN_CONTROL_TAB; 44 45 /** 46 * @brief CONNECTION_TAB Where all device connection settings (serial, usb, ethernet) are defined and controlled. 47 */ 48 extern const char *CONNECTION_TAB; 49 50 /** 51 * @brief MOTION_TAB Where all the motion control properties of the device are located. 52 */ 53 extern const char *MOTION_TAB; 54 55 /** 56 * @brief DATETIME_TAB Where all date and time setting properties are located. 57 */ 58 extern const char *DATETIME_TAB; 59 60 /** 61 * @brief SITE_TAB Where all site information setting are located. 62 */ 63 extern const char *SITE_TAB; 64 65 /** 66 * @brief OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls, driver 67 * metadata, version information..etc. 68 */ 69 extern const char *OPTIONS_TAB; 70 71 /** 72 * @brief FILTER_TAB Where all the properties for filter wheels are located. 73 */ 74 extern const char *FILTER_TAB; 75 76 /** 77 * @brief FOCUS_TAB Where all the properties for focuser are located. 78 */ 79 extern const char *FOCUS_TAB; 80 81 /** 82 * @brief GUIDE_TAB Where all the properties for guiding are located. 83 */ 84 extern const char *GUIDE_TAB; 85 86 /** 87 * @brief ALIGNMENT_TAB Where all the properties for guiding are located. 88 */ 89 extern const char *ALIGNMENT_TAB; 90 91 /** 92 * @brief INFO_TAB Where all the properties for general information are located. 93 */ 94 extern const char *INFO_TAB; 95 96 /** 97 * \class INDI::DefaultDevice 98 * \brief Class to provide extended functionality for devices in addition 99 * to the functionality provided by INDI::BaseDevice. This class should \e only be subclassed by 100 * drivers directly as it is linked with main(). Virtual drivers cannot employ INDI::DefaultDevice. 101 * 102 * INDI::DefaultDevice provides capability to add Debug, Simulation, and Configuration controls. 103 * These controls (switches) are defined to the client. Configuration options permit saving and 104 * loading of AS-IS property values. 105 * 106 * \see <a href='tutorial__four_8h_source.html'>Tutorial Four</a> 107 * \author Jasem Mutlaq 108 */ 109 class INDI::DefaultDevice : public INDI::BaseDevice 110 { 111 public: 112 DefaultDevice(); 113 virtual ~DefaultDevice() override; 114 115 /** \brief Add Debug, Simulation, and Configuration options to the driver */ 116 void addAuxControls(); 117 118 /** \brief Add Debug control to the driver */ 119 void addDebugControl(); 120 121 /** \brief Add Simulation control to the driver */ 122 void addSimulationControl(); 123 124 /** \brief Add Configuration control to the driver */ 125 void addConfigurationControl(); 126 127 /** \brief Add Polling period control to the driver */ 128 void addPollPeriodControl(); 129 130 /** \brief Set all properties to IDLE state */ 131 void resetProperties(); 132 133 /** 134 * \brief Define number vector to client & register it. Alternatively, IDDefNumber can 135 * be used but the property will not get registered and the driver will not be able to 136 * save configuration files. 137 * \param nvp The number vector property to be defined 138 */ 139 void defineNumber(INumberVectorProperty *nvp); 140 141 /** 142 * \brief Define text vector to client & register it. Alternatively, IDDefText can be 143 * used but the property will not get registered and the driver will not be able to save 144 * configuration files. 145 * \param tvp The text vector property to be defined 146 */ 147 void defineText(ITextVectorProperty *tvp); 148 149 /** 150 * \brief Define switch vector to client & register it. Alternatively, IDDefswitch can be 151 * used but the property will not get registered and the driver will not be able to save 152 * configuration files. 153 * \param svp The switch vector property to be defined 154 */ 155 void defineSwitch(ISwitchVectorProperty *svp); 156 157 /** 158 * \brief Define light vector to client & register it. Alternatively, IDDeflight can be 159 * used but the property will not get registered and the driver will not be able to save 160 * configuration files. 161 * \param lvp The light vector property to be defined 162 */ 163 void defineLight(ILightVectorProperty *lvp); 164 165 /** 166 * \brief Define BLOB vector to client & register it. Alternatively, IDDefBLOB can be 167 * used but the property will not get registered and the driver will not be able to 168 * save configuration files. 169 * \param bvp The BLOB vector property to be defined 170 */ 171 void defineBLOB(IBLOBVectorProperty *bvp); 172 173 /** 174 * \brief Delete a property and unregister it. It will also be deleted from all clients. 175 * \param propertyName name of property to be deleted. 176 */ 177 virtual bool deleteProperty(const char *propertyName); 178 179 /** 180 * \brief Set connection switch status in the client. 181 * \param status If true, the driver will attempt to connect to the device (CONNECT=ON). 182 * If false, it will attempt to disconnect the device. 183 * \param status True to set CONNECT on, false to set DISCONNECT on. 184 * \param state State of CONNECTION properti, by default IPS_OK. 185 * \param msg A message to be sent along with connect/disconnect command, by default nullptr. 186 */ 187 virtual void setConnected(bool status, IPState state = IPS_OK, const char *msg = nullptr); 188 189 /** 190 * \brief Set a timer to call the function TimerHit after ms milliseconds 191 * \param ms timer duration in milliseconds. 192 * \return id of the timer to be used with RemoveTimer 193 */ 194 int SetTimer(uint32_t ms); 195 196 /** 197 * \brief Remove timer added with SetTimer 198 * \param id ID of the timer as returned from SetTimer 199 */ 200 void RemoveTimer(int id); 201 202 /** \brief Callback function to be called once SetTimer duration elapses. */ 203 virtual void TimerHit(); 204 205 /** \return driver executable filename */ getDriverExec()206 virtual const char *getDriverExec() 207 { 208 return me; 209 } 210 211 /** \return driver name */ getDriverName()212 virtual const char *getDriverName() 213 { 214 return getDefaultName(); 215 } 216 217 /** 218 * \brief Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor 219 * \param vMajor major revision number 220 * \param vMinor minor revision number 221 */ setVersion(uint16_t vMajor,uint16_t vMinor)222 void setVersion(uint16_t vMajor, uint16_t vMinor) 223 { 224 majorVersion = vMajor; 225 minorVersion = vMinor; 226 } 227 228 /** \return Major driver version number. */ getMajorVersion()229 uint16_t getMajorVersion() 230 { 231 return majorVersion; 232 } 233 234 /** \return Minor driver version number. */ getMinorVersion()235 uint16_t getMinorVersion() 236 { 237 return minorVersion; 238 } 239 240 /** 241 * \brief define the driver's properties to the client. 242 * Usually, only a minimum set of properties are defined to the client in this function 243 * if the device is in disconnected state. Those properties should be enough to enable the 244 * client to establish a connection to the device. In addition to CONNECT/DISCONNECT, such 245 * properties may include port name, IP address, etc. You should check if the device is 246 * already connected, and if this is true, then you must define the remainder of the 247 * the properties to the client in this function. Otherwise, the remainder of the driver's 248 * properties are defined to the client in updateProperties() function which is called when 249 * a client connects/disconnects from a device. 250 * \param dev name of the device 251 * \note This function is called by the INDI framework, do not call it directly. See LX200 252 * Generic driver for an example implementation 253 */ 254 virtual void ISGetProperties(const char *dev); 255 256 /** 257 * \brief Process the client newSwitch command 258 * \note This function is called by the INDI framework, do not call it directly. 259 * \returns True if any property was successfully processed, false otherwise. 260 */ 261 virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n); 262 263 /** 264 * \brief Process the client newNumber command 265 * \note This function is called by the INDI framework, do not call it directly. 266 * \returns True if any property was successfully processed, false otherwise. 267 */ 268 virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n); 269 270 /** 271 * \brief Process the client newSwitch command 272 * \note This function is called by the INDI framework, do not call it directly. 273 * \returns True if any property was successfully processed, false otherwise. 274 */ 275 virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n); 276 277 /** 278 * \brief Process the client newBLOB command 279 * \note This function is called by the INDI framework, do not call it directly. 280 * \returns True if any property was successfully processed, false otherwise. 281 */ 282 virtual bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], 283 char *formats[], char *names[], int n); 284 285 /** 286 * \brief Process a snoop event from INDI server. This function is called when a snooped property is 287 * updated in a snooped driver. 288 * \note This function is called by the INDI framework, do not call it directly. 289 * \returns True if any property was successfully processed, false otherwise. 290 */ 291 virtual bool ISSnoopDevice(XMLEle *root); 292 293 /** 294 * @return getInterface Return the interface declared by the driver. 295 */ 296 virtual uint16_t getDriverInterface() override; 297 298 /** 299 * @brief setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE. 300 * You may send an ORed list of DeviceInterface values. 301 * @param value ORed list of DeviceInterface values. 302 */ 303 void setDriverInterface(uint16_t value); 304 305 protected: 306 /** 307 * @brief setDynamicPropertiesBehavior controls handling of dynamic properties. Dyanmic properties 308 * are those generated from an external skeleton XML file. By default all properties, including 309 * dynamic properties, are defined to the client in ISGetProperties(). Furthermore, when 310 * űdeleteProperty(properyName) is called, the dynamic property is deleted by default, and can only 311 * be restored by calling buildSkeleton(filename) again. However, it is sometimes desirable to skip 312 * the definition of the dynamic properties on startup and delegate this task to the child class. 313 * To control this behavior, set enabled to false. 314 * @param defineEnabled True to define all dynamic properties in INDI::DefaultDevice own 315 * ISGetProperties() on startup. False to skip defining dynamic properties. 316 * @param deleteEnabled True to delete dynamic properties from memory in deleteProperty(name). 317 * False to keep dynamic property in the properties list, but delete it from the client. 318 * @note This function has no effect on regular properties initialized directly by the driver. 319 */ setDynamicPropertiesBehavior(bool defineEnabled,bool deleteEnabled)320 void setDynamicPropertiesBehavior(bool defineEnabled, bool deleteEnabled) 321 { 322 defineDynamicProperties = defineEnabled; 323 deleteDynamicProperties = deleteEnabled; 324 } 325 326 // Configuration 327 328 /** 329 * \brief Load the last saved configuration file 330 * \param silent if true, don't report any error or notification messages. 331 * \param property Name of property to load configuration for. If nullptr, all properties in the 332 * configuration file are loaded which is the default behavior. 333 * \return True if successful, false otherwise. 334 */ 335 virtual bool loadConfig(bool silent = false, const char *property = nullptr); 336 337 /** 338 * \brief Save the current properties in a configuration file 339 * \param silent if true, don't report any error or notification messages. 340 * \param property Name of specific property to save while leaving all others properties in the 341 * file as is. 342 * \return True if successful, false otherwise. 343 */ 344 virtual bool saveConfig(bool silent = false, const char *property = nullptr); 345 346 /** 347 * @brief purgeConfig Remove config file from disk. 348 * @return True if successful, false otherwise. 349 */ 350 virtual bool purgeConfig(); 351 352 /** 353 * @brief saveConfigItems Save specific properties in the provide config file handler. Child 354 * class usually override this function to save their own properties and the base class 355 * saveConfigItems(fp) must be explicitly called by each child class. The Default Device 356 * saveConfigItems(fp) only save Debug properties options in the config file. 357 * @param fp Pointer to config file handler 358 * @return True if successful, false otherwise. 359 */ 360 virtual bool saveConfigItems(FILE *fp); 361 362 /** 363 * @brief saveAllConfigItems Save all the drivers' properties in the configuration file 364 * @param fp pointer to config file handler 365 * @return True if successful, false otherwise. 366 */ 367 virtual bool saveAllConfigItems(FILE *fp); 368 369 /** 370 * \brief Load the default configuration file 371 * \return True if successful, false otherwise. 372 */ 373 virtual bool loadDefaultConfig(); 374 375 // Simulatin & Debug 376 377 /** 378 * \brief Toggle driver debug status 379 * A driver can be more verbose if Debug option is enabled by the client. 380 * \param enable If true, the Debug option is set to ON. 381 */ 382 void setDebug(bool enable); 383 384 /** 385 * \brief Toggle driver simulation status 386 * A driver can run in simulation mode if Simulation option is enabled by the client. 387 * \param enable If true, the Simulation option is set to ON. 388 */ 389 void setSimulation(bool enable); 390 391 /** 392 * \brief Inform driver that the debug option was triggered. 393 * This function is called after setDebug is triggered by the client. Reimplement this 394 * function if your driver needs to take specific action after debug is enabled/disabled. 395 * Otherwise, you can use isDebug() to check if simulation is enabled or disabled. 396 * \param enable If true, the debug option is set to ON. 397 */ 398 virtual void debugTriggered(bool enable); 399 400 /** 401 * \brief Inform driver that the simulation option was triggered. 402 * This function is called after setSimulation is triggered by the client. Reimplement this 403 * function if your driver needs to take specific action after simulation is enabled/disabled. 404 * Otherwise, you can use isSimulation() to check if simulation is enabled or disabled. 405 * \param enable If true, the simulation option is set to ON. 406 */ 407 virtual void simulationTriggered(bool enable); 408 409 /** \return True if Debug is on, False otherwise. */ 410 bool isDebug(); 411 412 /** \return True if Simulation is on, False otherwise. */ 413 bool isSimulation(); 414 415 /** 416 * \brief Initilize properties initial state and value. The child class must implement this function. 417 * \return True if initilization is successful, false otherwise. 418 */ 419 virtual bool initProperties(); 420 421 /** 422 * \brief updateProperties is called whenever there is a change in the CONNECTION status of 423 * the driver. This will enable the driver to react to changes of switching ON/OFF a device. 424 * For example, a driver may only define a set of properties after a device is connected, but 425 * not before. 426 * \return True if update is successful, false otherwise. 427 */ 428 virtual bool updateProperties(); 429 430 /** 431 * \brief Connect to the device. INDI::DefaultDevice implementation connects to appropriate 432 * connection interface (Serial or TCP) governed by connectionMode. If connection is successful, 433 * it proceed to call Handshake() function to ensure communication with device is successful. 434 * For other communication interface, override the method in the child class implementation 435 * \return True if connection is successful, false otherwise 436 */ 437 virtual bool Connect(); 438 439 /** 440 * \brief Disconnect from device 441 * \return True if successful, false otherwise 442 */ 443 virtual bool Disconnect(); 444 445 /** 446 * @brief registerConnection Add new connection plugin to the existing connection pool. The 447 * connection type shall be defined to the client in ISGetProperties() 448 * @param newConnection Pointer to new connection plugin 449 */ 450 void registerConnection(Connection::Interface *newConnection); 451 452 /** 453 * @brief unRegisterConnection Remove connection from existing pool 454 * @param existingConnection pointer to connection interface 455 * @return True if connection is removed, false otherwise. 456 */ 457 bool unRegisterConnection(Connection::Interface *existingConnection); 458 459 /** @return Return actively selected connection plugin */ getActiveConnection()460 Connection::Interface *getActiveConnection() 461 { 462 return activeConnection; 463 } 464 465 void setDefaultPollingPeriod(uint32_t period); 466 void setPollingPeriodRange(uint32_t minimum, uint32_t maximum); getPollingPeriod()467 uint32_t getPollingPeriod() 468 { 469 return static_cast<uint32_t>(PollPeriodN[0].value); 470 } 471 472 /** \return Default name of the device. */ 473 virtual const char *getDefaultName() = 0; 474 475 /// Period in milliseconds to call TimerHit(). Default 1000 ms 476 uint32_t POLLMS = 1000; 477 478 private: 479 bool isInit { false }; 480 bool pDebug { false }; 481 bool pSimulation { false }; 482 483 uint16_t majorVersion { 1 }; 484 uint16_t minorVersion { 0 }; 485 uint16_t interfaceDescriptor { 0 }; 486 487 ISwitch DebugS[2]; 488 ISwitch SimulationS[2]; 489 ISwitch ConfigProcessS[4]; 490 ISwitch ConnectionS[2]; 491 INumber PollPeriodN[1]; 492 493 ISwitchVectorProperty DebugSP; 494 ISwitchVectorProperty SimulationSP; 495 ISwitchVectorProperty ConfigProcessSP; 496 ISwitchVectorProperty ConnectionSP; 497 INumberVectorProperty PollPeriodNP; 498 499 IText DriverInfoT[4] {}; 500 ITextVectorProperty DriverInfoTP; 501 502 // Connection modes 503 ISwitch *ConnectionModeS = nullptr; 504 ISwitchVectorProperty ConnectionModeSP; 505 506 std::vector<Connection::Interface *> connections; 507 Connection::Interface *activeConnection = nullptr; 508 509 // Connection Plugins 510 friend class Connection::Serial; 511 friend class Connection::TCP; 512 friend class FilterInterface; 513 514 bool defineDynamicProperties = true; 515 bool deleteDynamicProperties = true; 516 }; 517