//////////////////////////////////////////////////////////////////////
//
// PmcaCom.cpp: implementation of the PmcaCom module.
//
// This module is a part of the PMCA COM package. It contains PMCA COM
// Application Programming Interface (API) functions.
//
// Amptek Inc. 2000
//
//////////////////////////////////////////////////////////////////////

#include "request.h"

// Local utility fucntions

static int PutSimpleRequestAndWait(OpCodeType code)
{
    int stat;
    RequestType *request = AllocateRequest(code, NULL);
    stat = PutRequest(request);
    return stat;
}

static int PutSimpleRequest(OpCodeType code, int *result)
{
    int stat;
    RequestType *request = AllocateRequest(code, result);
    stat = PutRequest(request);
    return stat;
}

static int ValidateComPort(int port)
{
    int stat = PMCA_ERROR_SUCCESS;
    if (port < 0 || port > MAX_COM_PORT)
        stat = PMCA_ERROR_INVALID_COM_PORT;
    return stat;
}

static int ValidatePointer(void *pointer)
{
    int stat = PMCA_ERROR_SUCCESS;
    if (!pointer)
        stat = PMCA_ERROR_INVALID_DATA_POINTER;
    return stat;
}

static int ValidateGroup(int group)
{
    int stat = PMCA_ERROR_SUCCESS;
    if (group < 0 || group > MAX_GROUP)
        stat = PMCA_ERROR_INVALID_GROUP;
    return stat;
}

// PMCA COM Application Programming Interface functions

// Synchronous functions

// Get Device Type

PmcaDeviceType PMCA_CALL PmcaGetDeviceType(void)
{
    return GetDeviceType();
}

// Terminate PMCA Communication 

PMCA_RETURN PmcaTerminateCom(void)
{
    int stat = TerminateCom();
    return stat;
}

// Set Priority

PMCA_RETURN PmcaSetPriority(int priority)
{
    int stat = SetPriority(priority);
    return stat;
}

// Cancel Request

PMCA_RETURN PmcaCancel(int requestId)
{
    int stat = CancelRequest(requestId);
    return stat;
}

// Wait for request completion

PMCA_RETURN PmcaWait(int requestId)
{
    int stat = WaitForRequestCompletion(requestId);
    return stat;
}

// Synchronous and Asynchronous functions

// PowerUp

static int MakePowerUpRequest(int *result, int port)
{
    int stat = ValidateComPort(port);
    if (!stat)
    {
        RequestType *request = AllocateRequest(OP_POWER_UP, result);
        request->p.powerUpPort = port;
        stat = PutRequest(request);
    }
    return stat;
}

PMCA_RETURN PmcaPowerUp(int port)
{
    int stat = MakePowerUpRequest(NULL, port);
    return stat;
}

PMCA_RETURN PmcaAsyncPowerUp(int *result, int port)
{
    int stat = MakePowerUpRequest(result, port);
    return stat;
}

// Connect

static int MakeConnectRequest(int *result,
        int port, int baudRate, PmcaDeviceType device)
{
    int stat = ValidateComPort(port);
    if (stat)
        goto L_Leave;
    if ((baudRate < MIN_BAUD_RATE) || (baudRate > MAX_BAUD_RATE))
        stat = PMCA_ERROR_INVALID_BAUD_RATE;
    else
    {
        RequestType *request = AllocateRequest(OP_CONNECT, result);
        request->p.connect.baudRate = baudRate;
        request->p.connect.device = device;
        request->p.connect.port = port;
        stat = PutRequest(request);
    }
L_Leave:
    return stat;
}

PMCA_RETURN PmcaConnect(int port, int baudRate, PmcaDeviceType device)
{
    int stat = MakeConnectRequest(NULL, port, baudRate, device);
    return stat;
}

PMCA_RETURN PmcaAsyncConnect(int *result,
        int port, int baudRate, PmcaDeviceType device)
{
    int stat = MakeConnectRequest(result, port, baudRate, device);
    return stat;
}

// Disconnect

PMCA_RETURN PmcaDisconnect(void)
{
    int stat = PutSimpleRequestAndWait(OP_DISCONNECT);
    return stat;
}

PMCA_RETURN PmcaAsyncDisconnect(int *result)
{
    int stat = PutSimpleRequest(OP_DISCONNECT, result);
    return stat;
}

// Get Serial Number

