/***************************************************************************
 *   Copyright (C) 2004 by EVER Sp. z o.o.                                 *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#include "ccomm.h"
#include "conf.h"
#include "common.h"

#define NET3000_DRIVER_BUILD 1
#include "net3000.h"

/* 
 * Helper macros
 */
#undef COMMIOFAIL
#define COMMIOFAIL( v, en )  					\
	if ( COMMFAIL( v ) ) 						\
	{											\
		iNet3k_ExtError = en; 					\
		return IOCTL_ERROR_COMM_LINKFAIL;		\
	}

/* 
 * Deklaracje zmiennych globalnych
 */
sdrv_config sdcNet3k;
int iNet3k_ExtError = 0;
CComm	commNet3k;

int net3k_ioctl(long lCommand, void *lpvBuff, int *lpiBuffSize)
{
	switch(lCommand)
	{
	case IOCTL_INIT: 
		return Net3k_DoInit(lpvBuff, lpiBuffSize);

	case IOCTL_UNINIT:
		return Net3k_DoUnInit(lpvBuff, lpiBuffSize);
		
	case IOCTL_GETCONFIGFILENAME:
		return Net3k_DoGetConfigFileName(lpvBuff, lpiBuffSize);

	case IOCTL_AUTOCONFIGURE: 
		return Net3k_DoAutoConfigure(lpvBuff, lpiBuffSize);

	case IOCTL_CONFIGURE: 
		return Net3k_DoConfigure(lpvBuff, lpiBuffSize);

	case IOCTL_GET_UPSINFOMASK: 
		return Net3k_DoGetUpsInfoMask(lpvBuff, lpiBuffSize);

	case IOCTL_SET_UPSINFOMASK:
		return Net3k_DoSetUpsInfoMask(lpvBuff, lpiBuffSize);

	case IOCTL_GET_UPSSTATESMASK:
		return Net3k_DoGetUpsStateMask(lpvBuff, lpiBuffSize);

	case IOCTL_SET_UPSSTATESMASK:
		return Net3k_DoSetUpsStateMask(lpvBuff, lpiBuffSize);

	case IOCTL_GET_UPSSTATE:
		return Net3k_DoGetUpsState(lpvBuff, lpiBuffSize);

	case IOCTL_GET_UPSPARAMSMASK:
		return Net3k_DoGetUpsParamsMask(lpvBuff, lpiBuffSize);

	case IOCTL_SET_UPSPARAMSMASK:
		return Net3k_DoSetUpsParamsMask(lpvBuff, lpiBuffSize);

	case IOCTL_GET_UPSPARAMS:
		return Net3k_DoGetUpsParams(lpvBuff, lpiBuffSize);

	case IOCTL_GET_UPSSETUPPARAMSMASK:
		return Net3k_DoGetUpsSetupParamsMask(lpvBuff, lpiBuffSize);

	case IOCTL_SET_UPSSETUPPARAMSMASK:
		return Net3k_DoSetUpsSetupParamsMask(lpvBuff, lpiBuffSize);

	case IOCTL_GET_UPSSETUPPARAMS:
		return Net3k_DoGetUpsSetupParams(lpvBuff, lpiBuffSize);

	case IOCTL_SET_UPSSETUPPARAMS:
		return Net3k_DoSetUpsSetupParams(lpvBuff, lpiBuffSize);

	case IOCTL_GET_UPSCHARACTERISTICMASK:
		return Net3k_DoGetUpsCharacteristicMask(lpvBuff, lpiBuffSize);

	case IOCTL_GET_UPSCHARACTERISTIC:
		return Net3k_DoGetUpsCharacteristic(lpvBuff, lpiBuffSize);

	case IOCTL_GET_DRIVER_INFO:
		return Net3k_DoGetDriverInfo(lpvBuff, lpiBuffSize);

	case IOCTL_GET_ERRORNO:
		return Net3k_DoGetExtendedError(lpvBuff, lpiBuffSize);

	case IOCTL_TESTUPSLINK:
		return Net3k_DoTestUpsLink(lpvBuff, lpiBuffSize);

	case IOCTL_GETCONFIGPARAMSCOUNT:
		return Net3k_DoGetConfigParamsCount(lpvBuff, lpiBuffSize);

	case IOCTL_GETCONFIGPARAMS:
		return Net3k_DoGetConfigParams(lpvBuff, lpiBuffSize);

	case IOCTL_GETCONFIGPARAM:
		return Net3k_DoGetConfigParam(lpvBuff, lpiBuffSize);

	case IOCTL_SETCONFIGPARAMS:
		return Net3k_DoSetConfigParams(lpvBuff, lpiBuffSize);

	case IOCTL_SETCONFIGPARAM:
		return Net3k_DoSetConfigParam(lpvBuff, lpiBuffSize);

	case IOCTL_UPDATECONFIG:
		return Net3k_DoUpdateConfig(lpvBuff, lpiBuffSize);

	case IOCTL_GETDRIVERMODE:
		return Net3k_DoGetDriverMode(lpvBuff, lpiBuffSize);

	case IOCTL_SHUTDOWNUPS:
		return Net3k_DoUpsShutdown(lpvBuff, lpiBuffSize);

	default:
		return IOCTL_ERROR_CMD_NOTSUPPORTED;
	}
}

// Function name	: Net3k_DoInit
// Description		: Inicjalizacja drivera
int Net3k_DoInit( void *lpvBuff, int *lpiBuffSize )
{
	iNet3k_ExtError = 0;

	if (Net3k_ReadConfig() != IOCTL_ERROR_SUCCESS)
		return IOCTL_ERROR_CONFIG_READFAIL;

	commNet3k.init(sdcNet3k.szSerialPort, B2400);
	if (commNet3k.open()!=COMM_SUCCESS) {
		iNet3k_ExtError=IOCTL_ERROR_COMM_INITFAIL;
		return IOCTL_ERROR;
	}
	
	iNet3k_ExtError = 0;
	Net3k_DoUpdateConfig(NULL, NULL);

	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoUnInit
// Description		: Deinicjalizacja drivera
int Net3k_DoUnInit( void *lpvBuff, int *lpiBuffSize )
{
	if (commNet3k.close()!=COMM_SUCCESS) {
		iNet3k_ExtError=0;
		return IOCTL_ERROR;
	}
	
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoUnInit
// Description		: 
int Net3k_DoGetConfigFileName( void *lpvBuff, int *lpiBuffSize )
{
	if (lpvBuff != NULL) {
		if ( *lpiBuffSize >= strlen(DRIVER_CONFIG_FILE) )
			strcpy((char *)lpvBuff, DRIVER_CONFIG_FILE );
		else
			return IOCTL_ERROR_INVALIDARGUMENT;
	} else
		return IOCTL_ERROR_INVALIDARGUMENT;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoAutoConfigure
// Description		: Self configure
int Net3k_DoAutoConfigure( void *lpvBuff, int *lpiBuffSize )
{
	sdcNet3k.iSerialPort=1;
	sprintf( sdcNet3k.szSerialPort, "/dev/ttyS%d", sdcNet3k.iSerialPort );
	
	sdcNet3k.uiSetupTable[SETUP_ITEM_STANDBY_TIME] = DEFAULT_STANDBY_TIME;
	sdcNet3k.uiSetupTable[SETUP_ITEM_BUZZER_EN] = 1;
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_LOWER] = DEFAULT_LOWER_TT;
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_AVR] = DEFAULT_AVR_TT;
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_UPPER] = DEFAULT_UPPER_TT;
	sdcNet3k.uiSetupTable[SETUP_ITEM_KEYB_LOCK] = 0;
	
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoConfigure
// Description		: Configure driver to work properly with UPS and reinit
int Net3k_DoConfigure( void *lpvBuff, int *lpiBuffSize )
{
	sdcNet3k.iSerialPort=1;
	sprintf( sdcNet3k.szSerialPort, "/dev/ttyS%d", sdcNet3k.iSerialPort );
	
	sdcNet3k.uiSetupTable[SETUP_ITEM_STANDBY_TIME] = DEFAULT_STANDBY_TIME;
	sdcNet3k.uiSetupTable[SETUP_ITEM_BUZZER_EN] = 1;
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_LOWER] = DEFAULT_LOWER_TT;
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_AVR] = DEFAULT_AVR_TT;
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_UPPER] = DEFAULT_UPPER_TT;
	sdcNet3k.uiSetupTable[SETUP_ITEM_KEYB_LOCK] = 0;
	
	Net3k_DoUnInit(NULL, NULL);
	Net3k_DoInit(NULL, NULL);

	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoGetUpsInfoMask
