37 #include <libnova/sidereal_time.h>
47 #define MOUNTINFO_TAB "Mount Info"
49 #define PMC8_DEFAULT_PORT 54372
50 #define PMC8_DEFAULT_IP_ADDRESS "192.168.47.1"
51 #define PMC8_TRACKING_AUTODETECT_INTERVAL 10
52 #define PMC8_VERSION_MAJOR 0
53 #define PMC8_VERSION_MINOR 5
55 static std::unique_ptr<PMC8> scope(
new PMC8());
60 currentRA = ln_get_apparent_sidereal_time(ln_get_julian_from_sys());
120 IUFillSwitch(&PostGotoS[0],
"GOTO_START_TRACKING",
"Start / Resume Tracking",
ISS_ON);
138 IUFillNumber(&RampN[0],
"RAMP_INTERVAL",
"Interval (ms)",
"%g", 20, 1000, 5, 200);
139 IUFillNumber(&RampN[1],
"RAMP_BASESTEP",
"Base Step",
"%g", 1, 256, 1, 4);
140 IUFillNumber(&RampN[2],
"RAMP_FACTOR",
"Factor",
"%g", 1.0, 2.0, 0.1, 1.4);
144 IUFillNumber(&GuideRateN[0],
"GUIDE_RATE_RA",
"RA (x Sidereal)",
"%g", 0.1, 1.0, 0.1, 0.4);
145 IUFillNumber(&GuideRateN[1],
"GUIDE_RATE_DE",
"DEC (x Sidereal)",
"%g", 0.1, 1.0, 0.1, 0.4);
147 IUFillNumber(&LegacyGuideRateN[0],
"LEGACY_GUIDE_RATE",
"x Sidereal",
"%g", 0.1, 1.0, 0.1, 0.4);
162 IUFillText(&FirmwareT[0],
"Version",
"Version",
"");
226 void PMC8::getStartupData()
242 LOG_INFO(
"Detected mount type as Exos2.");
247 LOG_INFO(
"Detected mount type as G11.");
252 LOG_INFO(
"Detected mount type as iExos100.");
256 LOG_INFO(
"Cannot detect mount type--perhaps this is older firmware?");
260 LOG_INFO(
"Guessing mount is EXOS2 from device name.");
265 LOG_INFO(
"Guessing mount is iEXOS100 from device name.");
286 GuideRateN[0].value = rate;
292 GuideRateN[1].value = rate;
312 LOG_INFO(
"The PMC-Eight driver is in BETA development currently.");
313 LOG_INFO(
"Be prepared to intervene if something unexpected occurs.");
317 double HA = ln_get_apparent_sidereal_time(ln_get_julian_from_sys());
318 double DEC = CurrentDEC;
349 bool PMC8::ISNewNumber(
const char *dev,
const char *name,
double values[],
char *names[],
int n)
354 if (!strcmp(name, RampNP.
name))
362 if (!strcmp(name, LegacyGuideRateNP.
name))
375 if (!strcmp(name, GuideRateNP.
name))
430 if (strcmp(name, MountTypeSP.
name) == 0)
434 LOGF_INFO(
"Selected mount is %s", MountTypeS[currentMountIndex].label);
442 if (strcmp(name, SerialCableTypeSP.
name) == 0)
449 if (strcmp(name, PostGotoSP.
name) == 0)
482 if (isPulsingNS || isPulsingWE)
return true;
484 bool slewing =
false;
494 LOG_ERROR(
"PMC8::ReadScopeStatus() - unable to check slew state");
498 if (slewing ==
false)
503 LOG_INFO(
"Slew complete, tracking...");
513 LOG_ERROR(
"slew complete - unable to enable tracking");
534 LOG_ERROR(
"PMC8::ReadScopeStatus() - unable to check slew state");
538 if (slewing ==
false)
552 if (!trackingPollCounter--)
573 LOGF_INFO(
"Mount has started tracking at %f arcsec / sec", track_rate);
584 if (!trackingPollCounter--)
597 if (rc && ((
int)track_rate == 0))
599 LOG_INFO(
"Mount appears to have stopped tracking");
616 LOGF_INFO(
"Mount now tracking at %f arcsec / sec", track_rate);
642 LOG_ERROR(
"Cannot slew while moving or guiding. Please stop moving or guiding first");
652 LOG_INFO(
"Goto called while already slewing. Stopping slew and will try goto again in 2.5 seconds");
667 char RAStr[64] = {0}, DecStr[64] = {0};
672 fs_sexa(RAStr, targetRA, 2, 3600);
673 fs_sexa(DecStr, targetDEC, 2, 3600);
675 LOGF_DEBUG(
"Slewing to RA: %s - DEC: %s", RAStr, DecStr);
693 char RAStr[64] = {0}, DecStr[64] = {0};
695 fs_sexa(RAStr, targetRA, 2, 3600);
696 fs_sexa(DecStr, targetDEC, 2, 3600);
698 LOGF_DEBUG(
"Syncing to RA: %s - DEC: %s", RAStr, DecStr);
718 static_cast<PMC8*
>(p)->
Goto(
static_cast<PMC8*
>(p)->targetRA,
static_cast<PMC8*
>(p)->targetDEC);
773 LOG_INFO(
"Abort called--stopping all motion.");
804 LOG_INFO(
"Telescope parking in progress to motor position (0, 0)");
857 LOG_ERROR(
"PMC8::updateTime() not implemented!");
872 LOG_WARN(
"Southern Hemisphere support still experimental!");
879 char l[32] = {0}, L[32] = {0};
881 fs_sexa(L, longitude, 4, 3600);
883 LOGF_INFO(
"Site location updated to Lat %.32s - Long %.32s", l, L);
902 return 4 * pow(2, mode) * 15;
914 LOG_ERROR(
"Ramp function called while not in ramp state");
921 newrate += RampN[1].value * pow(RampN[2].value, moveInfo->
rampIteration++) * 15;
925 newrate -= RampN[1].value * pow(RampN[2].value, --moveInfo->
rampIteration) * 15;
928 int adjrate = newrate;
936 else if (newrate <= 0)
947 LOG_ERROR(
"slew complete - unable to enable tracking");
960 LOGF_EXTRA3(
"Ramping: mount dir %d, ramping dir %d, iteration %d, step to %d", dir, moveInfo->
rampDir,
965 LOGF_ERROR(
"Error ramping move rate: mount dir %d, ramping dir %d, iteration %d, step to %d", dir, moveInfo->
rampDir,
1007 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
1012 LOG_ERROR(
"Mount is slewing. Wait to issue move command until goto completes.");
1017 LOG_ERROR(
"Mount received command to move in opposite direction before stopping. This shouldn't happen.");
1023 LOGF_DEBUG(
"MoveNS at slew index %d", currentIndex);
1034 if (moveInfoDEC.
moveDir == dir)
return true;
1036 LOG_WARN(
"Started moving other direction before ramp down completed. This *may* cause mechanical problems with mount. It is adviseable to wait for axis movement to settle before switching directions.");
1049 if (moveInfoDEC.
moveDir != dir)
1051 LOGF_DEBUG(
"Stop command issued for direction %d, but we're not moving that way", dir);
1078 LOG_ERROR(
"Please unpark the mount before issuing any motion commands.");
1083 LOG_ERROR(
"Mount is already slewing. Wait to issue move command until done slewing.");
1088 LOG_ERROR(
"Mount received command to move in opposite direction before stopping. This shouldn't happen.");
1094 LOGF_DEBUG(
"MoveWE at slew index %d", currentIndex);
1105 if (moveInfoRA.
moveDir == dir)
return true;
1107 LOG_WARN(
"Started moving other direction before ramp down completed. This *may* cause mechanical problems with mount. It is adviseable to wait for axis movement to settle before switching directions.");
1120 if (moveInfoRA.
moveDir != dir)
1122 LOGF_DEBUG(
"Stop command issued for direction %d, but we're not moving that way", dir);
1147 long timetaken_us = 0;
1148 int timeremain_ms = 0;
1170 timeremain_ms = (int)(ms - ((
float)timetaken_us) / 1000.0);
1172 if (timeremain_ms < 0)
1179 LOG_INFO(
"Mount not tracking--cannot guide.");
1188 long timetaken_us = 0;
1189 int timeremain_ms = 0;
1211 timeremain_ms = (int)(ms - ((
float)timetaken_us) / 1000.0);
1213 if (timeremain_ms < 0)
1220 LOG_INFO(
"Mount not tracking--cannot guide.");
1229 long timetaken_us = 0;
1230 int timeremain_ms = 0;
1253 timeremain_ms = (int)(ms - ((
float)timetaken_us) / 1000.0);
1255 if (timeremain_ms < 0)
1262 LOG_INFO(
"Mount not tracking--cannot guide.");
1271 long timetaken_us = 0;
1272 int timeremain_ms = 0;
1294 timeremain_ms = (int)(ms - ((
float)timetaken_us) / 1000.0);
1296 if (timeremain_ms < 0)
1303 LOG_INFO(
"Mount not tracking--cannot guide.");
1316 isPulsingNS =
false;
1325 isPulsingWE =
false;
1380 static struct timeval ltv;
1386 gettimeofday(&tv,
nullptr);
1388 if (ltv.tv_sec == 0 && ltv.tv_usec == 0)
1391 dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec) / 1e6;
1487 SetAxis1Park(ln_get_apparent_sidereal_time(ln_get_julian_from_sys()));
1498 LOG_ERROR(
"PPMC8::SetCurrentPark() not implemented!");
1504 LOG_ERROR(
"PMC8::SetDefaultPark() not implemented!");
1509 uint8_t PMC8::convertToPMC8TrackMode(uint8_t mode)
1530 uint8_t PMC8::convertFromPMC8TrackMode(uint8_t mode)
1552 LOGF_DEBUG(
"PMC8::SetTrackMode called mode=%d", mode);
1554 pmc8_mode = convertToPMC8TrackMode(mode);
1558 LOGF_ERROR(
"PMC8::SetTrackMode mode=%d not supported!", mode);
1580 static bool deRateWarning =
true;
1583 LOGF_INFO(
"Custom tracking rate set: raRate=%f deRate=%f", raRate, deRate);
1586 pmc8RARate = raRate;
1588 if (deRate != 0 && deRateWarning)
1591 deRateWarning =
false;
1592 LOG_WARN(
"Custom Declination tracking rate is not implemented yet.");
1598 LOG_ERROR(
"PMC8::SetTrackRate not implemented!");
1605 LOGF_DEBUG(
"PMC8::SetTrackEnabled called enabled=%d", enabled);
1612 LOG_ERROR(
"PMC8::SetTrackEnabled - unable to enable tracking");
1623 LOG_ERROR(
"PMC8::SetTrackEnabled - unable to set RA track rate to 0");
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
void setDefaultHost(const char *addressHost)
void setDefaultPort(uint32_t addressPort)
const char * getDeviceName() const
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
virtual bool Disconnect()
Disconnect from device.
virtual void setConnected(bool status, IPState state=IPS_OK, const char *msg=nullptr)
Set connection switch status in the client.
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
bool isSimulation() const
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
Connection::Interface * getActiveConnection()
virtual bool Connect()
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
uint16_t getDriverInterface() const
INumberVectorProperty GuideNSNP
void initGuiderProperties(const char *deviceName, const char *groupName)
Initilize guider properties. It is recommended to call this function within initProperties() of your ...
INumberVectorProperty GuideWENP
void processGuiderProperties(const char *name, double values[], char *names[], int n)
Call this function whenever client updates GuideNSNP or GuideWSP properties in the primary device....
INumberVectorProperty TrackRateNP
TelescopeStatus TrackState
ISwitchVectorProperty TrackStateSP
ISwitchVectorProperty ParkOptionSP
void SetAxis1Park(double value)
SetRAPark Set current RA/AZ parking position. The data park file (stored in ~/.indi/ParkData....
ISwitchVectorProperty MovementNSSP
void SetAxis1ParkDefault(double steps)
SetRAPark Set default RA/AZ parking position.
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
double GetAxis1Park() const
INumberVectorProperty ParkPositionNP
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
double GetAxis2Park() const
bool isParked()
isParked is mount currently parked?
virtual int AddTrackMode(const char *name, const char *label, bool isDefault=false)
AddTrackMode.
ISwitchVectorProperty TrackModeSP
ISwitchVectorProperty SlewRateSP
Connection::Serial * serialConnection
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
Connection::TCP * tcpConnection
INumberVectorProperty EqNP
@ TELESCOPE_HAS_TRACK_RATE
@ TELESCOPE_HAS_TRACK_MODE
@ TELESCOPE_CAN_CONTROL_TRACK
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
bool InitPark()
InitPark Loads parking data (stored in ~/.indi/ParkData.xml) that contains parking status and parking...
ISwitchVectorProperty MovementWESP
TelescopeStatus RememberTrackState
RememberTrackState Remember last state of Track State to fall back to in case of errors or aborts.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
void SetAxis2Park(double steps)
SetDEPark Set current DEC/ALT parking position. The data park file (stored in ~/.indi/ParkData....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
void SetParkDataType(TelescopeParkData type)
setParkDataType Sets the type of parking data stored in the park data file and presented to the user.
void SetAxis2ParkDefault(double steps)
SetDEParkDefault Set default DEC/ALT parking position.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
static void guideTimeoutHelperE(void *p)
virtual void simulationTriggered(bool enable) override
Inform driver that the simulation option was triggered. This function is called after setSimulation i...
virtual bool SetSlewRate(int index) override
SetSlewRate Set desired slew rate index.
bool ramp_movement(PMC8_DIRECTION calldir)
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool SetDefaultPark() override
SetDefaultPark Set default coordinates/encoders value as the desired parking position.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual bool updateProperties() override
Called when connected state changes, to add/remove properties.
static void rampTimeoutHelperN(void *p)
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool updateTime(ln_date *utc, double utc_offset) override
Update telescope time, date, and UTC offset.
static void AbortGotoTimeoutHelper(void *p)
virtual const char * getDefaultName() override
virtual bool SetTrackEnabled(bool enabled) override
SetTrackEnabled Engages or disengages mount tracking. If there are no tracking modes available,...
static void rampTimeoutHelperS(void *p)
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
static void rampTimeoutHelperE(void *p)
virtual bool Park() override
Park the telescope to its home position.
virtual bool SetCurrentPark() override
SetCurrentPark Set current coordinates/encoders value as the desired parking position.
virtual void debugTriggered(bool enable) override
Inform driver that the debug option was triggered. This function is called after setDebug is triggere...
virtual bool SetTrackRate(double raRate, double deRate) override
SetTrackRate Set custom tracking rates.
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
virtual bool updateLocation(double latitude, double longitude, double elevation) override
Update telescope location settings.
static void guideTimeoutHelperS(void *p)
static void guideTimeoutHelperW(void *p)
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
static void guideTimeoutHelperN(void *p)
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
void guideTimeout(PMC8_DIRECTION calldir)
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
virtual bool UnPark() override
Unpark the telescope if already parked.
static void rampTimeoutHelperW(void *p)
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
virtual bool SetTrackMode(uint8_t mode) override
SetTrackMode Set active tracking mode. Do not change track state.
const char * GUIDE_TAB
GUIDE_TAB Where all the properties for guiding are located.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
void IERmTimer(int timerid)
Remove the timer with the given timerid, as returned from IEAddTimer() or IEAddPeriodicTimer().
int IEAddTimer(int millisecs, IE_TCF *fp, void *p)
Register a new single-shot timer function, fp, to be called with ud as argument after ms.
void set_sim_system_status(IEQ_SYSTEM_STATUS value)
double range24(double r)
range24 Limits a number to be between 0-24 range.
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string. sprint the variable a in sexagesimal format into out[].
Implementations for common driver routines.
#define TRACKRATE_SIDEREAL
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#define LOGF_INFO(fmt,...)
#define LOGF_EXTRA3(fmt,...)
#define LOGF_DEBUG(fmt,...)
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
#define LOGF_ERROR(fmt,...)
const char * CONNECTION_TAB
#define PMC8_TRACKING_AUTODETECT_INTERVAL
#define PMC8_DEFAULT_IP_ADDRESS
#define PMC8_VERSION_MINOR
#define PMC8_DEFAULT_PORT
#define PMC8_VERSION_MAJOR
bool get_pmc8_guide_rate(int fd, PMC8_AXIS axis, double &rate)
void set_pmc8_location(double latitude, double longitude)
bool set_pmc8_custom_ra_track_rate(int fd, double rate)
bool start_pmc8_guide(int fd, PMC8_DIRECTION gdir, int ms, long &timetaken_us, double ratehint)
void set_pmc8_sim_system_status(PMC8_SYSTEM_STATUS value)
void set_pmc8_device(const char *name)
bool stop_pmc8_guide(int fd, PMC8_DIRECTION gdir)
void set_pmc8_debug(bool enable)
bool sync_pmc8(int fd, double ra, double dec)
bool abort_pmc8_goto(int fd)
bool slew_pmc8(int fd, double ra, double dec)
bool get_pmc8_is_scope_slewing(int fd, bool &isslew)
bool set_pmc8_track_mode(int fd, uint8_t mode)
bool set_pmc8_radec(int fd, double ra, double dec)
void set_pmc8_mountParameters(int index)
bool set_pmc8_guide_rate(int fd, PMC8_AXIS axis, double rate)
void set_pmc8_simulation(bool enable)
void set_pmc8_goto_resume(bool resume)
bool get_pmc8_firmware(int fd, FirmwareInfo *info)
bool get_pmc8_coords(int fd, double &ra, double &dec)
bool get_pmc8_reconnect_flag()
bool get_pmc8_tracking_data(int fd, double &rate, uint8_t &mode)
bool check_pmc8_connection(int fd, PMC8_CONNECTION_TYPE connection)
void set_pmc8_sim_move_rate(int value)
bool stop_pmc8_tracking_motion(int fd)
void set_pmc8_sim_track_rate(PMC8_TRACK_RATE value)
void set_pmc8_sim_ra(double ra)
bool set_pmc8_ra_tracking(int fd, double rate)
void set_pmc8_sim_dec(double dec)
bool set_pmc8_move_rate_axis(int fd, PMC8_DIRECTION dir, int reqrate)
#define PMC8_MAX_MOVE_RATE
#define PMC8_MAX_TRACK_RATE
PMC8_MOUNT_TYPES MountType
std::string MainBoardFirmware
static Logger & getInstance()
Method to get a reference to the object (i.e., Singleton) It is a static method.
int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName)
Adds a new debugging level to the driver.
PMC8_RAMP_DIRECTION rampDir
double round(double value, int decimal_places)