PMCA_RETURN PmcaGetSerialNumber(void)
{
    int stat = PutSimpleRequestAndWait(OP_GET_SERIAL_NUMBER);
    return stat;
}

PMCA_RETURN PmcaAsyncGetSerialNumber(int *result)
{
    int stat = PutSimpleRequest(OP_GET_SERIAL_NUMBER, result);
    return stat;
}

// Get Battery Type

PMCA_RETURN PmcaGetBatteryType(void)
{
    int stat = PutSimpleRequestAndWait(OP_GET_BATTERY_TYPE);
    return stat;
}

PMCA_RETURN PmcaAsyncGetBatteryType(int *result)
{
    int stat = PutSimpleRequest(OP_GET_BATTERY_TYPE, result);
    return stat;
}

// Get Battery Condition

PMCA_RETURN PmcaGetBatteryCondition(void)
{
    int stat = PutSimpleRequestAndWait(OP_GET_BATTERY_CONDITION);
    return stat;
}

PMCA_RETURN PmcaAsyncGetBatteryCondition(int *result)
{
    int stat = PutSimpleRequest(OP_GET_BATTERY_CONDITION, result);
    return stat;
}

// Get Battery Capacity

PMCA_RETURN PmcaGetBatteryCapacity(void)
{
    int stat = PutSimpleRequestAndWait(OP_GET_BATTERY_CAPACITY);
    return stat;
}

PMCA_RETURN PmcaAsyncGetBatteryCapacity(int *result)
{
    int stat = PutSimpleRequest(OP_GET_BATTERY_CAPACITY, result);
    return stat;
}

// Get Group

PMCA_RETURN PmcaGetGroup(void)
{
    int stat = PutSimpleRequestAndWait(OP_GET_GROUP);
    return stat;
}

PMCA_RETURN PmcaAsyncGetGroup(int *result)
{
    int stat = PutSimpleRequest(OP_GET_GROUP, result);
    return stat;
}

// Get Threshold

PMCA_RETURN PmcaGetThreshold(void)
{
    int stat = PutSimpleRequestAndWait(OP_GET_THRESHOLD);
    return stat;
}

PMCA_RETURN PmcaAsyncGetThreshold(int *result)
{
    int stat = PutSimpleRequest(OP_GET_THRESHOLD, result);
    return stat;
}

// Get Gain

PMCA_RETURN PmcaGetGain(void)
{
    int stat = PutSimpleRequestAndWait(OP_GET_GAIN);
    return stat;
}

PMCA_RETURN PmcaAsyncGetGain(int *result)
{
    int stat = PutSimpleRequest(OP_GET_GAIN, result);
    return stat;
}

// Get Real Time (in milliseconds)

PMCA_RETURN PmcaGetRealTime(void)
{
    int stat = PutSimpleRequestAndWait(OP_GET_REAL_TIME);
    return stat;
}

PMCA_RETURN PmcaAsyncGetRealTime(int *result)
{
    int stat = PutSimpleRequest(OP_GET_REAL_TIME, result);
    return stat;
}

// Get Live Time (in milliseconds)

PMCA_RETURN PmcaGetLiveTime(void)
{
    int stat = PutSimpleRequestAndWait(OP_GET_LIVE_TIME);
    return stat;
}

PMCA_RETURN PmcaAsyncGetLiveTime(int *result)
{
    int stat = PutSimpleRequest(OP_GET_LIVE_TIME, result);
    return stat;
}

// Get Flags

static int GetFlags(int *result, PmcaFlagsType *flags)
{
    int stat = ValidatePointer(flags);
    if (!stat)
    {
        RequestType *request = AllocateRequest(OP_GET_FLAGS, result);
        request->p.flagsPtr = flags;
        stat = PutRequest(request);
    }
    return stat;
}

PMCA_RETURN PmcaGetFlags(PmcaFlagsType *flags)
{
    int stat = GetFlags(NULL, flags);
    return stat;
}

PMCA_RETURN PmcaAsyncGetFlags(int *result, PmcaFlagsType *flags)
{
    int stat = GetFlags(result, flags);
    return stat;
}

// Get Status

static int GetStatus(int *result, PmcaStatusType *status)
{
    int stat = ValidatePointer(status);
    if (!stat)
    {
        RequestType *request = AllocateRequest(OP_GET_STATUS, result);
        request->p.statusPtr = status;
        stat = PutRequest(request);
    }
    return stat;
}

