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
 */
{
    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
 */
{
    long Result;
    printf("\n\ntestUnits ---------------------------------------------------\n");
    printf("MinPos_mm: %f\n", MinPos_mm);
    printf("MaxVel_mm_s: %f\n", MaxVel_mm_s);
    printf("MaxVel_mm_min: %f\n", MaxVel_mm_min);
    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("MaxVel_mm_min: %f\n", NemV4DeviceVelToMillimetresPerMinute(Nemesys1, Nemesys1->MaxVelocity));
    printf("MaxLevel_ul: %f\n", MaxLevel_ul);
    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);
}
/**
 * Tests the basic move functionality with device specific units
 */
{
    long Result;
    int32_t PosIs;
    printf("\n\ntestBasicMoveFunctions --------------------------------------\n");
    Result = NemV4GetPosIs(Nemesys1, &PosIs);
    RETURN_ON_ERROR(Result);
    printf("PosIs : %d\n", PosIs);
    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);
    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
 */
{
    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
 */
{
    long Result;
    int32_t Distance = Nemesys1->MinPos / 10;
    double MaxLevel_ul;
    double MaxFlow_ul_min;
    printf("\n\ntestDoseVolume ----------------------------------------------\n");
    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
 */
{
    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
 */
{
    long Result;
    printf("\n\ntestAnalogInReading -----------------------------------------\n");
    int16_t AnalogValue_mV;
    RETURN_ON_ERROR(Result);
    printf("Analog %d: %d mV", NEM4_ANALOG_IN_EXTERNAL , 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
 */
{
    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)
    {
        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);
        Result = NemV4WriteDigitalOutput(Nemesys1, NEM4_DIG_OUT_BLUE_LED, 1);
        RETURN_ON_ERROR(Result);
        CSI_SLEEP_MS(250);
    }
    return ERR_NOERR;
}
/**
 * Test valve switching function
 */
{
    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
 */
{
    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
 */
{
    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;
    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
    //
    RETURN_ON_ERROR(Result);
    //
    // If the port is open, we initialize the device object Nemesys1.
    //
    RETURN_ON_ERROR(Result);
    //
    // Now the device object is properly initialized and we can print some
    // information from the initialized device object members
    //
    //
    // 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
    //
    RETURN_ON_ERROR(Result);
    printf("\n\nNemesys V4 API Test finished ================================\n");
    return EXIT_SUCCESS;
}
 
          
          