NemV4Test.cpp

The example shows how to use the Nemesys V4 API from application code.

#include <nem4_rs232_api.h>
#include <math.h>
#include <stdio.h>
/**
* If the returned result is an error, then print the error and return the
* error code
*/
#define RETURN_ON_ERROR(_result_) \
if ((_result_) < ERR_NOERR) { \
showError(_result_, __LINE__); \
return (_result_); }
/**
* Checks the given expression
*/
#define CHECK(_result_) \
if (!(_result_)) { \
printf("Check in line %d failed: %s\n", __LINE__, #_result_); \
fprintf(stderr, "Check in line %d failed: %s\n", __LINE__, #_result_); }
/**
* Print error code and error description via CsiErrorToString() to std::out
*/
static long showError(long ErrCode, int Line)
{
if (ErrCode < 0)
{
printf("Error in line %d: 0x%08x: - %s\n", Line, (uint32_t)abs(ErrCode), CsiErrorToString(ErrCode));
fprintf(stderr, "Error in line %d: 0x%08x: - %s\n", Line, (uint32_t)abs(ErrCode), CsiErrorToString(ErrCode));
}
return ErrCode;
}
/**
* Waits until pump stops
*/
static long waitForStopped(TNemesysV4* Nemesys)
{
long Result;
/**
* Poll the device until dosing has been finished
*/
do
{
double Level_ul;
Result = NemV4GetSyringeLevel(Nemesys, &Level_ul);
double Flow_ul_min;
Result = NemV4GetCurrentFlow(Nemesys, &Flow_ul_min);
printf("Level_ul: %f Flow_ul_min: %f\n", Level_ul, Flow_ul_min);
Result = NemV4IsStopped(Nemesys);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(100);// do not block CPU
} while (0 == Result);
return Result;
}
/**
* Test unit conversion functions
*/
static long testUnits(TNemesysV4* Nemesys1)
{
long Result;
printf("\n\ntestUnits ---------------------------------------------------\n");
printf("VelocityMax: %d\n", Nemesys1->MaxVelocity);
printf("MaxPos: %d\n", Nemesys1->MaxPos);
printf("MinPos: %d\n", Nemesys1->MinPos);
printf("PosUnitsPerRevolution: %f\n", Nemesys1->PosUnitsPerRevolution);
printf("VelUnitsPerRPM: %f\n", Nemesys1->VelUnitsPerRPM);
double MinPos_mm = Nemesys1->MinPos / Nemesys1->PosUnitsPerRevolution;
printf("MinPos_mm: %f\n", MinPos_mm);
double MaxVel_mm_s = Nemesys1->MaxVelocity / 60.0 / Nemesys1->VelUnitsPerRPM;
printf("MaxVel_mm_s: %f\n", MaxVel_mm_s);
double MaxVel_mm_min = Nemesys1->MaxVelocity / Nemesys1->VelUnitsPerRPM;
printf("MaxVel_mm_min: %f\n", MaxVel_mm_min);
double SyringeArea_mm2 = M_PI * pow(Nemesys1->InnerSyringeDiameter_mm, 2) / 4;
printf("SyringeArea_mm2: %f\n", SyringeArea_mm2);
double MaxFlow_ul_min = MaxVel_mm_min * SyringeArea_mm2;
printf("MaxFlow_ul_min: %f\n", MaxFlow_ul_min);
double MaxVolume_ul = (0 - MinPos_mm) * SyringeArea_mm2;
printf("MaxVolume_ul: %f\n", MaxVolume_ul);
printf("MinPos_mm: %f\n", NemV4DevicePosToMillimetres(Nemesys1, Nemesys1->MinPos));
printf("MinPos: %d\n", NemV4MillimetresToDevicePos(Nemesys1, 60));
printf("MaxVel_mm_min: %f\n", NemV4DeviceVelToMillimetresPerMinute(Nemesys1, Nemesys1->MaxVelocity));
printf("MinVel: %d\n", NemV4MillimetresPerMinuteToDeviceVel(Nemesys1, 360));
double MaxLevel_ul = NemV4DevicePosToMicrolitres(Nemesys1, Nemesys1->MinPos);
printf("MaxLevel_ul: %f\n", MaxLevel_ul);
MaxFlow_ul_min = NemV4DeviceVelToMicrolitresPerMinute(Nemesys1, Nemesys1->MaxVelocity);
printf("MaxFlow_ul_min: %f\n", MaxFlow_ul_min);
int32_t MaxLevelPos = NemV4MicrolitresToDevicePos(Nemesys1, MaxLevel_ul);
printf("MaxLevelPos: %d\n", MaxLevelPos);
int32_t MaxVel = NemV4MicrolitresPerMinuteToDeviceVel(Nemesys1, MaxFlow_ul_min);
printf("MaxVel: %d\n", MaxVel);
Result = NemV4GetMaxFlow(Nemesys1, &MaxFlow_ul_min);
RETURN_ON_ERROR(Result);
printf("NemV4GetMaxFlow: %f\n", MaxFlow_ul_min);
NemV4GetMaxSyringeLevel(Nemesys1, &MaxLevel_ul);
RETURN_ON_ERROR(Result);
printf("NemV4GetMaxSyringeLevel: %f\n", MaxLevel_ul);
return ERR_NOERR;
}
/**
* Tests the basic move functionality with device specific units
*/
static long testBasicMoveFunctions(TNemesysV4* Nemesys1)
{
long Result;
int32_t PosIs;
printf("\n\ntestBasicMoveFunctions --------------------------------------\n");
Result = NemV4GetPosIs(Nemesys1, &PosIs);
RETURN_ON_ERROR(Result);
printf("PosIs : %d\n", PosIs);
Result = NemV4MoveWithVelocity(Nemesys1, 0 - (Nemesys1->MaxVelocity / 10));
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(100);// give drive some time to start
Result = NemV4IsStopped(Nemesys1);
RETURN_ON_ERROR(Result);
printf("NemV4IsStopped: %ld\n", Result);
CHECK(0 == Result);
CSI_SLEEP_MS(2000);// give drive some time to move
Result = NemV4Stop(Nemesys1);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(100);// give drive some time to stop
Result = NemV4IsStopped(Nemesys1);
RETURN_ON_ERROR(Result);
CHECK(1 == Result);
printf("NemV4IsStopped: %ld\n", Result);
Result = NemV4MoveToPos(Nemesys1, Nemesys1->MaxPos, Nemesys1->MaxVelocity);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(100);// give drive some time to start
/**
* Poll the device until dosing has been finished
*/
do
{
int32_t PosIs;
Result = NemV4GetPosIs(Nemesys1, &PosIs);
RETURN_ON_ERROR(Result);
printf("PosIs : %d\n", PosIs);
Result = NemV4IsStopped(Nemesys1);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(100);// do not block CPU
} while (0 == Result);
RETURN_ON_ERROR(Result);
return ERR_NOERR;
}
/**
* Tests set syringe level functionality
*/
static long testSetSyringeLevel(TNemesysV4* Nemesys1)
{
long Result;
double MaxLevel_ul;
double MaxFlow_ul_min;
printf("\n\ntestSetSyringeLevel -----------------------------------------\n");
Result = NemV4GetMaxSyringeLevel(Nemesys1, &MaxLevel_ul);
RETURN_ON_ERROR(Result);
Result = NemV4GetMaxFlow(Nemesys1, &MaxFlow_ul_min);
RETURN_ON_ERROR(Result);
Result = NemV4SetSyringeLevel(Nemesys1, MaxLevel_ul, MaxFlow_ul_min);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(100);// give drive some time to start
Result = waitForStopped(Nemesys1);
RETURN_ON_ERROR(Result);
Result = NemV4SetSyringeLevel(Nemesys1, 0, MaxFlow_ul_min);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(1000);// give drive some time to start
Result = waitForStopped(Nemesys1);
RETURN_ON_ERROR(Result);
return ERR_NOERR;
}
/**
* Tests dose volume functionality
*/
static long testDoseVolume(TNemesysV4* Nemesys1)
{
long Result;
int32_t Distance = Nemesys1->MinPos / 10;
double MaxLevel_ul;
double MaxFlow_ul_min;
printf("\n\ntestDoseVolume ----------------------------------------------\n");
Result = NemV4MoveDistance(Nemesys1, Distance, Nemesys1->MaxVelocity);
RETURN_ON_ERROR(Result);
Result = waitForStopped(Nemesys1);
RETURN_ON_ERROR(Result);
Distance = 0 - Distance;
Result = NemV4MoveDistance(Nemesys1, Distance, Nemesys1->MaxVelocity);
RETURN_ON_ERROR(Result);
Result = waitForStopped(Nemesys1);
RETURN_ON_ERROR(Result);
Result = NemV4GetMaxSyringeLevel(Nemesys1, &MaxLevel_ul);
RETURN_ON_ERROR(Result);
Result = NemV4GetMaxFlow(Nemesys1, &MaxFlow_ul_min);
RETURN_ON_ERROR(Result);
double Volume_ul = MaxLevel_ul / 5;
Result = NemV4DoseVolume(Nemesys1, Volume_ul, MaxFlow_ul_min);
RETURN_ON_ERROR(Result);
Result = waitForStopped(Nemesys1);
RETURN_ON_ERROR(Result);
Volume_ul = 0 - Volume_ul;
Result = NemV4DoseVolume(Nemesys1, Volume_ul, MaxFlow_ul_min);
RETURN_ON_ERROR(Result);
Result = waitForStopped(Nemesys1);
RETURN_ON_ERROR(Result);
return ERR_NOERR;
}
/**
* Test generate flow functionality
*/
static long testGenerateFlow(TNemesysV4* Nemesys1)
{
double MaxFlow_ul_min;
long Result;
printf("\n\ntestGenerateFlow --------------------------------------------\n");
Result = NemV4GetMaxFlow(Nemesys1, &MaxFlow_ul_min);
RETURN_ON_ERROR(Result);
Result = NemV4GenerateFlow(Nemesys1, -MaxFlow_ul_min);
RETURN_ON_ERROR(Result);
Result = waitForStopped(Nemesys1);
RETURN_ON_ERROR(Result);
Result = NemV4GenerateFlow(Nemesys1, MaxFlow_ul_min);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(3000);
Result = NemV4Stop(Nemesys1);
RETURN_ON_ERROR(Result);
return ERR_NOERR;
}
/**
* Tests analog in reading
*/
static long testAnalogInReading(TNemesysV4* Nemesys1)
{
long Result;
printf("\n\ntestAnalogInReading -----------------------------------------\n");
int16_t AnalogValue_mV;
Result = NemV4ReadAnalogInput(Nemesys1, NEM4_ANALOG_IN_EXTERNAL, &AnalogValue_mV);
RETURN_ON_ERROR(Result);
printf("Analog %d: %d mV", NEM4_ANALOG_IN_EXTERNAL , AnalogValue_mV);
Result = NemV4ReadAnalogInput(Nemesys1, NEM4_ANALOG_IN_FORCE_SENSOR, &AnalogValue_mV);
RETURN_ON_ERROR(Result);
printf("Analog %d: %d mV", NEM4_ANALOG_IN_FORCE_SENSOR , AnalogValue_mV);
return ERR_NOERR;
}
/**
* Tests setting of digital outputs
*/
static long testDigitalOutputs(TNemesysV4* Nemesys1)
{
long Result;
uint32_t DigOutMask = NEM4_DIG_OUT_BLUE_LED;
printf("\n\ntestDigitalOutputs ------------------------------------------\n");
//
// Blink the blue LED with frequency of 1 HZ using NemV4WriteDigitalOutputs
//
for (int i = 0; i < 5; ++i)
{
Result = NemV4WriteDigitalOutputs(Nemesys1, DigOutMask, ~NEM4_DIG_OUT_BLUE_LED);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(500);
Result = NemV4WriteDigitalOutputs(Nemesys1, DigOutMask, NEM4_DIG_OUT_BLUE_LED);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(500);
}
//
// Blink the blue LED with frequency of 2 HZ using NemV4WriteDigitalOutput
//
for (int i = 0; i < 5; ++i)
{
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(250);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(250);
}
return ERR_NOERR;
}
/**
* Test valve switching function
*/
static long testValveSwitching(TNemesysV4* Nemesys1)
{
long Result;
printf("\n\ntestValveSwitching ------------------------------------------\n");
//
// Cycle through all 4 valve positions
//
for (uint8_t ValvePosition = 0; ValvePosition <= 3; ++ValvePosition)
{
Result = NemV4SwitchValve(Nemesys1, ValvePosition);
RETURN_ON_ERROR(Result);
CSI_SLEEP_MS(1000);
}
return ERR_NOERR;
}
/**
* Tests force monitoring switching
*/
static long testForceMonitoringSwitching(TNemesysV4* Nemesys1)
{
long Result;
uint32_t DigInputs;
printf("\n\ntestForceMonitoringSwitching --------------------------------\n");
//
// Normally safety stop should be inactive
//
Result = NemV4IsSafetyStopActive(Nemesys1);
RETURN_ON_ERROR(Result);
printf("SafetyStop: %ld\n", Result);
CHECK(0 == Result);
//
// We disable force monitoring - this should cause an activaton of the
// safety stop
//
Result = NemV4EnableForceMonitoring(Nemesys1, 0);
RETURN_ON_ERROR(Result);
//
// Safety stop should be on now
//
Result = NemV4IsSafetyStopActive(Nemesys1);
RETURN_ON_ERROR(Result);
printf("SafetyStop: %ld\n", Result);
CHECK(1 == Result);
//
// If safety stop is active, then the device should be disabled
//
Result = NemV4IsEnabled(Nemesys1);
RETURN_ON_ERROR(Result);
printf("IsEnabled: %ld\n", Result);
CHECK(0 == Result);
//
// We enable force monitoring - this should clear the safety stop
//
Result = NemV4EnableForceMonitoring(Nemesys1, 1);
RETURN_ON_ERROR(Result);
//
// Force monitoring is enabled so safety stop should be cleared now
//
Result = NemV4IsSafetyStopActive(Nemesys1);
RETURN_ON_ERROR(Result);
printf("SafetyStop: %ld\n", Result);
CHECK(0 == Result);
Result = NemV4SetEnabled(Nemesys1);
RETURN_ON_ERROR(Result);
//
// Now device should be enabled again
//
Result = NemV4IsEnabled(Nemesys1);
RETURN_ON_ERROR(Result);
printf("IsEnabled: %ld\n", Result);
CHECK(1 == Result);
return ERR_NOERR;
}
/**
* Tests force monitoring
*/
static long testForceMonitoring(TNemesysV4* Nemesys1)
{
float Force_kN;
long Result;
printf("\n\ntestForceMonitoring -----------------------------------------\n");
Result = NemV4ReadForceSensor(Nemesys1, &Force_kN);
RETURN_ON_ERROR(Result);
printf("Force: %f kN\n", Force_kN);
Result = NemV4WriteForceLimit(Nemesys1, 0.1);
RETURN_ON_ERROR(Result);
return ERR_NOERR;
}
int main(int argc, char *argv[])
{
TNemesysV4 Nemesys1;
struct CsiBus CsiBus;
long Result;
//
// Disable std stream buffering for immediate output
//
setbuf(stdout, NULL);
setbuf(stderr, NULL);
printf("\n\nNemesys V4 API Test =========================================\n");
//
// First open the serial port 1 (on Windows COM6) with a baudrate of
// 115200 and a timeout value of 100 ms
//
Result = CsiOpen(&CsiBus, "COM6", CSI_BAUD_115200, 200);
RETURN_ON_ERROR(Result);
//
// If the port is open, we initialize the device object Nemesys1.
//
Result = NemV4DevInit(&CsiBus, 2, &Nemesys1);
RETURN_ON_ERROR(Result);
//
// Now the device object is properly initialized and we can print some
// information from the initialized device object members
//
printf("ProductType: %d\n", Nemesys1.ProductType);
printf("ForceLimitScaling.Factor: %f\n", Nemesys1.ForceLimitScaling.Factor);
printf("ForceLimitScaling.Offset: %f\n", Nemesys1.ForceLimitScaling.Offset);
//
// Enable force monitoring - pumping is only possible if force monitoring
// is enabled
//
Result = NemV4EnableForceMonitoring(&Nemesys1, 1);
RETURN_ON_ERROR(Result);
//
// Ensure that device is not in fault state after power up
//
Result = NemV4ClearFault(&Nemesys1);
RETURN_ON_ERROR(Result);
//
// Now we enable the drive - after this call the position controller is
// active and the drive power stage is powered
//
Result = NemV4SetEnabled(&Nemesys1);
RETURN_ON_ERROR(Result);
//
// Check if enabling the device was successful - if not, then something
// went wrong and you should check errors
//
Result = NemV4IsEnabled(&Nemesys1);
RETURN_ON_ERROR(Result);
CHECK(1 == Result);
//
// Now run the various tests
//
Result = testUnits(&Nemesys1);
RETURN_ON_ERROR(Result);
Result = testBasicMoveFunctions(&Nemesys1);
RETURN_ON_ERROR(Result);
Result = testSetSyringeLevel(&Nemesys1);
RETURN_ON_ERROR(Result);
Result = testDoseVolume(&Nemesys1);
RETURN_ON_ERROR(Result);
Result = testGenerateFlow(&Nemesys1);
RETURN_ON_ERROR(Result);
Result = testAnalogInReading(&Nemesys1);
RETURN_ON_ERROR(Result);
Result = testDigitalOutputs(&Nemesys1);
RETURN_ON_ERROR(Result);
Result = testValveSwitching(&Nemesys1);
RETURN_ON_ERROR(Result);
Result = testForceMonitoringSwitching(&Nemesys1);
RETURN_ON_ERROR(Result);
Result = testForceMonitoring(&Nemesys1);
RETURN_ON_ERROR(Result);
//
// Now close the connection to the device
//
Result = CsiClose(&CsiBus);
RETURN_ON_ERROR(Result);
printf("\n\nNemesys V4 API Test finished ================================\n");
return EXIT_SUCCESS;
}