PMCA_RETURN PmcaGetStatus(PmcaStatusType *status)
{
    int stat = GetStatus(NULL, status);
    return stat;
}

PMCA_RETURN PmcaAsyncGetStatus(int *result, PmcaStatusType *status)
{
    int stat = GetStatus(result, status);
    return stat;
}

// Get Data

static int GetData(int *result,
        unsigned long *buffer, int channel, int dwordCount)
{
    int stat = ValidatePointer(buffer);
    if (!stat)			//changed from if(stat) to if(!stat)
    {
        RequestType *request = AllocateRequest(OP_GET_DATA, result);
        request->p.data.buffer = (BYTE *) buffer;
        request->p.data.channel = channel;
        request->p.data.dwordCount = dwordCount;
        stat = PutRequest(request);
    }
    return stat;
}

PMCA_RETURN PmcaGetData(unsigned long *buffer,
        int channel, int dwordCount)
{
    int stat = GetData(NULL, buffer, channel, dwordCount);
    return stat;
}

PMCA_RETURN PmcaAsyncGetData(int *result,
        unsigned long *buffer, int channel, int dwordCount)
{
    int stat = GetData(result, buffer, channel, dwordCount);
    return stat;
}

// Get Time

static int GetDateAndTime(int *result, char *strDateTime)
{
    int stat = ValidatePointer(strDateTime);
    if (!stat)
    {
        RequestType *request =
                AllocateRequest(OP_GET_DATE_TIME, result);
        request->p.strDateTime = strDateTime;
        stat = PutRequest(request);
    }
    return stat;
}

PMCA_RETURN PmcaGetDateAndTime(char *strDateTime)
{
    int stat = GetDateAndTime(NULL, strDateTime);
    return stat;
}

PMCA_RETURN PmcaAsyncGetDateAndTime(int *result, char *strDateTime)
{
    int stat = GetDateAndTime(result, strDateTime);
    return stat;
}

// Set functions

// Set Absolute Peak Mode

PMCA_RETURN PmcaSetAbsolutePeakMode(void)
{
    int stat = PutSimpleRequestAndWait(OP_SET_ABSOLUTE_PEAK_MODE);
    return stat;
}

PMCA_RETURN PmcaAsyncSetAbsolutePeakMode(int *result)
{
    int stat = PutSimpleRequest(OP_SET_ABSOLUTE_PEAK_MODE, result);
    return stat;
}

// Set First Peak Mode

PMCA_RETURN PmcaSetFirstPeakMode(void)
{
    int stat = PutSimpleRequestAndWait(OP_SET_FIRST_PEAK_MODE);
    return stat;
}

PMCA_RETURN PmcaAsyncSetFirstPeakMode(int *result)
{
    int stat = PutSimpleRequest(OP_SET_FIRST_PEAK_MODE, result);
    return stat;
}

// Select Real Timer

PMCA_RETURN PmcaSelectRealTimer(void)
{
    int stat = PutSimpleRequestAndWait(OP_SELECT_REAL_TIMER);
    return stat;
}

PMCA_RETURN PmcaAsyncSelectRealTimer(int *result)
{
    int stat = PutSimpleRequest(OP_SELECT_REAL_TIMER, result);
    return stat;
}

// Select Live Timer

PMCA_RETURN PmcaSelectLiveTimer(void)
{
    int stat = PutSimpleRequestAndWait(OP_SELECT_LIVE_TIMER);
    return stat;
}

PMCA_RETURN PmcaAsyncSelectLiveTimer(int *result)
{
    int stat = PutSimpleRequest(OP_SELECT_LIVE_TIMER, result);
    return stat;
}

// Clear Data

PMCA_RETURN PmcaClearData(void)
{
    int stat = PutSimpleRequestAndWait(OP_CLEAR_DATA);
    return stat;
}

PMCA_RETURN PmcaAsyncClearData(int *result)
{
    int stat = PutSimpleRequest(OP_CLEAR_DATA, result);
    return stat;
}

// Clear time

PMCA_RETURN PmcaClearTime(void)
{
    int stat = PutSimpleRequestAndWait(OP_CLEAR_TIME);
    return stat;
}