// Description		: Zwraca informacje o wypelnieniu struktury informacji o UPS-ie
int Net3k_DoGetUpsInfoMask( void *lpvBuff, int *lpiBuffSize )
{
	unsigned long ulMask = UI_PARAMETERS | UI_SETUP_PARAMETERS | UI_UPS_STATE;

	if ( *lpiBuffSize == sizeof( unsigned long ) )
		memcpy( lpvBuff, &ulMask, sizeof( unsigned long ) );
	else
		return IOCTL_ERROR_INVALIDARGUMENT;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoSetUpsInfoMask
// Description		: 
int	Net3k_DoSetUpsInfoMask(void *lpvBuff, int *lpiBuffSize)
{
	return IOCTL_ERROR_CMD_NOTSUPPORTED;
}

// Function name	: Net3k_DoGetUpsStateMask
// Description		: 
int	Net3k_DoGetUpsStateMask(void *lpvBuff, int *lpiBuffSize)
{
	unsigned long	ulMask = US_POWERON | US_POWERFAIL | US_STANDBY | 
		US_OVERLOAD | US_BATTERYLOW;

	if ( *lpiBuffSize == sizeof( unsigned long ) )
		memcpy( lpvBuff, &ulMask, sizeof( unsigned long ) );
	else
		return IOCTL_ERROR_INVALIDARGUMENT;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoSetUpsStateMask
// Description		: 
int	Net3k_DoSetUpsStateMask(void *lpvBuff, int *lpiBuffSize)
{
	return IOCTL_ERROR_CMD_NOTSUPPORTED;
}

// Function name	: Net3k_DoGetUpsState
// Description		: Return actual UPS state
int	Net3k_DoGetUpsState(void *lpvBuff, int *lpiBuffSize)
{
#undef ADJUST_BITS
#define ADJUST_BITS(src, sbit, sres, dest, dbit) { \
	if ((src&sbit)==sres) dest|=dbit; else dest&=~(dbit); }

	unsigned long ulUpsState = 0;
	unsigned int uiUpsState, uiUpsData[PARAMS_TABLE_ITEMS] = { 0 };
	int iRet, iSize;

	if (lpiBuffSize != NULL)
		if (*lpiBuffSize < sizeof(ulUpsState))
			return IOCTL_ERROR_INVALIDARGUMENT;

	iSize = PARAMS_TABLE_ITEMS;
	iRet = Net3k_DoGetUPSdata(EU_MAIN, uiUpsData, &iSize);
	if (iRet != IOCTL_ERROR_SUCCESS) {
		return iRet;
	}
	uiUpsState = uiUpsData[PARAMS_ITEM_SYSFLAG];
	// Currently supported flags are :
	// US_POWERON | US_POWERFAIL | US_STANDBY | US_OVERLOAD | US_BATTERYLOW

	// konwersja bitów do standardu pscore
	ADJUST_BITS( uiUpsState, USB_AND_POWERFAIL, USB_FLAG_POWERFAIL, ulUpsState, US_POWERFAIL );
	ADJUST_BITS( uiUpsState, USB_AND_POWEROK, USB_FLAG_POWEROK, ulUpsState, US_POWERON );
	ADJUST_BITS( uiUpsState, USB_AND_STANDBY, USB_FLAG_STANDBY, ulUpsState, US_STANDBY );
	ADJUST_BITS( uiUpsState, USB_AND_OVERLOAD, USB_FLAG_OVERLOAD, ulUpsState, US_OVERLOAD );

	if (uiUpsData[PARAMS_ITEM_V_AKU] < 440) 
		ulUpsState |= US_BATTERYLOW;
	else
		ulUpsState &= ~(US_BATTERYLOW);

	memcpy( lpvBuff, &ulUpsState, *lpiBuffSize );

	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoGetUpsParamsMask
// Description		: 
int	Net3k_DoGetUpsParamsMask(void *lpvBuff, int *lpiBuffSize)
{
	__int64 iMask = UP_PST_UPPER|UP_PST_LOWER|UP_PST_AVRUP|
		UP_FRQ_OUTPUT|UP_VLT_INPUT|UP_VLT_BATTERY|UP_UID_FAMILY|UP_UID_MODEL;

	if (*lpiBuffSize == sizeof(__int64))
		memcpy(lpvBuff, &iMask, sizeof(__int64));
	else
		return IOCTL_ERROR_INVALIDARGUMENT;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoSetUpsParamsMask
// Description		: 
int	Net3k_DoSetUpsParamsMask(void *lpvBuff, int *lpiBuffSize)
{
	return IOCTL_ERROR_CMD_NOTSUPPORTED;
}

// Function name	: Net3k_DoGetUpsParams
// Description		: 
int	Net3k_DoGetUpsParams(void *lpvBuff, int *lpiBuffSize)
{
	int	iSize, iRet, iMul;
	unsigned int uiModel;
	supsp sup;
	struct tagModel { 
		int iId; char szName[32]; 
	} sModel[UPS_MAX_MODELS * 2] = { 
		{ INT_UPS_MODEL1, UPS_MODEL1 }
	};

	if (lpiBuffSize != NULL)
		if (*lpiBuffSize < sizeof( supsp ))
			return IOCTL_ERROR_INVALIDARGUMENT;

	iSize = PARAMS_TABLE_ITEMS;
	iRet = Net3k_GetAllUpsParams( sdcNet3k.uiParamsTable, &iSize );
	if (iRet != IOCTL_ERROR_SUCCESS)
		return iRet;

	// fill params mask
	sup.iMask = UP_PST_UPPER|UP_PST_LOWER|UP_PST_AVRUP|
		UP_FRQ_OUTPUT|UP_VLT_INPUT|UP_VLT_BATTERY|UP_UID_FAMILY|UP_UID_MODEL;

	uiModel = sdcNet3k.uiParamsTable[IDXP_UPSTYPE];

	// by default, unknown ups type
	sprintf( sup.sz__uid_model, "%s %s", DRIVER_UPS_PREFIX, DRIVER_UPS_SUFFIX );
	sprintf( sup.sz__uid_family, "%s", DRIVER_UPS_FAMILY );

	// czestotliwosc wejsciowa
	sup.ui__frq_output = 50;
	sup.ui__frq_output_div = 1;

	// napiecie sieciowe - wejsciowe
	sup.ui__vlt_input = sdcNet3k.uiParamsTable[PARAMS_ITEM_V_INPUT];
	sup.ui__vlt_input_div = 1;

	// napiecie akumulatora,
	// jest to: 
	// 12V dla 500;  
	// 24V dla 700-1400; 
	// 48 dla 2200-3000;
	iMul = 1;
	sup.ui__vlt_battery = (unsigned int)sdcNet3k.uiParamsTable[PARAMS_ITEM_V_AKU] * iMul;
	sup.ui__vlt_battery_div = 10;
	
	// napiecie przelaczania AVR
	sup.ui__pst_avrup = (unsigned int)sdcNet3k.uiParamsTable[PARAMS_ITEM_TH_AVR];
	sup.ui__pst_avrup_div = 1;
	// napiecie przelaczania - gorny prog
	sup.ui__pst_upper = (unsigned int)sdcNet3k.uiParamsTable[PARAMS_ITEM_TH_UPPER];
	sup.ui__pst_upper_div = 1;
	// napiecie przelaczania - dolny prog
	sup.ui__pst_lower = (unsigned int)sdcNet3k.uiParamsTable[PARAMS_ITEM_TH_LOWER];
	sup.ui__pst_lower_div = 1;

	memcpy( lpvBuff, &sup, sizeof(supsp) );

	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoGetUpsSetupParamsMask
// Description		: 
int	Net3k_DoGetUpsSetupParamsMask(void *lpvBuff, int *lpiBuffSize)
{
	unsigned long ulMask = UP_SET_PST_UPPER|UP_SET_PST_LOWER|UP_SET_PST_AVRUP|
		UP_SET_AAL_ON|UP_SET_TMR_POWERFAILTOSTANDBY;

	if ( *lpiBuffSize == sizeof( unsigned long ) )
		memcpy( lpvBuff, &ulMask, sizeof( unsigned long ) );
	else
		return IOCTL_ERROR_INVALIDARGUMENT;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoSetUpsSetupParamsMask
// Description		: 
int	Net3k_DoSetUpsSetupParamsMask(void *lpvBuff, int *lpiBuffSize)
{
	return IOCTL_ERROR_CMD_NOTSUPPORTED;
}

// Function name	: Net3k_DoGetUpsSetupParams
// Description		: 
int	Net3k_DoGetUpsSetupParams(void *lpvBuff, int *lpiBuffSize)
{
	supssp susp;

	if (lpiBuffSize != NULL)
		if (*lpiBuffSize < sizeof(unsigned int) * SETUP_TABLE_ITEMS)
			return IOCTL_ERROR_INVALIDARGUMENT;

	susp.ulMask = UP_SET_PST_UPPER|UP_SET_PST_LOWER|UP_SET_PST_AVRUP|
		UP_SET_AAL_ON|UP_SET_TMR_POWERFAILTOSTANDBY;

	// TODO:: reading from configuration file and/or directly from UPS
	
	susp.ui__set_pst_upper = sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_UPPER];
	susp.ui__set_pst_upper_div = 1;
	susp.ui__set_pst_lower = sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_LOWER];
	susp.ui__set_pst_lower_div = 1;
	susp.ui__set_pst_avrup = sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_AVR];
	susp.ui__set_pst_avrup_div = 1;
	susp.ui__set_aal_on = sdcNet3k.uiSetupTable[SETUP_ITEM_BUZZER_EN];
	susp.ui__set_tmr_powerfailtostandby = sdcNet3k.uiSetupTable[SETUP_ITEM_STANDBY_TIME];
	susp.ui__set_tmr_powerfailtostandby_div = 1;

	memcpy( lpvBuff, &susp, *lpiBuffSize );

	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoSetUpsSetupParams
// Description		: 
int	Net3k_DoSetUpsSetupParams(void *lpvBuff, int *lpiBuffSize)
{
	return IOCTL_ERROR_CMD_NOTSUPPORTED;
}

// Function name	: Net3k_DoGetDriverInfo
// Description		: 
int	Net3k_DoGetDriverInfo(void *lpvBuff, int *lpiBuffSize)
{
	if (*lpiBuffSize != sizeof(sdrv_info))
		return IOCTL_ERROR_INVALIDARGUMENT;
	sprintf( (( lpsdrv_info )lpvBuff )->szName, "%s %s DRIVER", DRIVER_UPS_PREFIX, DRIVER_UPS_SUFFIX );
	sprintf( (( lpsdrv_info )lpvBuff )->szFamily, "%s", DRIVER_UPS_FAMILY );
	((lpsdrv_info)lpvBuff)->eLink = ul_serial;
	((lpsdrv_info)lpvBuff)->uiVersionMajor = DRIVER_VERSION_MAJOR;
	((lpsdrv_info)lpvBuff)->uiVersionMinor = DRIVER_VERSION_MINOR;
	strcpy(((lpsdrv_info)lpvBuff)->szCfgFileName, DRIVER_CONFIG_FILE);
	strcpy(((lpsdrv_info)lpvBuff)->szBmpFileName, DRIVER_BITMAP_FILE);
	
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoGetExtendedError
// Description		: Get extended error information - return value of last error
int	Net3k_DoGetExtendedError(void *lpvBuff, int *lpiBuffSize)
{
	return iNet3k_ExtError;
}

// Function name	: Net3k_DoGetUpsCharacteristicMask
// Description		: 
int	Net3k_DoGetUpsCharacteristicMask(void *lpvBuff, int *lpiBuffSize)
{
	unsigned long ulMask = UC_PST_LOWER_MIN|UC_PST_LOWER_MAX|UC_PST_UPPER_MIN|UC_PST_UPPER_MAX|UC_PST_AVRUP_MIN;

	if ( *lpiBuffSize == sizeof( unsigned long ) )
		memcpy( lpvBuff, &ulMask, sizeof( unsigned long ) );
	else
		return IOCTL_ERROR_INVALIDARGUMENT;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoGetUpsCharacteristic
// Description		: 
int	Net3k_DoGetUpsCharacteristic(void *lpvBuff, int *lpiBuffSize)
{
	supsch such;

	memset( &such, 0, sizeof(supsch) );

	such.ulMask = UC_PST_LOWER_MIN|UC_PST_LOWER_MAX|UC_PST_UPPER_MIN|UC_PST_UPPER_MAX|UC_PST_AVRUP_MIN;

	such.ui__pst_avrup_min = 200;
	such.ui__pst_avrup_min_div = 1;
	such.ui__pst_lower_max = 195;
	such.ui__pst_lower_max_div = 1;
	such.ui__pst_lower_min = 160;
	such.ui__pst_lower_min_div = 1;
	such.ui__pst_upper_max = 280;
	such.ui__pst_upper_max_div = 1;
	such.ui__pst_upper_min = 240;
	such.ui__pst_upper_min_div = 1;

	memcpy( lpvBuff, &such, *lpiBuffSize );

	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoTestUpsLink
// Description		: 
int	Net3k_DoTestUpsLink(void *lpvBuff, int *lpiBuffSize)
{
	unsigned int uiInfo[PARAMS_TABLE_ITEMS];
	int	iSize, iRet;
	for (int i = 0; i < 3; i++) {
		// Czyszczenie ramki
		iSize = PARAMS_TABLE_ITEMS;
		iRet = Net3k_DoGetUPSdata(EU_MAIN, (void*)&uiInfo, &iSize);
		if (iRet != IOCTL_ERROR_SUCCESS) {
			usleep(500000);
			continue;
		}else
			return IOCTL_ERROR_SUCCESS;
	}
	if (iRet != IOCTL_ERROR_SUCCESS)
		return iRet;
	return IOCTL_ERROR_SUCCESS;
}

// Read specified table from UPS
int Net3k_DoGetUPSdata(eups_datatypes eType, void *lpvBuff, int *lpiBuffSize)
{
	unsigned char ucDataBuff[255] = { 0 };
	unsigned int uiDataBuff[255] = { 0 };
	unsigned long ulCRC = 0, ulTmp;
	unsigned int uiLength = 0;
	int iCnt = 0;
	
	if (!commNet3k.isInitialized())
		return IOCTL_ERROR_NOTYETINITIALIZED;

	if (eType == EU_MAIN) {
		for (iCnt = 0; iCnt < 4; iCnt++) {
			commNet3k.flush(1,1);
			COMMIOFAIL( commNet3k.send(FRAME_INITCODE), IOCTL_ERROR_COMM_FAILTOSEND );
			usleep(100000);
			COMMIOFAIL( commNet3k.receive(&ucDataBuff[0]), IOCTL_ERROR_COMM_FAILTORECEIVE );
			if (ucDataBuff[0] == FRAME_INITCODE)
				break;
			usleep(500000);
		}
		if (ucDataBuff[0] != FRAME_INITCODE) {
			iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDCODE;
			return IOCTL_ERROR_COMM_LINKFAIL;
		}
		COMMIOFAIL( commNet3k.send(85), IOCTL_ERROR_COMM_FAILTOSEND );
		COMMIOFAIL( commNet3k.send(85), IOCTL_ERROR_COMM_FAILTOSEND );
		usleep(250000);
		COMMIOFAIL( commNet3k.receive(&ucDataBuff[1]), IOCTL_ERROR_COMM_FAILTORECEIVE );
		if (ucDataBuff[1] != 100) {
			iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDCODE;
			return IOCTL_ERROR_COMM_LINKFAIL;
		} else {
			ulCRC = ucDataBuff[1];
			// receive bulk with CRC
			for (int ir = 0; ir < IDXP_TAB_ITEMS; ir++) {
				COMMIOFAIL( commNet3k.receive(&ucDataBuff[ir]), IOCTL_ERROR_COMM_FAILTORECEIVE );
				ulCRC += ucDataBuff[ir];
			}
			COMMIOFAIL( commNet3k.receive(&ucDataBuff[IDXP_TAB_ITEMS]), IOCTL_ERROR_COMM_FAILTORECEIVE );
			ulCRC += ucDataBuff[IDXP_TAB_ITEMS];
			COMMIOFAIL( commNet3k.receive(&ucDataBuff[IDXP_TAB_ITEMS+1]), IOCTL_ERROR_COMM_FAILTORECEIVE );
			
			ulCRC = ulCRC % 256;
			if (ulCRC != ucDataBuff[IDXP_TAB_ITEMS+1]){
				iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDCRC;
				return IOCTL_ERROR_COMM_LINKFAIL;
			}
		}
		// przepisanie do tablicy

		// typ zasilacza
		uiDataBuff[PARAMS_ITEM_UPSTYPE] = (unsigned int)ucDataBuff[IDXP_UPSTYPE];
		// próg górny
		ulTmp = ucDataBuff[IDXP_TH_UPPER_LSB] + (ucDataBuff[IDXP_TH_UPPER_MSB] * 256);
		uiDataBuff[PARAMS_ITEM_TH_UPPER] = (unsigned int)((float)ulTmp / 3.72f);
		// próg avr
		ulTmp = ucDataBuff[IDXP_TH_AVR_LSB] + (ucDataBuff[IDXP_TH_AVR_MSB] * 256);
		uiDataBuff[PARAMS_ITEM_TH_AVR] = (unsigned int)((float)ulTmp / 3.72f);
		// próg dolny
		ulTmp = ucDataBuff[IDXP_TH_LOWER_LSB] + (ucDataBuff[IDXP_TH_LOWER_MSB] * 256);
		uiDataBuff[PARAMS_ITEM_TH_LOWER] = (unsigned int)((float)ulTmp / 3.72f);
		// napiecie aku
		ulTmp = ucDataBuff[IDXP_U_AKU];
		uiDataBuff[PARAMS_ITEM_V_AKU] = (unsigned int)(((ulTmp * 150) / 255) * 4);
		// napiecie wejsciowe
		ulTmp = ucDataBuff[IDXP_U_IN_LSB] + (ucDataBuff[IDXP_U_IN_MSB] * 256);
		uiDataBuff[PARAMS_ITEM_V_INPUT] = (unsigned int)((float)ulTmp / 3.72f);
		// moc wyjsciowa
		uiDataBuff[PARAMS_ITEM_POWEROUT] = (unsigned int)((ucDataBuff[IDXP_POWER_OUT] * 1800) / 221);
		// sysflag
		uiDataBuff[PARAMS_ITEM_SYSFLAG] = (unsigned int)ucDataBuff[IDXP_REG47];
		// wielkosc tablicy
		uiLength = PARAMS_TABLE_ITEMS;
	}


	if (eType == EU_EXTENDED) {
		for (iCnt = 0; iCnt < 4; iCnt++) {
			COMMIOFAIL( commNet3k.send( FRAME_INITCODE ), IOCTL_ERROR_COMM_FAILTOSEND );
			COMMIOFAIL( commNet3k.receive( &ucDataBuff[0] ), IOCTL_ERROR_COMM_FAILTORECEIVE );
			usleep(500000);
			if (ucDataBuff[0] == FRAME_INITCODE)
				break;
		}
		if (ucDataBuff[0] != FRAME_INITCODE) {
			iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDCODE;
			return IOCTL_ERROR_COMM_LINKFAIL;
		}
		COMMIOFAIL( commNet3k.send(170), IOCTL_ERROR_COMM_FAILTOSEND );
		COMMIOFAIL( commNet3k.send(170), IOCTL_ERROR_COMM_FAILTOSEND );
		usleep(250000);
		COMMIOFAIL( commNet3k.receive(&ucDataBuff[1]), IOCTL_ERROR_COMM_FAILTORECEIVE );
		if (ucDataBuff[1] != 100) {
			iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDCODE;
			return IOCTL_ERROR_COMM_LINKFAIL;
		} else {
			ulCRC = ucDataBuff[1];
			// receive bulk with CRC
			for (int ir = 0; ir < IDXPEXT_TAB_ITEMS; ir++) {
				COMMIOFAIL( commNet3k.receive(&ucDataBuff[ir]), IOCTL_ERROR_COMM_FAILTORECEIVE );
				ulCRC += ucDataBuff[ir];
			}
			COMMIOFAIL( commNet3k.receive(&ucDataBuff[IDXPEXT_TAB_ITEMS]), IOCTL_ERROR_COMM_FAILTORECEIVE );
			ulCRC += ucDataBuff[IDXPEXT_TAB_ITEMS];
			COMMIOFAIL( commNet3k.receive(&ucDataBuff[IDXPEXT_TAB_ITEMS+1]), IOCTL_ERROR_COMM_FAILTORECEIVE );
			
			ulCRC = ulCRC % 256;
			if (ulCRC != ucDataBuff[IDXPEXT_TAB_ITEMS + 1]){
				iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDCRC;
				return IOCTL_ERROR_COMM_LINKFAIL;
			}
		}
		// przepisanie do tablicy

		// wirtualna pojemnosc aku
		ulTmp = ucDataBuff[IDXPEXT_L3AKU] + (ucDataBuff[IDXPEXT_L2AKU] * 256) + 
			(ucDataBuff[IDXPEXT_L1AKU] * 65536);
		uiDataBuff[EXT_PARAMS_ITEM_AKUVIRTCAP] = (unsigned int)((ulTmp / 3000000) * 100);
		// wspolczynnik
		ulTmp = ucDataBuff[IDXPEXT_WSP_AKU2] + (ucDataBuff[IDXPEXT_WSP_AKU1] * 256);
		uiDataBuff[EXT_PARAMS_ITEM_AKUFACTOR] = (unsigned int)ulTmp;
		// ilosc modulow
		uiDataBuff[EXT_PARAMS_ITEM_MODULENO] = (unsigned int)ucDataBuff[IDXPEXT_MODULE_NO];
		// napiecie aku na baterii
		uiDataBuff[EXT_PARAMS_ITEM_V_AKU] = (unsigned int)ucDataBuff[IDXPEXT_V_AKU];
		// moc wyjsciowa na baterii
		uiDataBuff[EXT_PARAMS_ITEM_POWEROUT] = (unsigned int)ucDataBuff[IDXPEXT_POWER_OUT];
		// wielkosc tablicy
		uiLength = EXT_PARAMS_TABLE_ITEMS;
	}

	// skopiuj do bufora wejsciowego nowe dane
	memcpy(lpvBuff, &uiDataBuff, *lpiBuffSize * sizeof(unsigned int));

	if (uiLength > (unsigned int)*lpiBuffSize)
		iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDLENGTH;
	else
		iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: DoSetUPSdata
// Description		: Set specified UPS parameter
// Return type		: int 
// Argument         : eups_datatypes eType
// Argument         : void *lpvBuff
// Argument         : int *lpiBuffSize
int Net3k_DoSetUPSdata(eups_datatypes eType, void *lpvBuff, int *lpiBuffSize)
{
	unsigned char ucDataBuff[128] = { 0 }, ucDataOut[128] = { 0 };
	unsigned int uiDataBuff[255] = { 0 };
	unsigned long ulCRC = 0, ulTmp;
	unsigned int uiLength = 0;
	int iCnt = 0;

	if (!commNet3k.isInitialized())
		return IOCTL_ERROR_NOTYETINITIALIZED;

	if (eType == EU_SET_MAIN) {
		if (SETUP_TABLE_ITEMS != (unsigned int)*lpiBuffSize) {
			iNet3k_ExtError = IOCTL_ERROR_BUFFER_TOOSMALL;
			return IOCTL_ERROR;
		} else {
			memcpy(&uiDataBuff, lpvBuff, *lpiBuffSize * sizeof(unsigned int));
		}
		ucDataOut[IDXS_SYSFLAG_OR] = 0xFF;
		ucDataOut[IDXS_SYSFLAG_AND] = 0xFF;
		// beeper
		if (uiDataBuff[SETUP_ITEM_BUZZER_EN])
			ucDataOut[IDXS_SYSFLAG_OR] = SFB_AND_SOUND;
		else
			ucDataOut[IDXS_SYSFLAG_AND] = SFB_AND_SOUND;
		// transfer tresholds
		ulTmp = (unsigned long)ceil((float)uiDataBuff[SETUP_ITEM_V_TH_UPPER] * 3.72f);
		ucDataOut[IDXS_TH_UPPER_LSB] = LOBYTE((unsigned int)ulTmp);
		ucDataOut[IDXS_TH_UPPER_MSB] = HIBYTE((unsigned int)ulTmp);
		ulTmp = (unsigned long)ceil((float)uiDataBuff[SETUP_ITEM_V_TH_AVR] * 3.72f);
		ucDataOut[IDXS_TH_AVR_LSB] = LOBYTE((unsigned int)ulTmp);
		ucDataOut[IDXS_TH_AVR_MSB] = HIBYTE((unsigned int)ulTmp);
		ulTmp = (unsigned long)ceil((float)uiDataBuff[SETUP_ITEM_V_TH_LOWER] * 3.72f);
		ucDataOut[IDXS_TH_LOWER_LSB] = LOBYTE((unsigned int)ulTmp);
		ucDataOut[IDXS_TH_LOWER_MSB] = HIBYTE((unsigned int)ulTmp);
		// module number
		ucDataOut[IDXS_MODULE_NO] = (unsigned char)(uiDataBuff[SETUP_ITEM_MODULE_NO]!=0)?2:1;
		// keyboard block
		ucDataOut[IDXS_KEYB_LOCK] = (unsigned char)uiDataBuff[SETUP_ITEM_KEYB_LOCK]?1:64;

		ulCRC = 204;
		for (iCnt = 0; iCnt < IDXS_TAB_ITEMS; iCnt++)
			ulCRC += ucDataOut[iCnt];
		ucDataOut[IDXS_TAB_ITEMS] = (unsigned char)(ulCRC % 256);

		commNet3k.flush(1, 1);

		for (iCnt = 0; iCnt < 4; iCnt++) {
			COMMIOFAIL( commNet3k.send(FRAME_INITCODE), IOCTL_ERROR_COMM_FAILTOSEND );
			usleep(100000);
			COMMIOFAIL( commNet3k.receive(&ucDataBuff[0]), IOCTL_ERROR_COMM_FAILTORECEIVE );
			if (ucDataBuff[0] == FRAME_INITCODE)
				break;
			usleep(500000);
		}
		if (ucDataBuff[0] != FRAME_INITCODE) {
			iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDCODE;
			return IOCTL_ERROR_COMM_LINKFAIL;
		}
		COMMIOFAIL( commNet3k.send(204), IOCTL_ERROR_COMM_FAILTOSEND );
		COMMIOFAIL( commNet3k.send(ucDataOut, IDXS_TAB_ITEMS + 1), IOCTL_ERROR_COMM_FAILTOSEND );
		usleep(100000);
		COMMIOFAIL( commNet3k.receive(&ucDataBuff[1]), IOCTL_ERROR_COMM_FAILTORECEIVE );
		if (ucDataBuff[1] != 100) {
			iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDCODE;
			return IOCTL_ERROR_COMM_LINKFAIL;
		} else {
			iNet3k_ExtError = 0;
			return IOCTL_ERROR_SUCCESS;
		}
	}

	if (eType == EU_SET_UPSSHUTDOWN) {
		if (1 != (unsigned int)*lpiBuffSize) {
			iNet3k_ExtError = IOCTL_ERROR_BUFFER_TOOSMALL;
			return IOCTL_ERROR;
		} else {
			memcpy(&uiDataBuff, lpvBuff, *lpiBuffSize * sizeof(unsigned int));
		}

		ucDataOut[0] = (unsigned char)((float)uiDataBuff[0] / 1.28f);
		ulCRC = 15;
		ulCRC += ucDataOut[0];
		ucDataOut[1] = (unsigned char)ulCRC % 256;

		commNet3k.flush(1, 1);

		for (iCnt = 0; iCnt < 4; iCnt++) {
			COMMIOFAIL( commNet3k.send(FRAME_INITCODE), IOCTL_ERROR_COMM_FAILTOSEND );
			COMMIOFAIL( commNet3k.receive(&ucDataBuff[0]), IOCTL_ERROR_COMM_FAILTORECEIVE );
			usleep(500000);
			if (ucDataBuff[0] == FRAME_INITCODE)
				break;
		}
		if (ucDataBuff[0] != FRAME_INITCODE) {
			iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDCODE;
			return IOCTL_ERROR_COMM_LINKFAIL;
		}
		COMMIOFAIL( commNet3k.send(15), IOCTL_ERROR_COMM_FAILTOSEND );
		COMMIOFAIL( commNet3k.send(ucDataOut, 2), IOCTL_ERROR_COMM_FAILTOSEND );
		COMMIOFAIL( commNet3k.receive(&ucDataBuff[1]), IOCTL_ERROR_COMM_FAILTORECEIVE );
		if (ucDataBuff[1] != 100) {
			iNet3k_ExtError = IOCTL_ERROR_COMM_INVALIDCODE;
			return IOCTL_ERROR_COMM_LINKFAIL;
		} else {
			iNet3k_ExtError = 0;
			return IOCTL_ERROR_SUCCESS;
		}
	}

	iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoGetConfigParamsCount
// Description		: 
int	Net3k_DoGetConfigParamsCount(void *lpvBuff, int *lpiBuffSize)
{
	unsigned long ulCount = INT_MAX_SETUPITEMS;

	if ( lpiBuffSize != NULL )
		if ( *lpiBuffSize < sizeof( unsigned long ) )
			return IOCTL_ERROR_INVALIDARGUMENT;

	memcpy( lpvBuff, &ulCount, sizeof( ulCount ) );

	iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoGetConfigParams
// Description		: 
int	Net3k_DoGetConfigParams(void *lpvBuff, int *lpiBuffSize)
{
	int	icnt;
	scfg_value scfgvaldef[ INT_MAX_SETUPITEMS ];
	char szStr[ MAX_PATHBUFF ];
	unsigned long ulSize;
	unsigned int uiSetupTable[SETUP_TABLE_ITEMS];

	if (lpiBuffSize != NULL)
		if (*lpiBuffSize < sizeof( scfgvaldef ))
			return IOCTL_ERROR_INVALIDARGUMENT;

	memcpy( uiSetupTable, &sdcNet3k.uiSetupTable, sizeof(sdcNet3k.uiSetupTable) );

	// Port komunikacyjny
	scfgvaldef[ INT_UPSCFG_SERIALCOMM ].eType = VT_INTLIST;
	strcpy(scfgvaldef[ INT_UPSCFG_SERIALCOMM ].szName, TXT_CFG_COMMUNICATIONPORT);
	scfgvaldef[ INT_UPSCFG_SERIALCOMM ].dDivider = 1;
	scfgvaldef[ INT_UPSCFG_SERIALCOMM ].value.iValue = (int)sdcNet3k.iSerialPort;
	scfgvaldef[ INT_UPSCFG_SERIALCOMM ].range.lMin = 0;

	for (icnt = 0; icnt < 32; icnt++) {
		sprintf(szStr, "/dev/ttyS%d", icnt);
		strcpy(scfgvaldef[ INT_UPSCFG_SERIALCOMM ].list[icnt].szName, szStr);
		scfgvaldef[ INT_UPSCFG_SERIALCOMM ].list[icnt].iValue = atoi((const char *)(szStr + 3) ) - 1;
		memset(szStr, 0, sizeof(szStr));
	}
	scfgvaldef[ INT_UPSCFG_SERIALCOMM ].range.lMax = icnt-1;
	scfgvaldef[ INT_UPSCFG_SERIALCOMM ].iListItems = icnt;

	// KONTROLA_PRACY:buzer
	scfgvaldef[ INT_UPSCFG_BUZZER ].eType = VT_INTLIST;
	strcpy(scfgvaldef[ INT_UPSCFG_BUZZER ].szName, TXT_CFG_SOUNDALERT);
	scfgvaldef[ INT_UPSCFG_BUZZER ].dDivider = 1;
	scfgvaldef[ INT_UPSCFG_BUZZER ].value.iValue = (int)uiSetupTable[SETUP_ITEM_BUZZER_EN];
	scfgvaldef[ INT_UPSCFG_BUZZER ].range.lMin = 0;
	scfgvaldef[ INT_UPSCFG_BUZZER ].range.lMax = 1;
	scfgvaldef[ INT_UPSCFG_BUZZER ].iListItems = 2;
	strcpy(scfgvaldef[ INT_UPSCFG_BUZZER ].list[0].szName, TXT_CFG_DISABLED);
	scfgvaldef[ INT_UPSCFG_BUZZER ].list[0].iValue = 0;
	strcpy(scfgvaldef[ INT_UPSCFG_BUZZER ].list[1].szName, TXT_CFG_ENABLED);
	scfgvaldef[ INT_UPSCFG_BUZZER ].list[1].iValue = 1;

	// V_DOLNY
	scfgvaldef[ INT_UPSCFG_V_TH_LOWER ].eType = VT_INTEGER;
	strcpy(scfgvaldef[ INT_UPSCFG_V_TH_LOWER ].szName, TXT_CFG_POWERSTATELOWER);
	scfgvaldef[ INT_UPSCFG_V_TH_LOWER ].dDivider = 1;
	scfgvaldef[ INT_UPSCFG_V_TH_LOWER ].value.iValue = (int)uiSetupTable[SETUP_ITEM_V_TH_LOWER];
	scfgvaldef[ INT_UPSCFG_V_TH_LOWER ].range.lMin = (long)160;
	scfgvaldef[ INT_UPSCFG_V_TH_LOWER ].range.lMax = (long)200;
	scfgvaldef[ INT_UPSCFG_V_TH_LOWER ].iListItems = 0;
	// V_GORNY
	scfgvaldef[ INT_UPSCFG_V_TH_UPPER ].eType = VT_INTEGER;
	strcpy(scfgvaldef[ INT_UPSCFG_V_TH_UPPER ].szName, TXT_CFG_POWERSTATEUPPER);
	scfgvaldef[ INT_UPSCFG_V_TH_UPPER ].dDivider = 1;
	scfgvaldef[ INT_UPSCFG_V_TH_UPPER ].value.iValue = (int)uiSetupTable[SETUP_ITEM_V_TH_UPPER];
	scfgvaldef[ INT_UPSCFG_V_TH_UPPER ].range.lMin = (long)235;
	scfgvaldef[ INT_UPSCFG_V_TH_UPPER ].range.lMax = (long)290;
	scfgvaldef[ INT_UPSCFG_V_TH_UPPER ].iListItems = 0;

	// V_AVR
	scfgvaldef[ INT_UPSCFG_V_TH_AVR ].eType = VT_INTEGER;
	strcpy(scfgvaldef[ INT_UPSCFG_V_TH_AVR ].szName, TXT_CFG_AVR);
	scfgvaldef[ INT_UPSCFG_V_TH_AVR ].dDivider = 1;
	scfgvaldef[ INT_UPSCFG_V_TH_AVR ].value.iValue = (int)uiSetupTable[SETUP_ITEM_V_TH_AVR];
	scfgvaldef[ INT_UPSCFG_V_TH_AVR ].range.lMin = (long)165;
	scfgvaldef[ INT_UPSCFG_V_TH_AVR ].range.lMax = (long)230;
	scfgvaldef[ INT_UPSCFG_V_TH_AVR ].iListItems = 0;

	// OPOZNIENIE_STANDBY
	scfgvaldef[ INT_UPSCFG_STANDBYDELAY ].eType = VT_INTEGER;
	strcpy(scfgvaldef[ INT_UPSCFG_STANDBYDELAY ].szName, TXT_CFG_STANDBYTIMEOUT);
	scfgvaldef[ INT_UPSCFG_STANDBYDELAY ].dDivider = 1;
	scfgvaldef[ INT_UPSCFG_STANDBYDELAY ].value.iValue = (int)uiSetupTable[SETUP_ITEM_STANDBY_TIME];
	scfgvaldef[ INT_UPSCFG_STANDBYDELAY ].range.lMin = 0;
	scfgvaldef[ INT_UPSCFG_STANDBYDELAY ].range.lMax = 255;
	scfgvaldef[ INT_UPSCFG_STANDBYDELAY ].iListItems = 0;

	// KEYBOARD LOCK
	scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].eType = VT_INTLIST;
	strcpy(scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].szName, TXT_CFG_KEYBOARD_LOCK);
	scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].dDivider = 1;
	scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].value.iValue = (int)uiSetupTable[SETUP_ITEM_KEYB_LOCK];
	scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].range.lMin = 0;
	scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].range.lMax = 1;
	scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].iListItems = 2;
	strcpy(scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].list[0].szName, TXT_CFG_DISABLED);
	scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].list[0].iValue = 0;
	strcpy(scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].list[1].szName, TXT_CFG_ENABLED);
	scfgvaldef[ INT_UPSCFG_KEYBOARDLOCK ].list[1].iValue = 1;
	
	// BATTERY MODULES
	scfgvaldef[ INT_UPSCFG_MODULE_NO ].eType = VT_INTEGER;
	strcpy(scfgvaldef[ INT_UPSCFG_MODULE_NO ].szName, TXT_CFG_MODULE_NO);
	scfgvaldef[ INT_UPSCFG_MODULE_NO ].dDivider = 1;
	scfgvaldef[ INT_UPSCFG_MODULE_NO ].value.iValue = (int)uiSetupTable[SETUP_ITEM_MODULE_NO];
	scfgvaldef[ INT_UPSCFG_MODULE_NO ].range.lMin = 0;
	scfgvaldef[ INT_UPSCFG_MODULE_NO ].range.lMax = 1;
	scfgvaldef[ INT_UPSCFG_V_TH_UPPER ].iListItems = 0;

	memcpy( lpvBuff, scfgvaldef, *lpiBuffSize );

	iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoSetConfigParams
// Description		: 
int	Net3k_DoSetConfigParams(void *lpvBuff, int *lpiBuffSize)
{
	int iSize, iRet;
	unsigned long ulSize;
	scfg_value scfgvaldef[INT_MAX_SETUPITEMS];
	unsigned int uiSetupTable[SETUP_TABLE_ITEMS];

	if ( *lpiBuffSize != (sizeof(scfg_value) * INT_MAX_SETUPITEMS) )
		return IOCTL_ERROR_INVALIDARGUMENT;
	else
		memcpy( &scfgvaldef, lpvBuff, *lpiBuffSize );

	/* Port komunikacyjny */
	sdcNet3k.iSerialPort = scfgvaldef[ INT_UPSCFG_SERIALCOMM ].value.iValue;
	sprintf(sdcNet3k.szSerialPort, "/dev/ttyS%d", scfgvaldef[ INT_UPSCFG_SERIALCOMM ].value.iValue);
	
	// BUZZER
	sdcNet3k.uiSetupTable[SETUP_ITEM_BUZZER_EN] = scfgvaldef[ INT_UPSCFG_BUZZER ].value.iValue;
	// IDX_V_PROG_DOLNY
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_LOWER] = (int)(scfgvaldef[INT_UPSCFG_V_TH_LOWER].value.iValue * 
		scfgvaldef[INT_UPSCFG_V_TH_LOWER].dDivider);
	// IDX_V_PROG_GORNY
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_UPPER] = (int)(scfgvaldef[INT_UPSCFG_V_TH_UPPER].value.iValue * 
		scfgvaldef[INT_UPSCFG_V_TH_UPPER].dDivider);
	// IDX_V_PROG_AVR
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_AVR] = (int)(scfgvaldef[INT_UPSCFG_V_TH_AVR].value.iValue * 
		scfgvaldef[INT_UPSCFG_V_TH_AVR].dDivider);
	// OPOZNIENIE_STANDBY
	sdcNet3k.uiSetupTable[SETUP_ITEM_STANDBY_TIME] = (int)(scfgvaldef[INT_UPSCFG_STANDBYDELAY].value.iValue *
		scfgvaldef[INT_UPSCFG_STANDBYDELAY].dDivider);
	// Blokada klawiatury
	sdcNet3k.uiSetupTable[SETUP_ITEM_KEYB_LOCK] = (int)(scfgvaldef[INT_UPSCFG_KEYBOARDLOCK].value.iValue *
		scfgvaldef[INT_UPSCFG_KEYBOARDLOCK].dDivider);
	// Ilosc modulow bateryjnych
	sdcNet3k.uiSetupTable[SETUP_ITEM_MODULE_NO] = (int)(scfgvaldef[INT_UPSCFG_MODULE_NO].value.iValue *
		scfgvaldef[INT_UPSCFG_MODULE_NO].dDivider);

	memcpy(uiSetupTable, &sdcNet3k.uiSetupTable, sizeof(sdcNet3k.uiSetupTable));

	if (commNet3k.isInitialized()) {
		iSize = SETUP_TABLE_ITEMS;
		iRet = Net3k_SetAllUpsSetupParams(uiSetupTable, &iSize);
		if (iRet != IOCTL_ERROR_SUCCESS)
			return iRet;
	}

	iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoGetConfigParam
// Description		: 
int	Net3k_DoGetConfigParam(void *lpvBuff, int *lpiBuffSize)
{
	iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoSetConfigParam
// Description		: 
int	Net3k_DoSetConfigParam(void *lpvBuff, int *lpiBuffSize)
{
	iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_ReadConfig
// Description		: 
int	Net3k_ReadConfig()
{
	char *fp;
	fp = get_config_filepath(DRIVER_CONFIG_FILE);
	if (fp==NULL) {
		return IOCTL_ERROR;
	}
	CConf *pCfgDev = new CConf;
	if (pCfgDev->init(fp)!=CONF_SUCCESS) {
		free(fp);
		delete pCfgDev;
		return IOCTL_ERROR_CONFIG_READFAIL;
	} else {
		free(fp);
		pCfgDev->parse_config();
	}
	
	char szBuf[128] = "", *s;
	// serial port
	strcpy(sdcNet3k.szSerialPort, ((s=pCfgDev->getcfgitemvalue("commport"))=="")?"/dev/ttyS0":s);
	// BUZZER
	sdcNet3k.uiSetupTable[SETUP_ITEM_BUZZER_EN]=(bool)atoi(((s=pCfgDev->getcfgitemvalue("audible_alarm"))=="")?"1":s);
	// IDX_V_PROG_DOLNY
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_LOWER]=(unsigned int)atoi(
		((s=pCfgDev->getcfgitemvalue("lower_transfer_treshold"))=="")?"185":s);
	// IDX_V_PROG_GORNY
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_UPPER]=(unsigned int)atoi(
		((s=pCfgDev->getcfgitemvalue("upper_transfer_treshold"))=="")?"270":s);
	// IDX_V_PROG_AVR
	sdcNet3k.uiSetupTable[SETUP_ITEM_V_TH_AVR]=(unsigned int)atoi(
		((s=pCfgDev->getcfgitemvalue("avr_transfer_treshold"))=="")?"200":s);
	// OPOZNIENIE_STANDBY
	sdcNet3k.uiSetupTable[SETUP_ITEM_STANDBY_TIME]=(unsigned int)strtoul(
		((s=pCfgDev->getcfgitemvalue("powerfail_to_standby_timeout"))=="")?"90":s, NULL, 10);
	// Blokada klawiatury
	sdcNet3k.uiSetupTable[SETUP_ITEM_KEYB_LOCK]=(unsigned int)atoi(
		((s=pCfgDev->getcfgitemvalue("device_keyboard_lock"))=="")?"0":s);
	// Ilosc modulow bateryjnych
	sdcNet3k.uiSetupTable[SETUP_ITEM_MODULE_NO]=(unsigned int)atoi(
		((s=pCfgDev->getcfgitemvalue("extended_module_number"))=="")?"0":s);

	delete pCfgDev;
	
	return IOCTL_ERROR_SUCCESS;
}

