/* adelsystem_cbi.h - Driver for ADELSYSTEM CB/CBI DC-UPS * * Copyright (C) * 2022 Dimitris Economou * * 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 * */ /* * code indentation with tabstop=4 */ #ifndef ADELSYSTEM_CBI_H #define ADELSYSTEM_CBI_H #include /* UPS device details */ #define DEVICE_MFR "ADELSYSTEM" #define DEVICE_TYPE "DC-UPS" #define DEVICE_MODEL "CBI2801224A" /* serial access parameters */ #define BAUD_RATE 9600 #define PARITY 'N' #define DATA_BIT 8 #define STOP_BIT 1 /* * modbus response and byte timeouts * us: 1 - 999999 */ #define MODRESP_TIMEOUT_s 0 #define MODRESP_TIMEOUT_us 200000 #define MODBYTE_TIMEOUT_s 0 #define MODBYTE_TIMEOUT_us 50000 /* modbus access parameters */ #define MODBUS_SLAVE_ID 5 /* number of modbus registers */ #define MODBUS_NUMOF_REGS 98 /* max HOLDING registers */ #define MAX_H_REGS 120 /* start HOLDING register index */ #define H_REG_STARTIDX 0 /* read all regs preprocessor flag */ #ifndef READALL_REGS #define READALL_REGS 1 #endif /* number of device models */ #define DEV_NUMOF_MODELS 10 /* shutdown repeat on error */ #define FSD_REPEAT_CNT 3 /* shutdown repeat interval in ms */ #define FSD_REPEAT_INTRV 1500 /* definition of register type */ enum regtype { COIL = 0, INPUT_B, INPUT_R, HOLDING }; typedef enum regtype regtype_t; /* product name info, "device.model" */ struct prodname { uint16_t val; char *name; }; typedef struct prodname prodname_t; static prodname_t prdnm_i[] = { {1, "CBI1235A"}, {2, "CBI2420A"}, {3, "CBI4810A"}, {4, "CBI2801224"}, {7, "CBI480W"}, {8, "CB122410A"}, {9, "CB480W"}, {11, "CB12245AJ"}, {12, "CB1235A"}, {13, "CB2420A"}, {14, "CB4810A"} }; /* charging status info, "battery.charger.status" */ static char *chrgs_i[] = { "none", "resting", /* recovering */ "charging", /* bulk */ "charging", /* absorb */ "floating" /* float */ }; struct chrgs { int state; char *info; }; typedef struct chrgs chrgs_t; /* power management info, "ups.status", "battery.charger.status" */ static char *pwrmng_i[] = { "backup", /* "OB", "discharging" */ "charging", /* "OL" */ "boost", "not charging" }; struct pwrmng { int state; char *info; }; typedef struct pwrmng pwrmng_t; /* general modbus register value */ struct reg { union val { uint16_t ui16; uint8_t ui8; } val; char *strval; }; typedef struct reg reg_t; /* general alarm struct */ struct alrm { int actv; /* active flag */ char *descr; /* description field */ }; typedef struct alrm alrm_t; /* general alarm array */ struct alrm_ar { int alrm_c; /* alarm count */ alrm_t *alrm; /* alarm array */ }; typedef struct alrm_ar alrm_ar_t; /* * BIT MASKS and VALUES */ /* Charging status */ #define CHRG_NONE 0 #define CHRG_RECV 1 #define CHRG_BULK 2 #define CHRG_ABSR 3 #define CHRG_FLOAT 4 /* power management */ #define PMNG_BCKUP 0 #define PMNG_CHRGN 1 #define PMNG_BOOST 2 #define PMNG_NCHRG 3 /* product name */ #define PRDN_MAX 14 /* Mains alarm masks */ #define MAINS_AVAIL_M 0x0001 /* 0: available (OL) 1: not available (OB) */ #define SHUTD_REQST_M 0x0002 /* shutdown requested */ /* Mains alarm indices */ #define MAINS_AVAIL_I 0 /* 0: available (OL) 1: not available (OB) */ #define SHUTD_REQST_I 1 /* shutdown requested */ /* AC input voltage alarm masks */ #define VACA_HIALRM_M 0x0001 /* high alarm */ #define VACA_LOALRM_M 0x0002 /* low alarm */ /* AC input voltage alarm indices */ #define VACA_HIALRM_I 0 /* high alarm */ #define VACA_LOALRM_I 1 /* low alarm */ /* Onboard temperature alarm value */ #define OBTA_HIALRM_V 1 /* high alarm */ /* Onboard temperature alarm index */ #define OBTA_HIALRM_I 0 /* high alarm */ /* Device failure alarm masks */ #define DEVF_RCALRM_M 0x0001 /* rectifier failure */ #define DEVF_INALRM_M 0x0006 /* internal failure */ #define DEVF_LFNAVL_M 0x0008 /* lifetest not available */ /* Device failure alarm indices */ #define DEVF_RCALRM_I 0 /* rectifier failure */ #define DEVF_INALRM_I 1 /* internal failure */ #define DEVF_LFNAVL_I 2 /* lifetest not available */ /* Battery temp sensor failure alarm masks */ #define BTSF_FCND_M 0x0001 /* connection fault */ #define BTSF_NCND_M 0x0002 /* not connected */ /* Battery temp sensor failure alarm indices */ #define BTSF_FCND_I 0 /* connection fault */ #define BTSF_NCND_I 1 /* not connected */ /* Battery voltage alarm masks */ #define BVAL_HIALRM_M 0x0001 /* high voltage */ #define BVAL_LOALRM_M 0x0002 /* low voltage */ #define BVAL_BSTSFL_M 0x0004 /* battery start with battery flat */ /* Battery voltage alarm indices */ #define BVAL_HIALRM_I 0 /* high voltage */ #define BVAL_LOALRM_I 1 /* low voltage */ #define BVAL_BSTSFL_I 2 /* battery start with battery flat */ /* SoH and SoC alarm masks */ #define SHSC_HIRESI_M 0x0001 /* high internal resistance */ #define SHSC_LOCHEF_M 0x0002 /* low charge efficiency */ #define SHSC_LOEFCP_M 0x0004 /* low effective capacity */ #define SHSC_LOWSOC_M 0x0040 /* low state of charge */ /* SoH and SoC alarm indices */ #define SHSC_HIRESI_I 0 /* high internal resistance */ #define SHSC_LOCHEF_I 1 /* low charge efficiency */ #define SHSC_LOEFCP_I 2 /* low effective capacity */ #define SHSC_LOWSOC_I 3 /* low state of charge */ /* Battery status alarm masks */ #define BSTA_REVPOL_M 0x0001 /* reversed polarity */ #define BSTA_NOCNND_M 0x0002 /* not connected */ #define BSTA_CLSHCR_M 0x0004 /* cell short circuit */ #define BSTA_SULPHD_M 0x0008 /* sulphated */ #define BSTA_CHEMNS_M 0x0010 /* chemistry not supported */ #define BSTA_CNNFLT_M 0x0020 /* connection fault */ /* Battery status alarm indices */ #define BSTA_REVPOL_I 0 /* reversed polarity */ #define BSTA_NOCNND_I 1 /* not connected */ #define BSTA_CLSHCR_I 2 /* cell short circuit */ #define BSTA_SULPHD_I 3 /* sulphated */ #define BSTA_CHEMNS_I 4 /* chemistry not supported */ #define BSTA_CNNFLT_I 5 /* connection fault */ /* Allocate alarm arrays */ static inline alrm_ar_t *alloc_alrm_ar(int as, size_t n) { alrm_ar_t *ret = xcalloc(sizeof(alrm_t) + n, 1); if (ret) { memcpy(ret, &(alrm_ar_t const) { .alrm_c = as }, sizeof(alrm_ar_t) ); } return ret; } /* Initialize alarm arrays */ static inline void alrm_ar_init(alrm_ar_t *ar_ptr, alrm_t *a_ptr, int as) { ar_ptr->alrm_c = as; ar_ptr->alrm = a_ptr; } /* input mains and shutdown alarms */ static alrm_t mains_ar[] = { {0, "input voltage not available"}, {0, "ups shutdown requested"} }; static int mains_c = 2; static alrm_ar_t *mains; /* AC input voltage alarms */ static alrm_t vaca_ar[] = { {0, "input voltage high alarm"}, {0, "input voltage low alarm"} }; static int vaca_c = 2; static alrm_ar_t *vaca; /* device failure alarms */ static alrm_t devf_ar[] = { {0, "UPS rectifier failure"}, {0, "UPS internal failure"}, {0, "UPS lifetest not available"} }; static int devf_c = 3; static alrm_ar_t *devf; /* battery sensor failure alarms */ static alrm_t btsf_ar[] = { {0, "battery temp sensor connection fault"}, {0, "battery temp sensor not connected"} }; static int btsf_c = 2; static alrm_ar_t *btsf; /* battery voltage alarms */ static alrm_t bval_ar[] = { {0, "battery high voltage"}, {0, "battery low voltage"}, {0, "battery start with battery flat"} }; static int bval_c = 3; static alrm_ar_t *bval; /* battery SoH and SoC alarms */ static alrm_t shsc_ar[] = { {0, "battery high internal resistance"}, {0, "battery low charge efficiency"}, {0, "battery low effective capacity"}, {0, "battery low state of charge"} }; static int shsc_c = 4; static alrm_ar_t *shsc; /* battery status alarm */ static alrm_t bsta_ar[] = { {0, "battery reversed polarity"}, {0, "battery not connected"}, {0, "battery cell short circuit"}, {0, "battery sulphated"}, {0, "battery chemistry not supported"}, {0, "battery connection fault"} }; static int bsta_c = 4; static alrm_ar_t *bsta; /* onboard temperature alarm */ static alrm_t obta_ar[] = { {0, "onboard temperature high"} }; static int obta_c = 4; static alrm_ar_t *obta; /* UPS device reg enum */ enum devreg { CHRG = 4, /* Charging status, "battery.charger.status" */ BATV = 7, /* Battery voltage, "battery.voltage" */ BCEF = 18, /* Battery charge efficiency factor (CEF) */ BSOH = 20, /* Battery state-of-health */ BSOC = 22, /* Battery state-of-charge, "battery.charge" */ BTMP = 25, /* Battery temperature in Kelvin units, "battery.temperature" */ PMNG = 5, /* Power management, "ups.status" */ OTMP = 28, /* Onboard temperature, "ups.temperature" */ PRDN = 67, /* Product name, "ups.model" */ VAC = 29, /* AC voltage, "input.voltage" */ LVDC = 10, /* Load voltage, "output.voltage" */ LCUR = 19, /* Load current, "output.current" */ BINH = 87, /* Backup inhibit */ FSD = 40, /* Force shutdown */ TBUF = 103, /* Time buffering, "battery.runtime" */ BSTA = 31, /* Battery status alarms */ SCSH, /* SoH and SoC alarms */ BVAL = 34, /* Battery voltage alarm */ BTSF = 43, /* Battery temp sensor failure */ DEVF = 42, /* Device failure */ OBTA = 46, /* On board temp alarm */ VACA = 44, /* VAC alarms */ MAIN /* Mains status */ }; typedef enum devreg devreg_t; /* UPS register attributes */ struct regattr { int num; int saddr; /* register start address */ int xaddr; /* register hex address */ float scale; /* scale */ regtype_t type; /* register type */ }; typedef struct regattr regattr_t; /* UPS device state info union */ union devstate { prodname_t product; /* ups model name */ chrgs_t charge; /* charging status */ pwrmng_t power; /* ups status */ reg_t reg; /* state register*/ alrm_ar_t *alrm; /* alarm statuses */ }; typedef union devstate devstate_t; /* device register memory image */ static uint16_t regs_data[MAX_H_REGS]; /* ADELSYSTEM CBI registers */ static regattr_t regs[] = { {40001, 0, 0, 1, HOLDING}, /* Address of slave unit */ {40002, 0, 0, 1, HOLDING}, /* Baud rate for serial communication */ {40003, 0, 0, 1, HOLDING}, /* Parity bit for serial communication */ {40004, 0, 0, 1, HOLDING}, {40005, 0, 0, 1, HOLDING}, /* Charging status */ {40006, 0, 0, 1, HOLDING}, /* Power management * 0:Backup 1:Charging 2:boost 3:Not charging */ {40007, 0, 0, 1, HOLDING}, /* Nominal output voltage */ {40008, 0, 0, 1, HOLDING}, /* Battery voltage */ {40009, 0, 0, 1, HOLDING}, /* Parameter map version ID */ {40010, 0, 0, 1, HOLDING}, /* Software ID */ {40011, 0, 0, 1, HOLDING}, /* Output load voltage */ {40012, 0, 0, 1, HOLDING}, {40013, 0, 0, 1, HOLDING}, {40014, 0, 0, 1, HOLDING}, /* Battery charge current */ {40015, 0, 0, 1, HOLDING}, {40016, 0, 0, .1, HOLDING}, /* Battery capacity consumed */ {40017, 0, 0, 1, HOLDING}, /* Battery discharge current */ {40018, 0, 0, .1, HOLDING}, /* Effective battery capacity */ {40019, 0, 0, 1, HOLDING}, /* Battery charge efficiency factor (CEF) */ {40020, 0, 0, 1, HOLDING}, /* Output load current */ {40021, 0, 0, 1, HOLDING}, /* Battery state-of-health */ {40022, 0, 0, 1, HOLDING}, /* Time remaining to 100% discharge */ {40023, 0, 0, .1, HOLDING}, /* Battery state-of-charge */ {40024, 0, 0, 1, HOLDING}, /* Battery type currently selected */ {40025, 0, 0, 1, HOLDING}, {40026, 0, 0, 1, HOLDING}, /* Battery temperature in Kelvin units */ {40027, 0, 0, 1, HOLDING}, /* Configuration mode */ {40028, 0, 0, .1, HOLDING}, /* Battery net internal resistance */ {40029, 0, 0, 1, HOLDING}, /* On-board temperature */ {40030, 0, 0, 1, HOLDING}, /* AC input voltage */ {40031, 0, 0, 1, HOLDING}, {40032, 0, 0, 1, HOLDING}, /* Battery status alarm */ {40033, 0, 0, 1, HOLDING}, /* Battery State of Charge and State of Health */ {40034, 0, 0, 1, HOLDING}, /* Load output off duration after PC shutdown */ {40035, 0, 0, 1, HOLDING}, /* Battery voltage alarm */ {40036, 0, 0, 1, HOLDING}, /* Low AC input voltage alarm threshold */ {40037, 0, 0, 1, HOLDING}, /* High AC input voltage alarm threshold */ {40038, 0, 0, 1, HOLDING}, /* Load alarm */ {40039, 0, 0, 1, HOLDING}, /* Device variant */ {40040, 0, 0, 1, HOLDING}, {40041, 0, 0, 1, HOLDING}, /* Force shutdown */ {40042, 0, 0, 1, HOLDING}, {40043, 0, 0, 1, HOLDING}, /* Device failure */ {40044, 0, 0, 1, HOLDING}, /* Battery temperature sensor failure */ {40045, 0, 0, 1, HOLDING}, /* AC input voltage alarm */ {40046, 0, 0, 1, HOLDING}, /* Mains status */ {40047, 0, 0, 1, HOLDING}, /* On board temperature alarm */ {40048, 0, 0, 1, HOLDING}, /* Number of charge cycles completed */ {40049, 0, 0, 1, HOLDING}, /* Charge cycles not completed */ {40050, 0, 0, .1, HOLDING}, /* Ah charged */ {40051, 0, 0, 1, HOLDING}, /* Total run time */ {40052, 0, 0, 1, HOLDING}, /* Number of low battery voltage events */ {40053, 0, 0, 1, HOLDING}, /* Number of high battery voltage events */ {40054, 0, 0, 1, HOLDING}, /* Number of low VAC events at mains input */ {40055, 0, 0, 1, HOLDING}, /* Number of High VAC events at mains input */ {40056, 0, 0, 1, HOLDING}, /* Number of over temperature inside events */ {40057, 0, 0, 1, HOLDING}, /* Number of mains-backup transitions */ {40058, 0, 0, 1, HOLDING}, /* Number power boost events */ {40059, 0, 0, 1, HOLDING}, /* Highest battery voltage */ {40060, 0, 0, 1, HOLDING}, /* Highest output load voltage */ {40061, 0, 0, .1, HOLDING}, /* Maximum depth of discharge */ {40062, 0, 0, 1, HOLDING}, /* Lowest battery voltage */ {40063, 0, 0, 1, HOLDING}, /* Lowest output load voltage */ {40064, 0, 0, .1, HOLDING}, /* Average depth of discharge */ {40065, 0, 0, 1, HOLDING}, /* History clear all */ {40066, 0, 0, 1, HOLDING}, /* Factory settings */ {40067, 0, 0, 1, HOLDING}, /* Product name */ {40068, 0, 0, 1, HOLDING}, {40069, 0, 0, 1, HOLDING}, /* Reset internal battery model */ {40070, 0, 0, 1, HOLDING}, {40071, 0, 0, 1, HOLDING}, /* Deep discharge battery prevention */ {40072, 0, 0, 1, HOLDING}, /* Maximum charge current */ {40073, 0, 0, 1, HOLDING}, /* Bulk voltage */ {40074, 0, 0, 1, HOLDING}, /* Max bulk timer */ {40075, 0, 0, 1, HOLDING}, /* Min bulk timer */ {40076, 0, 0, 1, HOLDING}, {40077, 0, 0, 1, HOLDING}, /* Absorption voltage */ {40078, 0, 0, 1, HOLDING}, /* Max absorption timer */ {40079, 0, 0, 1, HOLDING}, /* Min absorption timer */ {40080, 0, 0, 1, HOLDING}, /* Return Amperes to float */ {40081, 0, 0, 1, HOLDING}, /* Return amps timer */ {40082, 0, 0, 1, HOLDING}, /* Float voltage */ {40083, 0, 0, 1, HOLDING}, /* Force boost charge */ {40084, 0, 0, 1, HOLDING}, /* Return to bulk voltage from float */ {40085, 0, 0, 1, HOLDING}, /* Return to bulk delay */ {40086, 0, 0, 1, HOLDING}, {40087, 0, 0, 1, HOLDING}, /* Switchoff voltage without mains */ {40088, 0, 0, 1, HOLDING}, /* Backup Inhibit 0 = Backup allowed * 1 = Backup not allowed */ {40089, 0, 0, 1, HOLDING}, /* Number of battery cells */ {40090, 0, 0, 1, HOLDING}, /* Temperature compensation coefficient */ {40091, 0, 0, 1, HOLDING}, {40092, 0, 0, 1, HOLDING}, /* Lifetest enable */ {40093, 0, 0, 1, HOLDING}, /* Max alarm temp */ {40094, 0, 0, 1, HOLDING}, /* Min alarm temp */ {40095, 0, 0, 1, HOLDING}, {40096, 0, 0, 1, HOLDING}, {40097, 0, 0, 1, HOLDING}, /* Low battery threshold */ {40098, 0, 0, 1, HOLDING}, /* SoC/SoH test period */ {40099, 0, 0, 1, HOLDING}, /* Manual SoC/SoH test request */ {40100, 0, 0, 1, HOLDING}, /* SoC/SoH test possible */ {40101, 0, 0, .1, HOLDING}, /* Nominal battery internal resistance */ {40102, 0, 0, .1, HOLDING}, /* Nominal battery cables resistance */ {40103, 0, 0, 1, HOLDING}, /* Firmware ID */ {40104, 0, 0, 1, HOLDING}, /* Time buffering */ {40105, 0, 0, .1, HOLDING}, /* Battery capacity C20 */ {40106, 0, 0, .1, HOLDING}, /* Battery Capacity C10 */ {40107, 0, 0, 1, HOLDING}, /* Device switchoff delay */ {40108, 0, 0, .1, HOLDING}, /* Battery Capacity C5 */ {40109, 0, 0, .1, HOLDING}, /* Battery Capacity C2 */ {40110, 0, 0, 1, HOLDING}, {40111, 0, 0, 1, HOLDING}, /* PC power supply removal delay */ {40112, 0, 0, .1, HOLDING}, /* Battery Capacity C1 */ {40113, 0, 0, .1, HOLDING}, /* Low state-of-charge */ {40114, 0, 0, 1, HOLDING}, {40115, 0, 0, 1, HOLDING}, {40116, 0, 0, 1, HOLDING}, {40117, 0, 0, 1, HOLDING}, {40118, 0, 0, 1, HOLDING}, {40119, 0, 0, 1, HOLDING}, {40120, 0, 0, 1, HOLDING} /* Zero-SoC reference */ }; #endif /* ADELSYSTEM_CBI_H */