PMCA_RETURN PmcaAsyncClearTime(int *result)
{
    int stat = PutSimpleRequest(OP_CLEAR_TIME, result);
    return stat;
}

// Clear data and time

PMCA_RETURN PmcaClearDataAndTime(void)
{
    int stat = PutSimpleRequestAndWait(OP_CLEAR_DATA_AND_TIME);
    return stat;
}

PMCA_RETURN PmcaAsyncClearDataAndTime(int *result)
{
    int stat = PutSimpleRequest(OP_CLEAR_DATA_AND_TIME, result);
    return stat;
}

// Start Acquisition

static int StartAcquisition(int *result, int setStartTime)
{
    int stat;
    RequestType *request =
            AllocateRequest(OP_START_ACQUISITION, result);
    request->p.setAcquisitionStartTime = setStartTime;
    stat = PutRequest(request);
    return stat;
}

PMCA_RETURN PmcaStartAcquisition(int setStartTime)
{
    int stat = StartAcquisition(NULL, setStartTime);
    return stat;
}

PMCA_RETURN PmcaAsyncStartAcquisition(int *result, int setStartTime)
{
    int stat = StartAcquisition(result, setStartTime);
    return stat;
}

// Stop Acquisition

PMCA_RETURN PmcaStopAcquisition(void)
{
    int stat = PutSimpleRequestAndWait(OP_STOP_ACQUISITION);
    return stat;
}

PMCA_RETURN PmcaAsyncStopAcquisition(int *result)
{
    int stat = PutSimpleRequest(OP_STOP_ACQUISITION, result);
    return stat;
}

// Set Group

static int SetGroup(int *result, int group)
{
    int stat = ValidateGroup(group);
    if (!stat)
    {
        RequestType *request = AllocateRequest(OP_SET_GROUP, result);
        request->p.group = group;
        stat = PutRequest(request);
    }
    return stat;
}

PMCA_RETURN PmcaSetGroup(int group)
{
    int stat = SetGroup(NULL, group);
    return stat;
}

PMCA_RETURN PmcaAsyncSetGroup(int *result, int group)
{
    int stat = SetGroup(result, group);
    return stat;
}

// Set Gain

static int SetGain(int *result, int gain)
{
    int stat;
    if (gain <= (MIN_GAIN >> 1) || gain > MAX_GAIN)
        stat = PMCA_ERROR_INVALID_GAIN;
    else
    {
        RequestType *request = AllocateRequest(OP_SET_GAIN, result);
        request->p.gain = gain;
        stat = PutRequest(request);
    }
    return stat;
}

PMCA_RETURN PmcaSetGain(int gain)
{
    int stat = SetGain(NULL, gain);
    return stat;
}

PMCA_RETURN PmcaAsyncSetGain(int *result, int gain)
{
    int stat = SetGain(result, gain);
    return stat;
}

// Set Time

static BYTE MakeBcd(char *digits, BYTE maxValue)
{
    BYTE out = 0;
    char b = digits[0];
    if (b < '0' || b > '9')
        goto L_Error;
    b -= '0';
    out |= (b << 4);
    b = digits[1];
    if (b < '0' || b > '9')
        goto L_Error;
    b -= '0';
    out |= (b & 0xF);
    if (out > maxValue)
        goto L_Error;
L_Leave:
    return out;
L_Error:
    out = 255;
    goto L_Leave;
}

static int SetTime(int *result, char *strTime)
{
    BYTE oneByte;
    RequestType *request;
    int stat = ValidatePointer(strTime);
    if (stat)
        goto L_Leave;
    request = AllocateRequest(OP_SET_TIME, result);
    oneByte = MakeBcd(strTime, 0x23);
    if (oneByte == 255)
        goto L_Error;
    request->p.timeStamp.hours = oneByte;
    oneByte = MakeBcd(strTime + 3, 0x59);
    if (oneByte == 255)
        goto L_Error;
    request->p.timeStamp.minutes = oneByte;
    oneByte = MakeBcd(strTime + 6, 0x59);
    if (oneByte == 255)
        goto L_Error;
    request->p.timeStamp.seconds = oneByte;
    stat = PutRequest(request);
L_Leave:
    return stat;
L_Error:
    stat = PMCA_ERROR_INVALID_TIME;
    goto L_Leave;    
}

PMCA_RETURN PmcaSetTime(char *strTime)
{
    int stat = SetTime(NULL, strTime);
    return stat;
}