// Function name	: Net3k_DoUpdateConfig
// Description		: 
int	Net3k_DoUpdateConfig(void *lpvBuff, int *lpiBuffSize)
{
	iNet3k_ExtError = 0;
	
	if (Net3k_ReadConfig() != IOCTL_ERROR_SUCCESS)
		return IOCTL_ERROR_CONFIG_READFAIL;
	
	int iSize = SETUP_TABLE_ITEMS;
	return Net3k_SetAllUpsSetupParams(sdcNet3k.uiSetupTable, &iSize);
}

// Function name	: Net3k_DoGetDriverMode
// Description		: 
// Return type		: int
// Argument         : void *lpvBuff
// Argument         : int *lpiBuffSize
int	Net3k_DoGetDriverMode(void *lpvBuff, int *lpiBuffSize)
{
	iNet3k_ExtError = 0;
	return IOCTL_ERROR_CMD_NOTSUPPORTED;
}

// Function name	: Net3k_DoUpsShutdown
// Description		: 
// Return type		: int 
// Argument         : void *lpvBuff
// Argument         : int *lpiBuffSize
int Net3k_DoUpsShutdown(void *lpvBuff, int *lpiBuffSize)
{
	unsigned int uiData[2];
	int iSize, iRet;
	
	// opoznienie standby
	uiData[0] = (unsigned int)sdcNet3k.uiSetupTable[SETUP_ITEM_STANDBY_TIME];
	
	iRet = Net3k_DoSetUPSdata(EU_SET_UPSSHUTDOWN, &uiData[0], &(iSize = 1));
	if (iRet != IOCTL_ERROR_SUCCESS)
		return iRet;

	iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}

int Net3k_GetAllUpsParams(void *lpvBuff, int *lpiBuffSize)
{
	int	iSize, iRet;
	/* tablica parametrow */
	unsigned int uiParamsTable[PARAMS_TABLE_ITEMS];

	if (lpiBuffSize != NULL)
		if (*lpiBuffSize < PARAMS_TABLE_ITEMS)
			return IOCTL_ERROR_INVALIDARGUMENT;

	iSize = PARAMS_TABLE_ITEMS;
	iRet = Net3k_DoGetUPSdata(EU_MAIN, uiParamsTable, &iSize);
	if (iRet != IOCTL_ERROR_SUCCESS) {
		return iRet;
	}

	memcpy( lpvBuff, uiParamsTable, PARAMS_TABLE_ITEMS * sizeof(unsigned int) );

	iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}

int Net3k_GetAllUpsSetupParams(void *lpvBuff, int *lpiBuffSize)
{
	int	iSize, iRet;
	// tablice parametrow
	unsigned int uiSetupTable[SETUP_TABLE_ITEMS];
	unsigned int uiParamsTable[PARAMS_TABLE_ITEMS];
	unsigned int uiExtParamsTable[EXT_PARAMS_TABLE_ITEMS];
	
	if (lpiBuffSize != NULL)
		if (*lpiBuffSize < SETUP_TABLE_ITEMS)
			return IOCTL_ERROR_INVALIDARGUMENT;

	iSize = PARAMS_TABLE_ITEMS;
	iRet = Net3k_DoGetUPSdata(EU_MAIN, uiParamsTable, &iSize);
	if (iRet != IOCTL_ERROR_SUCCESS)
		return iRet;

	iSize = EXT_PARAMS_TABLE_ITEMS;
	iRet = Net3k_DoGetUPSdata(EU_EXTENDED, uiExtParamsTable, &iSize);
	if (iRet != IOCTL_ERROR_SUCCESS)
		return iRet;

	memcpy( uiSetupTable, lpvBuff, SETUP_TABLE_ITEMS * sizeof(unsigned int) );

	uiSetupTable[SETUP_ITEM_V_TH_UPPER] = uiParamsTable[PARAMS_ITEM_TH_UPPER];
	uiSetupTable[SETUP_ITEM_V_TH_AVR] = uiParamsTable[PARAMS_ITEM_TH_AVR];
	uiSetupTable[SETUP_ITEM_V_TH_LOWER] = uiParamsTable[PARAMS_ITEM_TH_LOWER];
	uiSetupTable[SETUP_ITEM_BUZZER_EN] = uiParamsTable[PARAMS_ITEM_SYSFLAG] & SFB_OR_SOUND;
	uiSetupTable[SETUP_ITEM_MODULE_NO] = uiExtParamsTable[EXT_PARAMS_ITEM_MODULENO];

	memcpy( lpvBuff, uiSetupTable, SETUP_TABLE_ITEMS * sizeof(unsigned int) );

	iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}

int Net3k_SetAllUpsSetupParams(void *lpvBuff, int *lpiBuffSize)
{
	int	iSize, iRet;
	// tablica parametrow
	unsigned int uiSetupTable[SETUP_TABLE_ITEMS];

	if (lpiBuffSize != NULL)
		if (*lpiBuffSize < SETUP_TABLE_ITEMS)
			return IOCTL_ERROR_INVALIDARGUMENT;
	memcpy( &uiSetupTable, lpvBuff, sizeof(unsigned int) * (*lpiBuffSize) );

	iSize = SETUP_TABLE_ITEMS;
	iRet = Net3k_DoSetUPSdata(EU_SET_MAIN, uiSetupTable, &iSize);
	if (iRet != IOCTL_ERROR_SUCCESS)
		return iRet;
	memcpy( lpvBuff, uiSetupTable, SETUP_TABLE_ITEMS * sizeof(unsigned int) );

	iNet3k_ExtError = 0;
	return IOCTL_ERROR_SUCCESS;
}