PMCA_RETURN PmcaAsyncSetTime(int *result, char *strTime)
{
    int stat = SetTime(result, strTime);
    return stat;
}

// Set Date

static int SetDate(int *result, char *strDate)
{
    BYTE oneByte;
    RequestType *request;
    int stat = ValidatePointer(strDate);
    if (stat)
        goto L_Leave;
    request = AllocateRequest(OP_SET_DATE, result);
    oneByte = MakeBcd(strDate, 0x12);
    if (oneByte == 255)
        goto L_Error;
    request->p.dateStamp.month = oneByte;
    oneByte = MakeBcd(strDate + 3, 0x31);
    if (oneByte == 255)
        goto L_Error;
    request->p.dateStamp.day = oneByte;
    oneByte = MakeBcd(strDate + 6, 0x20);
    if (oneByte == 255)
        goto L_Error;
   // if (oneByte != 0x19)	removed by tjp on 1/11/01 to allow for y2k dates
     //   goto L_Error;
    request->p.dateStamp.century = oneByte;
    oneByte = MakeBcd(strDate + 8, 0x99);
    if (oneByte == 255)
        goto L_Error;
    request->p.dateStamp.year = oneByte;
    stat = PutRequest(request);
L_Leave:
    return stat;
L_Error:
    stat = PMCA_ERROR_INVALID_DATE;
    goto L_Leave;    
}

PMCA_RETURN PmcaSetDate(char *strDate)
{
    int stat = SetDate(NULL, strDate);
    return stat;
}

PMCA_RETURN PmcaAsyncSetDate(int *result, char *strDate)
{
    int stat = SetDate(result, strDate);
    return stat;
}

// Set Lock

static int SetLock(int *result, int lock)
{
    int stat;
    RequestType *request = AllocateRequest(OP_SET_LOCK, result);
    request->p.lock = lock;
    stat = PutRequest(request);
    return stat;
}

PMCA_RETURN PmcaSetLock(int lock)
{
    int stat = SetLock(NULL, lock);
    return stat;
}

PMCA_RETURN PmcaAsyncSetLock(int *result, int lock)
{
    int stat = SetLock(result, lock);
    return stat;
}

// Set Battery Type

static int SetBatteryType(int *result, PmcaBatteryType batteryType)
{
    int stat;
    RequestType *request =
            AllocateRequest(OP_SET_BATTERY_TYPE, result);
    request->p.batteryType = batteryType;
    stat = PutRequest(request);
    return stat;
}

PMCA_RETURN PmcaSetBatteryType(PmcaBatteryType batteryType)
{
    int stat = SetBatteryType(NULL, batteryType);
    return stat;
}

PMCA_RETURN PmcaAsyncSetBatteryType(int *result, PmcaBatteryType batteryType)
{
    int stat = SetBatteryType(result, batteryType);
    return stat;
}

// Set Acquisition Time

static int SetAcquisitionTime(int *result, int time)
{
    int stat;
    if (time < 0 || time > 0xFFFFFF)
        stat = PMCA_ERROR_INVALID_ACQUISITION_TIME;
    else
    {
        RequestType *request =
                AllocateRequest(OP_SET_ACQUISITION_TIME, result);
        request->p.time = time;
        stat = PutRequest(request);
    }
    return stat;
}

PMCA_RETURN PmcaSetAcquisitionTime(int time)
{
    int stat = SetAcquisitionTime(NULL, time);
    return stat;
}

PMCA_RETURN PmcaAsyncSetAcquisitionTime(int *result, int time)
{
    int stat = SetAcquisitionTime(result, time);
    return stat;
}

// Set  Threshold

static int SetThreshold(int *result, short threshold)
{
    int stat;
    if (threshold < 0)
        stat = PMCA_ERROR_INVALID_THRESHOLD;
    else
    {
        RequestType *request =
                AllocateRequest(OP_SET_THRESHOLD, result);
        request->p.threshold = (unsigned short) threshold;
        stat = PutRequest(request);
    }
    return stat;
}

PMCA_RETURN PmcaSetThreshold(short threshold)
{
    int stat = SetThreshold(NULL, threshold);
    return stat;
}

PMCA_RETURN PmcaAsyncSetThreshold(int *result, short threshold)
{
    int stat = SetThreshold(result, threshold);
    return stat;
}
