├── .gitignore ├── CODESYS ├── MEGA_BAS.package ├── MegaBAS.project └── README.md ├── LICENSE ├── MODBUS.md ├── Makefile ├── README.md ├── node-red-contrib-sm-bas ├── README.md ├── bas.html ├── bas.js ├── icons │ ├── adc.png │ ├── dac.png │ ├── switch.png │ ├── thermistor.png │ ├── triac.jpg │ └── triac.png └── package.json ├── python ├── LICENSE ├── Makefile ├── README.md ├── megabas │ └── __init__.py ├── res │ └── sequent.jpg ├── setup.cfg ├── setup.py └── tests │ └── uoutin.py ├── res ├── megabas.jpg └── sequent.jpg ├── src ├── comm.c ├── comm.h ├── megabas.c ├── megabas.h ├── thread.c └── thread.h └── update ├── README.md ├── fwrevhist.md ├── update └── update64 /.gitignore: -------------------------------------------------------------------------------- 1 | #c cli build 2 | *.o 3 | megabas 4 | 5 | #python build dirs 6 | /python/build/ 7 | /python/dist/ 8 | /python/*.egg-info/ 9 | -------------------------------------------------------------------------------- /CODESYS/MEGA_BAS.package: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/CODESYS/MEGA_BAS.package -------------------------------------------------------------------------------- /CODESYS/MegaBAS.project: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/CODESYS/MegaBAS.project -------------------------------------------------------------------------------- /CODESYS/README.md: -------------------------------------------------------------------------------- 1 | # CODESYS Driver 2 | 3 | This is the Codesys driver for the [Building Automation Card](https://sequentmicrosystems.com/products/raspberry-pi-building-automation) 4 | 5 | We include the source code library in the package so everyone can modify. Note that it is an open source library with absolutely no warranty. 6 | Checkout our example project for guidance. 7 | 8 | For using multiple card in the same time you need to set the card stack lever from jumpers and modify the "I2C address" parameter of the device, below you find the correspondence between stack level and hardware address: 9 | 10 | | Stack Level | I2C address | 11 | | --- | --- | 12 | | 0 | 16#48 | 13 | | 1 | 16#49 | 14 | | 2 | 16#4A | 15 | | 3 | 16#4B | 16 | | 4 | 16#4C | 17 | | 5 | 16#4D | 18 | | 6 | 16#4E | 19 | | 7 | 16#4F | 20 | 21 | # Important Notice 22 | We are thankful to [nikke344](https://github.com/nikke344) who helped to develop the library. 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sequent Microsystems 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MODBUS.md: -------------------------------------------------------------------------------- 1 | [![megabas-rpi](res/sequent.jpg)](https://sequentmicrosystems.com) 2 | 3 | # Modbus 4 | 5 | The [Building](https://sequentmicrosystems.com/product/raspberry-pi-building-automation/) Automation I/O Expansion cards for Raspberry Pi can be accessed thru Modbus RTU protocol over RS-485 port. 6 | You can set-up the RS-485 port with **megabas** command. 7 | 8 | Example: 9 | ```bash 10 | ~$ megabas 0 rs485wr 1 9600 1 0 1 11 | ``` 12 | Set Modbus RTU , Baudrate: 9600bps, 1 Stop Bit, parity: None, slave address offset: 1 13 | ```bash 14 | ~$ megabas -h rs485wr 15 | ``` 16 | display the full set of options 17 | 18 | ## Slave Address 19 | The slave address is add with the "stack level" jumpers. For example the jumpers configuration for stack level 1 (one jumper in position ID0) slave address offset to 1 corespond to slave address 2. 20 | 21 | ## Modbus object types 22 | All modbus RTU object type with standard addresses are implemented : Coils, Discrete Inputs, Input registers, Holding registers. 23 | 24 | ### Coils 25 | 26 | Acces level Read/Write, Size 1 bit 27 | 28 | | Device function | Register Address | Modbus Address | 29 | | --- | --- | --- | 30 | | TRIAC_1 | 0001 | 0x00 | 31 | | TRIAC_2 | 0002 | 0x01 | 32 | | TRIAC_3 | 0003 | 0x02 | 33 | | TRIAC_4 | 0004 | 0x03 | 34 | | DRY_CONTACT_RISING_COUNT_ENABLE_CH1 | 0005 | 0x04 | 35 | | DRY_CONTACT_RISING_COUNT_ENABLE_CH2 | 0006 | 0x05 | 36 | | DRY_CONTACT_RISING_COUNT_ENABLE_CH3 | 0007 | 0x06 | 37 | | DRY_CONTACT_RISING_COUNT_ENABLE_CH4 | 0008 | 0x07 | 38 | | DRY_CONTACT_RISING_COUNT_ENABLE_CH5 | 0009 | 0x08 | 39 | | DRY_CONTACT_RISING_COUNT_ENABLE_CH6 | 0010 | 0x09 | 40 | | DRY_CONTACT_RISING_COUNT_ENABLE_CH7 | 0011 | 0x0a | 41 | | DRY_CONTACT_RISING_COUNT_ENABLE_CH8 | 0012 | 0x0b | 42 | | DRY_CONTACT_FALLING_COUNT_ENABLE_CH1 | 0013 | 0x0c | 43 | | DRY_CONTACT_FALLING_COUNT_ENABLE_CH2 | 0014 | 0x0d | 44 | | DRY_CONTACT_FALLING_COUNT_ENABLE_CH3 | 0015 | 0x0e | 45 | | DRY_CONTACT_FALLING_COUNT_ENABLE_CH4 | 0016 | 0x0f | 46 | | DRY_CONTACT_FALLING_COUNT_ENABLE_CH5 | 0017 | 0x10 | 47 | | DRY_CONTACT_FALLING_COUNT_ENABLE_CH6 | 0018 | 0x11 | 48 | | DRY_CONTACT_FALLING_COUNT_ENABLE_CH7 | 0019 | 0x12 | 49 | | DRY_CONTACT_FALLING_COUNT_ENABLE_CH8 | 0020 | 0x13 | 50 | 51 | ### Discrete Inputs 52 | 53 | Access level Read Only, Size 1 bit 54 | 55 | | Device function | Register Address | Modbus Address | 56 | | --- | --- | --- | 57 | | DRY_CONTACT_1 | 10001 | 0x00 | 58 | | DRY_CONTACT_2 | 10002 | 0x01 | 59 | | DRY_CONTACT_3 | 10003 | 0x02 | 60 | | DRY_CONTACT_4 | 10004 | 0x03 | 61 | | DRY_CONTACT_5 | 10005 | 0x04 | 62 | | DRY_CONTACT_6 | 10006 | 0x05 | 63 | | DRY_CONTACT_7 | 10007 | 0x06 | 64 | | DRY_CONTACT_8 | 10008 | 0x07 | 65 | 66 | ### Input registers 67 | 68 | Access level Read Only, Size 16 bits 69 | 70 | | Device function | Register Address | Description | Measurement Unit | 71 | | --- | --- | --- | --- | 72 | | 0-10V_IN_1 | 30001 | 0 - 10V input channel 1 | mV | 73 | | 0-10V_IN_2 | 30002 | 0 - 10V input channel 2 | mV | 74 | | 0-10V_IN_3 | 30003 | 0 - 10V input channel 3 | mV | 75 | | 0-10V_IN_4 | 30004 | 0 - 10V input channel 4 | mV | 76 | | 0-10V_IN_5 | 30005 | 0 - 10V input channel 5 | mV | 77 | | 0-10V_IN_6 | 30006 | 0 - 10V input channel 6 | mV | 78 | | 0-10V_IN_7 | 30007 | 0 - 10V input channel 7 | mV | 79 | | 0-10V_IN_8 | 30008 | 0 - 10V input channel 8 | mV | 80 | | 1K_R_IN_1 | 30009 | 1K thernistor resistance channel 1 | ohm | 81 | | 1K_R_IN_2 | 30010 | 1K thernistor resistance channel 2 | ohm | 82 | | 1K_R_IN_3 | 30011 | 1K thernistor resistance channel 3 | ohm | 83 | | 1K_R_IN_4 | 30012 | 1K thernistor resistance channel 4 | ohm | 84 | | 1K_R_IN_5 | 30013 | 1K thernistor resistance channel 5 | ohm | 85 | | 1K_R_IN_6 | 30014 | 1K thernistor resistance channel 6 | ohm | 86 | | 1K_R_IN_7 | 30015 | 1K thernistor resistance channel 7 | ohm | 87 | | 1K_R_IN_8 | 30016 | 1K thernistor resistance channel 8 | ohm | 88 | | 10K_R_IN_1 | 30017 | 10K thernistor resistance channel 1 | ohm | 89 | | 10K_R_IN_2 | 30018 | 10K thernistor resistance channel 2 | ohm | 90 | | 10K_R_IN_3 | 30019 | 10K thernistor resistance channel 3 | ohm | 91 | | 10K_R_IN_4 | 30020 | 10K thernistor resistance channel 4 | ohm | 92 | | 10K_R_IN_5 | 30021 | 10K thernistor resistance channel 5 | ohm | 93 | | 10K_R_IN_6 | 30022 | 10K thernistor resistance channel 6 | ohm | 94 | | 10K_R_IN_7 | 30023 | 10K thernistor resistance channel 7 | ohm | 95 | | 10K_R_IN_8 | 30024 | 10K thernistor resistance channel 8 | ohm | 96 | | DRY_CONTACT_EDGE_COUNTER_CH1 | 30025 | Edge counter ch1 | - | 97 | | DRY_CONTACT_EDGE_COUNTER_CH2 | 30026 | Edge counter ch2 | - | 98 | | DRY_CONTACT_EDGE_COUNTER_CH3 | 30027 | Edge counter ch3 | - | 99 | | DRY_CONTACT_EDGE_COUNTER_CH4 | 30028 | Edge counter ch4 | - | 100 | | DRY_CONTACT_EDGE_COUNTER_CH5 | 30029 | Edge counter ch5 | - | 101 | | DRY_CONTACT_EDGE_COUNTER_CH6 | 30030 | Edge counter ch6 | - | 102 | | DRY_CONTACT_EDGE_COUNTER_CH7 | 30031 | Edge counter ch7 | - | 103 | | DRY_CONTACT_EDGE_COUNTER_CH8 | 30032 | Edge counter ch8 | - | 104 | | OWB_TEMP1| 30033 | Temperature 1 | 0.01C| 105 | | OWB_TEMP2| 30034 | Temperature 2 | 0.01C| 106 | | OWB_TEMP3| 30035 | Temperature 3 | 0.01C| 107 | | OWB_TEMP4| 30036 | Temperature 4 | 0.01C| 108 | | OWB_TEMP5| 30037 | Temperature 5 | 0.01C| 109 | | OWB_TEMP6| 30038 | Temperature 6 | 0.01C| 110 | | OWB_TEMP7| 30039 | Temperature 7 | 0.01C| 111 | | OWB_TEMP8| 30040 | Temperature 8 | 0.01C| 112 | | OWB_TEMP9| 30041 | Temperature 9 | 0.01C| 113 | | OWB_TEMP10| 30042 | Temperature 10 | 0.01C| 114 | | OWB_TEMP11| 30043 | Temperature 11 | 0.01C| 115 | | OWB_TEMP12| 30044 | Temperature 12 | 0.01C| 116 | | OWB_TEMP13| 30045 | Temperature 13 | 0.01C| 117 | | OWB_TEMP14| 30046 | Temperature 14 | 0.01C| 118 | | OWB_TEMP15| 30047 | Temperature 15 | 0.01C| 119 | | OWB_TEMP16| 30048 | Temperature 16 | 0.01C| 120 | | OWB_ID_A_TEMP1| 30049 | ID A Temperature 1 | 64 bit ID | 121 | | OWB_ID_B_TEMP1| 30050 | ID B Temperature 1 | | 122 | | OWB_ID_C_TEMP1| 30051 | ID C Temperature 1 | | 123 | | OWB_ID_D_TEMP1| 30052 | ID D Temperature 1 | | 124 | | OWB_ID_A_TEMP2| 30053 | ID A Temperature 2 | 64 bit ID | 125 | | OWB_ID_B_TEMP2| 30054 | ID B Temperature 2 | | 126 | | OWB_ID_C_TEMP2| 30055 | ID C Temperature 2 | | 127 | | OWB_ID_D_TEMP2| 30056 | ID D Temperature 2 | | 128 | | OWB_ID_A_TEMP3| 30057 | ID A Temperature 3 | 64 bit ID| 129 | | OWB_ID_B_TEMP3| 30058 | ID B Temperature 3 | | 130 | | OWB_ID_C_TEMP3| 30059 | ID C Temperature 3 | | 131 | | OWB_ID_D_TEMP3| 30060 | ID D Temperature 3 | | 132 | | OWB_ID_A_TEMP4| 30061 | ID A Temperature 4 | 64 bit ID| 133 | | OWB_ID_B_TEMP4| 30062 | ID B Temperature 4 | | 134 | | OWB_ID_C_TEMP4| 30063 | ID C Temperature 4 | | 135 | | OWB_ID_D_TEMP4| 30064 | ID D Temperature 4 | | 136 | | OWB_ID_A_TEMP5| 30065 | ID A Temperature 5 | 64 bit ID| 137 | | OWB_ID_B_TEMP5| 30066 | ID B Temperature 5 | | 138 | | OWB_ID_C_TEMP5| 30067 | ID C Temperature 5 | | 139 | | OWB_ID_D_TEMP5| 30068 | ID D Temperature 5 | | 140 | | OWB_ID_A_TEMP6| 30069 | ID A Temperature 6 | 64 bit ID| 141 | | OWB_ID_B_TEMP6| 30070 | ID B Temperature 6 | | 142 | | OWB_ID_C_TEMP6| 30071 | ID C Temperature 6 | | 143 | | OWB_ID_D_TEMP6| 30072 | ID D Temperature 6 | | 144 | | OWB_ID_A_TEMP7| 30073 | ID A Temperature 7 | 64 bit ID| 145 | | OWB_ID_B_TEMP7| 30074 | ID B Temperature 7 | | 146 | | OWB_ID_C_TEMP7| 30075 | ID C Temperature 7 | | 147 | | OWB_ID_D_TEMP7| 30076 | ID D Temperature 7 | | 148 | | OWB_ID_A_TEMP8| 30077 | ID A Temperature 8 | 64 bit ID| 149 | | OWB_ID_B_TEMP8| 30078 | ID B Temperature 8 | | 150 | | OWB_ID_C_TEMP8| 30079 | ID C Temperature 8 | | 151 | | OWB_ID_D_TEMP8| 30080 | ID D Temperature 8 | | 152 | | OWB_ID_A_TEMP9| 30081 | ID A Temperature 9 | 64 bit ID| 153 | | OWB_ID_B_TEMP9| 30082 | ID B Temperature 9 | | 154 | | OWB_ID_C_TEMP9| 30083 | ID C Temperature 9 | | 155 | | OWB_ID_D_TEMP9| 30084 | ID D Temperature 9 | | 156 | | OWB_ID_A_TEMP10| 30085 | ID A Temperature 10 | 64 bit ID| 157 | | OWB_ID_B_TEMP10| 30086 | ID B Temperature 10 | | 158 | | OWB_ID_C_TEMP10| 30087 | ID C Temperature 10 | | 159 | | OWB_ID_D_TEMP10| 30088 | ID D Temperature 10 | | 160 | | OWB_ID_A_TEMP11| 30089 | ID A Temperature 11 | 64 bit ID| 161 | | OWB_ID_B_TEMP11| 30090 | ID B Temperature 11 | | 162 | | OWB_ID_C_TEMP11| 30091 | ID C Temperature 11 | | 163 | | OWB_ID_D_TEMP11| 30092 | ID D Temperature 11 | | 164 | | OWB_ID_A_TEMP12| 30093 | ID A Temperature 12 | 64 bit ID| 165 | | OWB_ID_B_TEMP12| 30094 | ID B Temperature 12 | | 166 | | OWB_ID_C_TEMP12| 30095 | ID C Temperature 12 | | 167 | | OWB_ID_D_TEMP12| 30096 | ID D Temperature 12 | | 168 | | OWB_ID_A_TEMP13| 30097 | ID A Temperature 13 | 64 bit ID| 169 | | OWB_ID_B_TEMP13| 30098 | ID B Temperature 13 | | 170 | | OWB_ID_C_TEMP13| 30099 | ID C Temperature 13 | | 171 | | OWB_ID_D_TEMP13| 30100 | ID D Temperature 13 | | 172 | | OWB_ID_A_TEMP14| 30101 | ID A Temperature 14 | 64 bit ID| 173 | | OWB_ID_B_TEMP14| 30102 | ID B Temperature 14 | | 174 | | OWB_ID_C_TEMP14| 30103 | ID C Temperature 14 | | 175 | | OWB_ID_D_TEMP14| 30104 | ID D Temperature 14 | | 176 | | OWB_ID_A_TEMP15| 30105 | ID A Temperature 15 | 64 bit ID| 177 | | OWB_ID_B_TEMP15| 30106 | ID B Temperature 15 | | 178 | | OWB_ID_C_TEMP15| 30107 | ID C Temperature 15 | | 179 | | OWB_ID_D_TEMP15| 30108 | ID D Temperature 15 | | 180 | | OWB_ID_A_TEMP16| 30109 | ID A Temperature 16 | 64 bit ID| 181 | | OWB_ID_B_TEMP16| 30110 | ID B Temperature 16 | | 182 | | OWB_ID_C_TEMP16| 30111 | ID C Temperature 16 | | 183 | | OWB_ID_D_TEMP16| 30112 | ID D Temperature 16 | | 184 | 185 | ### Holding registers 186 | 187 | Access level Read/Write, Size 16 bits 188 | 189 | | Device function | Register Address | Modbus Address | Measurement Unit | 190 | | --- | --- | --- | --- | 191 | | 0-10V_OUT_1 | 40001 | 0x00 | mV | 192 | | 0-10V_OUT_2 | 40002 | 0x01 | mV | 193 | | 0-10V_OUT_3 | 40003 | 0x02 | mV | 194 | | 0-10V_OUT_4 | 40004 | 0x03 | mV | 195 | 196 | 197 | 198 | ## Function codes implemented 199 | 200 | * Read Coils (0x01) 201 | * Read Discrete Inputs (0x02) 202 | * Read Holding Registers (0x03) 203 | * Read Input Registers (0x04) 204 | * Write Single Coil (0x05) 205 | * Write Single Register (0x06) 206 | * Write Multiple Coils (0x0f) 207 | * Write Multiple registers (0x10) 208 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DESTDIR?=/usr 2 | PREFIX?=/local 3 | 4 | ifneq ($V,1) 5 | Q ?= @ 6 | endif 7 | 8 | CC = gcc 9 | CFLAGS = $(DEBUG) -Wall -Wextra $(INCLUDE) -Winline -pipe 10 | 11 | LDFLAGS = -L$(DESTDIR)$(PREFIX)/lib 12 | LIBS = -lpthread -lrt -lm -lcrypt 13 | 14 | SRC = src/megabas.c src/comm.c src/thread.c 15 | 16 | OBJ = $(SRC:.c=.o) 17 | 18 | all: megabas 19 | 20 | megabas: $(OBJ) 21 | $Q echo [Link] 22 | $Q $(CC) -o $@ $(OBJ) $(LDFLAGS) $(LIBS) 23 | 24 | .c.o: 25 | $Q echo [Compile] $< 26 | $Q $(CC) -c $(CFLAGS) $< -o $@ 27 | 28 | .PHONY: clean 29 | clean: 30 | $Q echo "[Clean]" 31 | $Q rm -f $(OBJ) megabas *~ core tags *.bak 32 | 33 | .PHONY: install 34 | install: megabas 35 | $Q echo "[Install]" 36 | $Q cp megabas $(DESTDIR)$(PREFIX)/bin 37 | ifneq ($(WIRINGPI_SUID),0) 38 | $Q chown root:root $(DESTDIR)$(PREFIX)/bin/megabas 39 | $Q chmod 4755 $(DESTDIR)$(PREFIX)/bin/megabas 40 | endif 41 | # $Q mkdir -p $(DESTDIR)$(PREFIX)/man/man1 42 | # $Q cp megaio.1 $(DESTDIR)$(PREFIX)/man/man1 43 | 44 | .PHONY: uninstall 45 | uninstall: 46 | $Q echo "[UnInstall]" 47 | $Q rm -f $(DESTDIR)$(PREFIX)/bin/megabas 48 | $Q rm -f $(DESTDIR)$(PREFIX)/man/man1/megabas.1 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![megabas-rpi](res/sequent.jpg)](https://www.sequentmicrosystems.com) 2 | 3 | # megabas-rpi 4 | 5 | This is the command to control [Building Automation Stackable Card for Raspberry Pi](https://sequentmicrosystems.com/products/building-automation-8-layer-stackable-hat-v4-for-raspberry-pi) 6 | 7 | ![MEGA-BAS](res/megabas.jpg) 8 | 9 | ## Setup 10 | 11 | Don't forget to enable I2C communication: 12 | ```bash 13 | ~$ sudo raspi-config 14 | ``` 15 | 16 | ## Usage 17 | 18 | ```bash 19 | ~$ git clone https://github.com/SequentMicrosystems/megabas-rpi.git 20 | ~$ cd megabas-rpi/ 21 | ~/megabas-rpi$ sudo make install 22 | ``` 23 | 24 | Now you can access all the functions of the BAS board through the command "megabas". Use -h option for help: 25 | ```bash 26 | ~$ megabas -h 27 | ``` 28 | ## Update 29 | If you clone the repository, any update can be made with the following commands: 30 | 31 | ```bash 32 | ~$ cd megabas-rpi/ 33 | ~/megabas-rpi$ git pull 34 | ~/megabas-rpi$ sudo make install 35 | ``` 36 | ## Software selectable input type 37 | 38 | For cards version 5.0 and up, input types are not dipswitch selectable, as for the previous versions, but software selectable. 39 | The default setting of the Inputs type is 0-10V, to change it: 40 | 41 | 1) Make sure you have the latest ```megabas``` command installed, as explained above. 42 | 2) Run the command ```megabas incfgwr ```, where 43 | * stack = 0 - 7, Stack level selectable from ID0, ID1, ID2 dipswitches 44 | * channel = 1 - 8, Channel number you need to modify 45 | * value = 0 for 0-10V, 1 for 1K Thermistor or Dry contact, 2 for 10K Thermistor 46 | 47 | For more info on the commands' parameters run ```megabas -h incfgwr``` and ```megabas -h incfgrd```. 48 | The input type settings are saved into the card's nonvolatile memory, so will be preserved after power-down. 49 | 50 | ## Additional Drivers / Resources 51 | 52 | [Python Library](python/README.md) 53 | 54 | [Firmware update instructions](update/README.md). 55 | 56 | [Node-RED](https://github.com/SequentMicrosystems/megabas-rpi/tree/master/node-red-contrib-sm-bas) 57 | 58 | [CODESYS Driver](https://github.com/SequentMicrosystems/megabas-rpi/tree/master/CODESYS) 59 | 60 | [Home Assistant Integration](https://github.com/SequentMicrosystems/SMmegabas-ha) 61 | 62 | [Open PLC](https://openplcproject.com/) 63 | 64 | [Arduino Library](https://github.com/SequentMicrosystems/Sequent-Building-Automation-Library) 65 | 66 | The board can act as Modbus RTU slave device, checkout [modbus instructions](MODBUS.md) 67 | -------------------------------------------------------------------------------- /node-red-contrib-sm-bas/README.md: -------------------------------------------------------------------------------- 1 | # node-red-contrib-sm-bas 2 | 3 | This is the node-red node to control Sequent Microsystems [Building Automation Stackable Card for Raspberry Pi](https://sequentmicrosystems.com/products/raspberry-pi-building-automation). 4 | 5 | ## Manual Install 6 | 7 | Clone or update the repository, follow the instrutions fron the [first page.](https://github.com/SequentMicrosystems/megabas-rpi) 8 | 9 | In your node-red user directory, tipicaly ~/.node-red, 10 | 11 | ```bash 12 | ~$ cd ~/.node-red 13 | ``` 14 | 15 | Run the fallowing command: 16 | 17 | ```bash 18 | ~/.node-red$ npm install ~/megabas-rpi/node-red-contrib-sm-bas 19 | ``` 20 | 21 | In order to see the node in the palette and use-it you need to restart node-red. If you run node-red as a service: 22 | ```bash 23 | ~$ node-red-stop 24 | ~$ node-red-start 25 | ``` 26 | 27 | ## Usage 28 | 29 | After install and restart the node-red you will see on the node palete, under Sequent Microsystems category 7 new nodes: 30 | 31 | ### BAS triac 32 | 33 | This node will turn on or off a triac. 34 | The card stack level and triac number can be set in the dialog screen or dynamicaly through ``` msg.stack``` and ``` msg.triac ```. 35 | The output of the triac can be set dynamically as a boolean using ```msg.payload```. 36 | 37 | ### BAS 0 10V in 38 | 39 | This node reads one 0-10V input channel (Make sure the corresponding jumper is in the "0-10V" position in order for this read to be correct). 40 | The card stack level and channel number can be set in the node dialog box or dynamically through ```msg.stack``` and ```msg.channel```. 41 | The read is triggered by the message input and output can be found in the output message payload as a number representing the voltage readings in volts. 42 | 43 | ### BAS 0 10V out 44 | 45 | This node controls one 0-10V output channel. 46 | The card stack level and channel number can be set in the node dialog box or dynamically through ```msg.stack``` and ```msg.channel```. 47 | The value in volts is set dynamically as a number between 0..10 thru ```msg.payload```. 48 | 49 | ### BAS R 1K in 50 | 51 | This node reads the 1K ohms thermistor input channel(Make sure the corresponding jumper is in the "1K" position in order for this read to be correct). 52 | The card stack level and channel number can be set in the node dialog box or dynamically through ```msg.stack``` and ```msg.channel```. 53 | The read is triggered by the message input and output can be found in the output message payload as a number representing the resistance readings in kiloohms. 54 | 55 | ### BAS R 10K in 56 | 57 | This node reads the 10K ohms thermistor input channel(Make sure the corresponding jumper is in the "10K" position in order for this read to be correct). 58 | The card stack level and channel number can be set in the node dialog box or dynamically through ```msg.stack``` and ```msg.channel```. 59 | The read is triggered by the message input and output can be found in the output message payload as a number representing the resistance readings in kiloohms. 60 | 61 | ### BAS DC cnt 62 | 63 | This node reads the dry contact input cunter for one particular channel and set the counting edges for that channel. 64 | The card stack level and dry contact inplut counter channel number can be set in the node dialog box or dynamically through ```msg.stack``` and ```msg.channel```. 65 | The rising edge counting and/or falling edge counting can be enabled/diabled with coresponding check box in the node dialog. The edge settings are sent to the card every time you deply nthis node or the flow start or you select different channel for read through ```msg.channel```. 66 | The read is triggered by the message input and output can be found in the output message payload. 67 | 68 | ### BAS DC in 69 | 70 | This node reads the dry contact input state for one particular channel(Make sure the corresponding jumper is in the "1K" position in order for this read to be correct). 71 | The card stack level and dry contact inplut channel number can be set in the node dialog box or dynamically through ```msg.stack``` and ```msg.channel```. 72 | The read is triggered by the message input and output can be found in the output message payload as boolean. 73 | 74 | ## Important note 75 | 76 | This node is using the I2C-bus package from @fivdi, you can visit his work on github [here](https://github.com/fivdi/i2c-bus). 77 | The inspiration for this node came from @nielsnl68 work with [node-red-contrib-i2c](https://github.com/nielsnl68/node-red-contrib-i2c).Thank both for the great job. 78 | -------------------------------------------------------------------------------- /node-red-contrib-sm-bas/bas.html: -------------------------------------------------------------------------------- 1 | 21 | 22 | 26 | 27 | 89 | 90 | 91 | 111 | 112 | 115 | 116 | 177 | 178 | 179 | 199 | 200 | 203 | 204 | 265 | 266 | 286 | 287 | 292 | 293 | 354 | 355 | 356 | 376 | 377 | 382 | 383 | 444 | 445 | 446 | 474 | 475 | 478 | 479 | 543 | 544 | 545 | 565 | 566 | 569 | 570 | 632 | -------------------------------------------------------------------------------- /node-red-contrib-sm-bas/bas.js: -------------------------------------------------------------------------------- 1 | module.exports = function(RED) { 2 | "use strict"; 3 | var I2C = require("i2c-bus"); 4 | const DEFAULT_HW_ADD = 0x48; 5 | const I2C_TRIACS_SET_ADD = 1; 6 | const I2C_TRIACS_CLR_ADD = 2; 7 | const I2C_DRY_CONTACT_VAL_ADD = 3; 8 | const I2C_U0_10_OUT_VAL1_ADD = 4; 9 | const I2C_U0_10_IN_VAL1_ADD = 12; 10 | const I2C_R_1K_CH1 = 28; 11 | const I2C_R_10K_CH1 = 44; 12 | const I2C_MEM_DRY_CONTACT_RISING_ENABLE = 103; 13 | const I2C_MEM_DRY_CONTACT_FALLING_ENABLE = 104; 14 | const I2C_MEM_DRY_CONTACT_CH_CONT_RESET = 105; 15 | const I2C_MEM_DRY_CONTACT_CONTORS = 128; //4 bytes integers 16 | 17 | // The relay Node 18 | function TriacNode(n) { 19 | RED.nodes.createNode(this, n); 20 | this.stack = parseInt(n.stack); 21 | this.channel = parseInt(n.channel); 22 | this.payload = n.payload; 23 | this.payloadType = n.payloadType; 24 | var node = this; 25 | 26 | //node.log("Triac node init"); 27 | node.port = I2C.openSync( 1 ); 28 | node.on("input", function(msg) { 29 | var myPayload; 30 | var stack = node.stack;//|| msg.stack; 31 | if (isNaN(stack)) stack = msg.stack; 32 | var channel = node.channel;// || msg.channel; 33 | if (isNaN(channel)) channel = msg.channel; 34 | stack = parseInt(stack); 35 | channel = parseInt(channel); 36 | 37 | if (isNaN(stack + 1)) { 38 | this.status({fill:"red",shape:"ring",text:"Stack level ("+stack+") value is missing or incorrect"}); 39 | return; 40 | } else if (isNaN(channel) ) { 41 | this.status({fill:"red",shape:"ring",text:"Triac channel ("+channel+") value is missing or incorrect"}); 42 | return; 43 | } else { 44 | this.status({}); 45 | } 46 | var hwAdd = DEFAULT_HW_ADD; 47 | if(stack < 0){ 48 | stack = 0; 49 | } 50 | if(stack > 7){ 51 | stack = 7; 52 | } 53 | //check the type of io_expander 54 | hwAdd += stack; 55 | try { 56 | if (this.payloadType == null) { 57 | myPayload = this.payload; 58 | } else if (this.payloadType == 'none') { 59 | myPayload = null; 60 | } else { 61 | myPayload = RED.util.evaluateNodeProperty(this.payload, this.payloadType, this,msg); 62 | } 63 | 64 | 65 | if(channel < 1){ 66 | channel = 1; 67 | } 68 | if(channel > 4){ 69 | channel = 4; 70 | } 71 | 72 | if (myPayload == null || myPayload == false || myPayload == 0 || myPayload == 'off') { 73 | node.port.writeByte(hwAdd, I2C_TRIACS_CLR_ADD, channel, function(err) { 74 | if (err) { node.error(err, msg); 75 | } else { 76 | node.send(msg); 77 | } 78 | }); 79 | } else { 80 | node.port.writeByte(hwAdd, I2C_TRIACS_SET_ADD, channel, function(err) { 81 | if (err) { node.error(err, msg); 82 | } else { 83 | node.send(msg); 84 | } 85 | }); 86 | } 87 | 88 | } catch(err) { 89 | this.error(err,msg); 90 | } 91 | 92 | }); 93 | 94 | node.on("close", function() { 95 | node.port.closeSync(); 96 | }); 97 | } 98 | RED.nodes.registerType("BAS triac", TriacNode); 99 | 100 | function VInNode(n) { 101 | RED.nodes.createNode(this, n); 102 | this.stack = parseInt(n.stack); 103 | this.channel = parseInt(n.channel); 104 | this.payload = n.payload; 105 | this.payloadType = n.payloadType; 106 | var node = this; 107 | var buffer = Buffer.alloc(2); 108 | 109 | node.port = I2C.openSync( 1 ); 110 | node.on("input", function(msg) { 111 | var myPayload; 112 | var stack = node.stack; 113 | if (isNaN(stack)) stack = msg.stack; 114 | var channel = node.channel; 115 | if (isNaN(channel)) channel = msg.channel; 116 | stack = parseInt(stack); 117 | channel = parseInt(channel); 118 | //var buffcount = parseInt(node.count); 119 | if (isNaN(stack)) { 120 | this.status({fill:"red",shape:"ring",text:"Stack level ("+stack+") value is missing or incorrect"}); 121 | return; 122 | } else if (isNaN(channel) ) { 123 | this.status({fill:"red",shape:"ring",text:"Sensor number ("+channel+") value is missing or incorrect"}); 124 | return; 125 | } else { 126 | this.status({}); 127 | } 128 | try { 129 | var hwAdd = DEFAULT_HW_ADD; 130 | if(stack < 0){ 131 | stack = 0; 132 | } 133 | if(stack > 7){ 134 | stack = 7; 135 | } 136 | hwAdd += stack; 137 | 138 | if(channel < 1){ 139 | channel = 1; 140 | } 141 | if(channel > 8){ 142 | channel = 8; 143 | } 144 | 145 | if (this.payloadType == null) { 146 | myPayload = this.payload; 147 | } else if (this.payloadType == 'none') { 148 | myPayload = null; 149 | } else { 150 | myPayload = RED.util.evaluateNodeProperty(this.payload, this.payloadType, this,msg); 151 | } 152 | node.port.readI2cBlock(hwAdd, I2C_U0_10_IN_VAL1_ADD + (channel - 1)*2, 2, buffer, function(err, size, res) { 153 | if (err) { 154 | node.error(err, msg); 155 | } 156 | else{ 157 | msg.payload = res.readIntLE(0, 2) / 1000.0; 158 | node.send(msg); 159 | } 160 | }); 161 | 162 | } catch(err) { 163 | this.error(err,msg); 164 | } 165 | 166 | }); 167 | 168 | node.on("close", function() { 169 | node.port.closeSync(); 170 | }); 171 | } 172 | RED.nodes.registerType("BAS 0-10V in", VInNode); 173 | 174 | 175 | function VOutNode(n) { 176 | RED.nodes.createNode(this, n); 177 | this.stack = parseInt(n.stack); 178 | this.channel = parseInt(n.channel); 179 | this.payload = n.payload; 180 | this.payloadType = n.payloadType; 181 | var node = this; 182 | var buffer = Buffer.alloc(2); 183 | 184 | node.port = I2C.openSync( 1 ); 185 | node.on("input", function(msg) { 186 | var myPayload; 187 | var stack = node.stack; 188 | if (isNaN(stack)) stack = msg.stack; 189 | var channel = node.channel; 190 | if (isNaN(channel)) channel = msg.channel; 191 | stack = parseInt(stack); 192 | channel = parseInt(channel); 193 | //var buffcount = parseInt(node.count); 194 | if (this.payloadType == null) { 195 | myPayload = this.payload; 196 | } else if (this.payloadType == 'none') { 197 | myPayload = null; 198 | } else { 199 | myPayload = RED.util.evaluateNodeProperty(this.payload, this.payloadType, this,msg); 200 | } 201 | if (isNaN(stack)) { 202 | this.status({fill:"red",shape:"ring",text:"Stack level ("+stack+") value is missing or incorrect"}); 203 | return; 204 | } else if (isNaN(channel) ) { 205 | this.status({fill:"red",shape:"ring",text:"Sensor number ("+channel+") value is missing or incorrect"}); 206 | return; 207 | } else if(isNaN(myPayload)){ 208 | this.status({fill:"red",shape:"ring",text:"Payload type must be a number ("+this.payload+") value is missing or incorrect myPayload: ("+myPayload+")"}); 209 | return; 210 | } 211 | else{ 212 | this.status({}); 213 | } 214 | try { 215 | var hwAdd = DEFAULT_HW_ADD; 216 | if(stack < 0){ 217 | stack = 0; 218 | } 219 | if(stack > 7){ 220 | stack = 7; 221 | } 222 | hwAdd += stack; 223 | 224 | if(channel < 1){ 225 | channel = 1; 226 | } 227 | if(channel > 8){ 228 | channel = 8; 229 | } 230 | 231 | if(myPayload < 0){ 232 | myPayload = 0; 233 | } 234 | if(myPayload > 10){ 235 | myPayload = 10; 236 | } 237 | var intVal = Math.round(myPayload * 1000); 238 | 239 | node.port.writeWord(hwAdd, I2C_U0_10_OUT_VAL1_ADD + (channel - 1)*2, intVal, function(err, size, res) { 240 | if (err) { 241 | node.error(err, msg); 242 | } 243 | else{ 244 | //rmsg.payload = res.readIntLE(0, 2) / 1000.0; 245 | node.send(msg); 246 | } 247 | }); 248 | 249 | } catch(err) { 250 | this.error(err,msg); 251 | } 252 | 253 | }); 254 | 255 | node.on("close", function() { 256 | node.port.closeSync(); 257 | }); 258 | } 259 | RED.nodes.registerType("BAS 0-10V out", VOutNode); 260 | 261 | function RIn1KNode(n) { 262 | RED.nodes.createNode(this, n); 263 | this.stack = parseInt(n.stack); 264 | this.channel = parseInt(n.channel); 265 | this.payload = n.payload; 266 | this.payloadType = n.payloadType; 267 | var node = this; 268 | var buffer = Buffer.alloc(4); 269 | 270 | node.port = I2C.openSync( 1 ); 271 | node.on("input", function(msg) { 272 | var myPayload; 273 | var stack = node.stack; 274 | if (isNaN(stack)) stack = msg.stack; 275 | var channel = node.channel; 276 | if (isNaN(channel)) channel = msg.channel; 277 | stack = parseInt(stack); 278 | channel = parseInt(channel); 279 | //var buffcount = parseInt(node.count); 280 | if (isNaN(stack)) { 281 | this.status({fill:"red",shape:"ring",text:"Stack level ("+stack+") value is missing or incorrect"}); 282 | return; 283 | } else if (isNaN(channel) ) { 284 | this.status({fill:"red",shape:"ring",text:"Sensor number ("+channel+") value is missing or incorrect"}); 285 | return; 286 | } else { 287 | this.status({}); 288 | } 289 | try { 290 | var hwAdd = DEFAULT_HW_ADD; 291 | if(stack < 0){ 292 | stack = 0; 293 | } 294 | if(stack > 7){ 295 | stack = 7; 296 | } 297 | hwAdd += stack; 298 | 299 | if(channel < 1){ 300 | channel = 1; 301 | } 302 | if(channel > 8){ 303 | channel = 8; 304 | } 305 | 306 | if (this.payloadType == null) { 307 | myPayload = this.payload; 308 | } else if (this.payloadType == 'none') { 309 | myPayload = null; 310 | } else { 311 | myPayload = RED.util.evaluateNodeProperty(this.payload, this.payloadType, this,msg); 312 | } 313 | node.port.readI2cBlock(hwAdd, I2C_R_1K_CH1 + (channel - 1)*2, 2, buffer, function(err, size, res) { 314 | if (err) { 315 | node.error(err, msg); 316 | } 317 | else{ 318 | msg.payload = res.readIntLE(0, 4) / 1000.0; 319 | node.send(msg); 320 | } 321 | }); 322 | 323 | } catch(err) { 324 | this.error(err,msg); 325 | } 326 | 327 | }); 328 | 329 | node.on("close", function() { 330 | node.port.closeSync(); 331 | }); 332 | } 333 | RED.nodes.registerType("BAS R 1K in", RIn1KNode); 334 | 335 | 336 | function RIn10KNode(n) { 337 | RED.nodes.createNode(this, n); 338 | this.stack = parseInt(n.stack); 339 | this.channel = parseInt(n.channel); 340 | this.payload = n.payload; 341 | this.payloadType = n.payloadType; 342 | var node = this; 343 | var buffer = Buffer.alloc(4); 344 | 345 | node.port = I2C.openSync( 1 ); 346 | node.on("input", function(msg) { 347 | var myPayload; 348 | var stack = node.stack; 349 | if (isNaN(stack)) stack = msg.stack; 350 | var channel = node.channel; 351 | if (isNaN(channel)) channel = msg.channel; 352 | stack = parseInt(stack); 353 | channel = parseInt(channel); 354 | //var buffcount = parseInt(node.count); 355 | if (isNaN(stack)) { 356 | this.status({fill:"red",shape:"ring",text:"Stack level ("+stack+") value is missing or incorrect"}); 357 | return; 358 | } else if (isNaN(channel) ) { 359 | this.status({fill:"red",shape:"ring",text:"Sensor number ("+channel+") value is missing or incorrect"}); 360 | return; 361 | } else { 362 | this.status({}); 363 | } 364 | try { 365 | var hwAdd = DEFAULT_HW_ADD; 366 | if(stack < 0){ 367 | stack = 0; 368 | } 369 | if(stack > 7){ 370 | stack = 7; 371 | } 372 | hwAdd += stack; 373 | 374 | if(channel < 1){ 375 | channel = 1; 376 | } 377 | if(channel > 8){ 378 | channel = 8; 379 | } 380 | 381 | if (this.payloadType == null) { 382 | myPayload = this.payload; 383 | } else if (this.payloadType == 'none') { 384 | myPayload = null; 385 | } else { 386 | myPayload = RED.util.evaluateNodeProperty(this.payload, this.payloadType, this,msg); 387 | } 388 | node.port.readI2cBlock(hwAdd, I2C_R_10K_CH1 + (channel - 1)*2, 2, buffer, function(err, size, res) { 389 | if (err) { 390 | node.error(err, msg); 391 | } 392 | else{ 393 | msg.payload = res.readIntLE(0, 4) / 1000.0; 394 | node.send(msg); 395 | } 396 | }); 397 | 398 | } catch(err) { 399 | this.error(err,msg); 400 | } 401 | 402 | }); 403 | 404 | node.on("close", function() { 405 | node.port.closeSync(); 406 | }); 407 | } 408 | RED.nodes.registerType("BAS R 10K in", RIn10KNode); 409 | 410 | 411 | function DryCounterNode(n) { 412 | RED.nodes.createNode(this, n); 413 | this.stack = parseInt(n.stack); 414 | this.channel = parseInt(n.channel); 415 | this.falling = n.falling; 416 | this.rising = n.rising; 417 | this.payload = n.payload; 418 | this.payloadType = n.payloadType; 419 | var node = this; 420 | var buffer = Buffer.alloc(4); 421 | var lastCfgCh = 0; 422 | var cfgByte = 0; 423 | 424 | node.port = I2C.openSync( 1 ); 425 | node.on("input", function(msg) { 426 | var myPayload; 427 | var stack = node.stack; 428 | if (isNaN(stack)) stack = msg.stack; 429 | var channel = node.channel; 430 | if (isNaN(channel)) channel = msg.channel; 431 | stack = parseInt(stack); 432 | channel = parseInt(channel); 433 | var rising = true; 434 | var falling = true; 435 | if(node.rising == false || node.rising == "false" || node.rising == 0) 436 | { 437 | rising = false; 438 | } 439 | if(node.falling == false || node.falling == "false" || node.falling == 0) 440 | { 441 | falling = false; 442 | } 443 | //var buffcount = parseInt(node.count); 444 | if (isNaN(stack)) { 445 | this.status({fill:"red",shape:"ring",text:"Stack level ("+stack+") value is missing or incorrect"}); 446 | return; 447 | } else if (isNaN(channel) ) { 448 | this.status({fill:"red",shape:"ring",text:"Sensor number ("+channel+") value is missing or incorrect"}); 449 | return; 450 | } else { 451 | this.status({}); 452 | } 453 | var hwAdd = DEFAULT_HW_ADD; 454 | if(stack < 0){ 455 | stack = 0; 456 | } 457 | if(stack > 7){ 458 | stack = 7; 459 | } 460 | hwAdd += stack; 461 | 462 | if(channel < 1){ 463 | channel = 1; 464 | } 465 | if(channel > 8){ 466 | channel = 8; 467 | } 468 | if(lastCfgCh != channel) 469 | { 470 | //node.log("Check configuration"); 471 | node.port.readByte(hwAdd, I2C_MEM_DRY_CONTACT_RISING_ENABLE, function(err, rbyte) { 472 | if (err) { 473 | node.error(err, msg); 474 | } 475 | else{ 476 | if(((rising == true) && ((rbyte & (1 << (channel - 1))) == 0)) || ((rising == false) && ((rbyte & (1 << (channel - 1))) != 0))){ 477 | cfgByte = rbyte; 478 | if(rising){ 479 | cfgByte |= 1 << (channel - 1); 480 | //node.log("Enable rising edge counting on channel " + channel ); 481 | } 482 | else{ 483 | cfgByte &= 0xff ^ (1 << (channel -1)); 484 | //node.log("Disable rising edge counting on channel " + channel ); 485 | } 486 | 487 | node.port.writeByte(hwAdd, I2C_MEM_DRY_CONTACT_RISING_ENABLE, cfgByte, function(err) { 488 | if (err) { 489 | node.error(err, msg); 490 | } 491 | }); 492 | } 493 | } 494 | }); 495 | 496 | node.port.readByte(hwAdd, I2C_MEM_DRY_CONTACT_FALLING_ENABLE, function(err, rbyte) { 497 | if (err) { 498 | node.error(err, msg); 499 | } 500 | else{ 501 | if(((falling == true) && ((rbyte & (1 << (channel - 1))) == 0)) || ((falling == false) && ((rbyte & (1 << (channel - 1))) != 0))){ 502 | cfgByte = rbyte; 503 | if(falling){ 504 | cfgByte |= 1 << (channel - 1); 505 | node.log("Enable falling edge counting on channel " + channel ); 506 | } 507 | else{ 508 | cfgByte &= 0xff ^ (1 << (channel -1)); 509 | node.log("Disable falling edge counting on channel " + channel ); 510 | } 511 | 512 | node.port.writeByte(hwAdd, I2C_MEM_DRY_CONTACT_FALLING_ENABLE, cfgByte, function(err) { 513 | if (err) { 514 | node.error(err, msg); 515 | } 516 | }); 517 | } 518 | } 519 | }); 520 | lastCfgCh = channel; 521 | } 522 | try { 523 | 524 | if (this.payloadType == null) { 525 | myPayload = this.payload; 526 | } else if (this.payloadType == 'none') { 527 | myPayload = null; 528 | } else { 529 | myPayload = RED.util.evaluateNodeProperty(this.payload, this.payloadType, this,msg); 530 | } 531 | node.port.readI2cBlock(hwAdd, I2C_MEM_DRY_CONTACT_CONTORS + (channel - 1)*4, 4, buffer, function(err, size, res) { 532 | if (err) { 533 | node.error(err, msg); 534 | } 535 | else{ 536 | msg.payload = res.readIntLE(0, 4); 537 | node.send(msg); 538 | } 539 | }); 540 | 541 | } catch(err) { 542 | this.error(err,msg); 543 | } 544 | 545 | }); 546 | 547 | node.on("close", function() { 548 | node.port.closeSync(); 549 | }); 550 | } 551 | RED.nodes.registerType("BAS DC cnt", DryCounterNode); 552 | 553 | 554 | function DryContactNode(n) { 555 | RED.nodes.createNode(this, n); 556 | this.stack = parseInt(n.stack); 557 | this.channel = parseInt(n.channel); 558 | this.falling = n.falling; 559 | this.rising = n.rising; 560 | this.payload = n.payload; 561 | this.payloadType = n.payloadType; 562 | var node = this; 563 | var buffer = Buffer.alloc(4); 564 | 565 | 566 | node.port = I2C.openSync( 1 ); 567 | node.on("input", function(msg) { 568 | var myPayload; 569 | var stack = node.stack; 570 | if (isNaN(stack)) stack = msg.stack; 571 | var channel = node.channel; 572 | if (isNaN(channel)) channel = msg.channel; 573 | stack = parseInt(stack); 574 | channel = parseInt(channel); 575 | 576 | //var buffcount = parseInt(node.count); 577 | if (isNaN(stack)) { 578 | this.status({fill:"red",shape:"ring",text:"Stack level ("+stack+") value is missing or incorrect"}); 579 | return; 580 | } else if (isNaN(channel) ) { 581 | this.status({fill:"red",shape:"ring",text:"Sensor number ("+channel+") value is missing or incorrect"}); 582 | return; 583 | } else { 584 | this.status({}); 585 | } 586 | var hwAdd = DEFAULT_HW_ADD; 587 | if(stack < 0){ 588 | stack = 0; 589 | } 590 | if(stack > 7){ 591 | stack = 7; 592 | } 593 | hwAdd += stack; 594 | 595 | if(channel < 1){ 596 | channel = 1; 597 | } 598 | if(channel > 8){ 599 | channel = 8; 600 | } 601 | try { 602 | 603 | if (this.payloadType == null) { 604 | myPayload = this.payload; 605 | } else if (this.payloadType == 'none') { 606 | myPayload = null; 607 | } else { 608 | myPayload = RED.util.evaluateNodeProperty(this.payload, this.payloadType, this,msg); 609 | } 610 | node.port.readByte(hwAdd, I2C_DRY_CONTACT_VAL_ADD , function(err, res) { 611 | if (err) { 612 | node.error(err, msg); 613 | } 614 | else{ 615 | if ((res & (1 << (channel - 1))) != 0) { 616 | msg.payload = true; 617 | } 618 | else{ 619 | msg.payload = false; 620 | } 621 | node.send(msg); 622 | } 623 | }); 624 | 625 | } catch(err) { 626 | this.error(err,msg); 627 | } 628 | 629 | }); 630 | 631 | node.on("close", function() { 632 | node.port.closeSync(); 633 | }); 634 | } 635 | RED.nodes.registerType("BAS DC in", DryContactNode); 636 | 637 | } 638 | -------------------------------------------------------------------------------- /node-red-contrib-sm-bas/icons/adc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/node-red-contrib-sm-bas/icons/adc.png -------------------------------------------------------------------------------- /node-red-contrib-sm-bas/icons/dac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/node-red-contrib-sm-bas/icons/dac.png -------------------------------------------------------------------------------- /node-red-contrib-sm-bas/icons/switch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/node-red-contrib-sm-bas/icons/switch.png -------------------------------------------------------------------------------- /node-red-contrib-sm-bas/icons/thermistor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/node-red-contrib-sm-bas/icons/thermistor.png -------------------------------------------------------------------------------- /node-red-contrib-sm-bas/icons/triac.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/node-red-contrib-sm-bas/icons/triac.jpg -------------------------------------------------------------------------------- /node-red-contrib-sm-bas/icons/triac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/node-red-contrib-sm-bas/icons/triac.png -------------------------------------------------------------------------------- /node-red-contrib-sm-bas/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-red-contrib-sm-bas", 3 | "version": "1.0.2", 4 | "bundleDependencies": false, 5 | "dependencies": { 6 | "i2c-bus": ">1.0.0" 7 | }, 8 | "engines": { 9 | "node": ">=10.0.0" 10 | }, 11 | "deprecated": false, 12 | "description": "A Node-RED collection of nodes to control Sequent Microsystems Building Automation Card", 13 | "main": "bas.js", 14 | "scripts": { 15 | "test": "echo \"Error: no test specified\" && exit 1" 16 | }, 17 | "author": "Sequent Microsystems", 18 | "license": "MIT", 19 | "node-red" : { 20 | "version": ">=2.0.0", 21 | "nodes": { 22 | "bas": "bas.js" 23 | } 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/SequentMicrosystems/megabas-rpi/tree/master/node-red-contrib-sm-bas" 28 | }, 29 | "keywords": [ 30 | "node-red", 31 | "node-red-contrib", 32 | "i2c", 33 | "industrial", 34 | "building", 35 | "automation", 36 | "0-10V", 37 | "thermistor", 38 | "AC" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /python/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Sequent Microsystems 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /python/Makefile: -------------------------------------------------------------------------------- 1 | PYTHON = python 2 | SETUP_PY = setup.py 3 | DIST = dist 4 | 5 | .PHONY: all dist 6 | 7 | all: dist 8 | @echo "Everything done!" 9 | @echo ' > Run "twine upload dist/*" to upload to pypi.org.' 10 | 11 | dist: 12 | @echo "Creating python distribution." 13 | @rm -rf $(DIST) 14 | @$(PYTHON) $(SETUP_PY) sdist bdist_wheel 1>/dev/null 15 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | 2 | [![megabas-rpi](res/sequent.jpg)](https://sequentmicrosystems.com) 3 | 4 | # megabas 5 | 6 | This is the python library to control the [ Building Automation Card for Raspberry Pi.](https://sequentmicrosystems.com/products/raspberry-pi-building-automation) 7 | 8 | ## Install 9 | 10 | ```bash 11 | sudo pip install SMmegabas 12 | ``` 13 | 14 | ## Usage 15 | 16 | Now you can import the megaio library and use its functions. To test, read triacs status from the MegaIO IND board with stack level 0: 17 | 18 | ```bash 19 | ~$ python 20 | Python 2.7.9 (default, Sep 17 2016, 20:26:04) 21 | [GCC 4.9.2] on linux2 22 | Type "help", "copyright", "credits" or "license" for more information. 23 | >>> import megabas 24 | >>> megabas.getTriacs(0) 25 | 0 26 | >>> 27 | ``` 28 | 29 | ## Functions 30 | 31 | ### def getVer(stack) 32 | Return firmware version 33 | 34 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 35 | 36 | 37 | ### setUOut(stack, ch, value) 38 | Set the selected output 0-10V channel value in volts 39 | 40 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 41 | 42 | ch - selected channel number [1..4] 43 | 44 | value - voltage output value in V [0..10] 45 | 46 | 47 | ### getUOut(stack, ch) 48 | Get the selected output 0-10V channel value in volts 49 | 50 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 51 | 52 | ch - selected channel number [1..4] 53 | 54 | return - value in V [0..10] 55 | 56 | 57 | ### getUIn(stack, ch) 58 | Return the selected input 0-10V channel value in volts 59 | 60 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 61 | 62 | ch - selected channel number [1..8] 63 | 64 | return - value in V [0..10] 65 | 66 | 67 | ### getRIn1K(stack, ch) 68 | Return the selected resistance (1K) measurements in kilo Ohms. This measurement is valid only if the jumper is place in "1K" position. 69 | On this type of input is recomended to measure 1kOhm thermistor. 70 | 71 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 72 | 73 | ch - selected channel number [1..8] 74 | 75 | return - value in kOhm [0..30] were 30 means invalid measurements 76 | 77 | 78 | ### getRIn10K(stack, ch) 79 | Return the selected resistance (10K) measurements in kilo Ohms. This measurement is valid only if the jumper is place in "10K" position. 80 | On this type of input is recomended to measure 10K thermistor. 81 | 82 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 83 | 84 | ch - selected channel number [1..8] 85 | 86 | return - value in kOhm [0..30] 87 | 88 | 89 | ### setTriac(stack, ch, val) 90 | Set one triac state. 91 | 92 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 93 | 94 | ch - triac number (id) [1..4] 95 | 96 | val - triac state 1: turn ON, 0: turn OFF[0..1] 97 | 98 | 99 | ### setTriacs(stack, value) 100 | Set all triacs state. 101 | 102 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 103 | 104 | value - 4 bit value of all triacs (ex: 15: turn on all triacs, 0: turn off all triacs, 1:turn on triac #1 and off the rest) 105 | 106 | 107 | ### getTriac(stack, ch) 108 | Return the state of one triac. 109 | 110 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 111 | 112 | ch - triac number (id) [1..4] 113 | 114 | return - (0/1) 115 | 116 | 117 | ### getTriacs(stack) 118 | Return the state of all triacs. 119 | 120 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 121 | 122 | return - [0..15] 123 | 124 | 125 | ### togleTriac(stack, ch, delay, count) 126 | Togle one triac state. 127 | 128 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 129 | 130 | ch - triac number (id) [1..4] 131 | 132 | delay - delay between togles 133 | 134 | count - number of togles 135 | 136 | 137 | ### getContact(stack) 138 | Get the state of the dry contact inputs 139 | 140 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 141 | 142 | return - value of the inputs [0..255] 143 | 144 | 145 | ### getContactCh(stack, ch) 146 | Get the state of the dry contact input channel 147 | 148 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 149 | 150 | ch - selected channel number [1..4] 151 | 152 | return - value of the inputs [0/1] 153 | 154 | 155 | ### getContactCounter(stack, ch) 156 | Return the counter value for corresponding dry contact input. 157 | 158 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 159 | 160 | ch - selected channel number [1..4] 161 | 162 | return - counter value (32bits) 163 | 164 | 165 | ### getContactCountEdge(stack, ch) 166 | Return dry contact edge settings for coresponding channel 167 | 168 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 169 | 170 | ch - selected channel number [1..4] 171 | 172 | return: 0 - edge count disable; 1 - rising edge count enabled; 2 - falling edge count enabled; 3 - both edges count enabled 173 | 174 | 175 | ### setContactCountEdge(stack, ch, edge) 176 | Set dry contact edge count mode 177 | 178 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 179 | 180 | ch - selected channel number [1..4] 181 | 182 | edge: 0 - edge count disable; 1 - rising edge count enabled; 2 - falling edge count enabled; 3 - both edges count enabled 183 | 184 | 185 | ### getInVolt(stack) 186 | Get the power supply voltage 187 | 188 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 189 | 190 | return - the power supply in Volts 191 | 192 | 193 | ### getRaspVolt(stack) 194 | Get the raspberry power supply voltage (5V) 195 | 196 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 197 | 198 | return - the Raspberry pi power supply in Volts 199 | 200 | 201 | ### getCpuTemp(stack) 202 | Get the cpu temperature 203 | 204 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 205 | 206 | return - temperature in deg Celsius 207 | 208 | 209 | ### wdtGetPeriod(stack) 210 | Return the current period of the watchdog timer in seconds 211 | 212 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 213 | 214 | 215 | ### wdtSetPeriod(stack, val) 216 | Set the period of the watchdog in seconds, val = 65000 disable the watchdog 217 | 218 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 219 | 220 | val - [10..65000] 221 | 222 | 223 | ### wdtReload(stack) 224 | Reload the watchdog timer with the current period. 225 | The next reload command must occur in no more the "period" time in order to prevent watchdog to re-power the Raspberry. 226 | This command also enables the watchdog if is disabled (power-up disabled). 227 | 228 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 229 | 230 | 231 | ### wdtSetDefaultPeriod(stack, val) 232 | This function updates the period that will be loaded after Raspberry power is turned off and back on. You must set this period long enough to let Raspberry boot-up and your "watchdog maintaining" script to start. 233 | 234 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 235 | 236 | value - [10...64999] seconds 237 | 238 | 239 | ### wdtGetDefaultPeriod(stack) 240 | Return the default period 241 | 242 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 243 | 244 | value - [10...64999] seconds 245 | 246 | 247 | ### wdtSetOffInterval(stack, val) 248 | Set the time interval in seconds for keeping Raspberry power off in case of watchdog timer expire. 249 | 250 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 251 | 252 | val - [10...4147200] seconds 253 | 254 | 255 | ### wdtGetOffInterval(stack) 256 | Return the Off time interval in seconds 257 | 258 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 259 | 260 | return - [10...4147200] seconds 261 | 262 | 263 | ### wdtGetResetCount(stack) 264 | Return the numbers of Raspberry re-powers performed by the watchdog 265 | 266 | stack - stack level of the megabas card (selectable from address jumpers [0..8]) 267 | 268 | return - [0..65535] 269 | 270 | ## RTC Functions 271 | 272 | ### rtcGet(stack) 273 | Return the RTC date and time as a list 274 | 275 | stack - stack level of the megabas card (selectable from address jumpers [0..7]) 276 | 277 | return (year, month, day, hour, minute, seconds) 278 | 279 | ### rtcSet(stack, y, mo, d, h, m, s) 280 | Set the RTC date and time 281 | 282 | stack - stack level of the megabas card (selectable from address jumpers [0..7]) 283 | 284 | y - year between 2000..2255 or between 0..255 285 | 286 | mo - month 1..12 287 | 288 | d - day 289 | 290 | h - hour 291 | 292 | m - minutes 293 | 294 | s - seconds 295 | 296 | ## Owire Bus Functions 297 | 298 | ### owbScan(stack) 299 | Start scanning for connected sensors 300 | 301 | stack - stack level of the megabas card (selectable from address jumpers [0..7]) 302 | 303 | ### owbGetSensorNo(stack) 304 | Get the numbers of 18B20 sensors connected on the bus 305 | 306 | stack - stack level of the megabas card (selectable from address jumpers [0..7]) 307 | 308 | return number of connected sensors 309 | 310 | ### owbGetTemp(stack, sensor) 311 | Read the temperature aquired by one sensor 312 | 313 | stack - stack level of the megabas card (selectable from address jumpers [0..7]) 314 | 315 | sensor - sensor number [1..16] 316 | 317 | return temperature in degree Celsius 318 | 319 | ### owbGetRomCode(stack, sensor) 320 | Read the unic ROM code of one sensor 321 | 322 | stack - stack level of the megabas card (selectable from address jumpers [0..7]) 323 | 324 | sensor - sensor number [1..16] 325 | 326 | return ROM code as 8 bytes array 327 | -------------------------------------------------------------------------------- /python/megabas/__init__.py: -------------------------------------------------------------------------------- 1 | import smbus2 2 | import time 3 | import math 4 | 5 | BUS_NO = 1 # change this in case of using different SBC 7 for ROCK 4 SE 6 | TRIACS_VAL_ADD = 0 7 | TRIACS_SET_ADD = 1 8 | TRIACS_CLR_ADD = 2 9 | DRY_CONTACT_VAL_ADD = 3 10 | 11 | U0_10_OUT_VAL1_ADD = 4 12 | U0_10_OUT_VAL2_ADD = 6 13 | U0_10_OUT_VAL3_ADD = 8 14 | U0_10_OUT_VAL4_ADD = 10 15 | U0_10_IN_VAL1_ADD = 12 16 | U0_10_IN_VAL2_ADD = 14 17 | U0_10_IN_VAL3_ADD = 16 18 | U0_10_IN_VAL4_ADD = 18 19 | U0_10_IN_VAL5_ADD = 20 20 | U0_10_IN_VAL6_ADD = 22 21 | U0_10_IN_VAL7_ADD = 24 22 | U0_10_IN_VAL8_ADD = 26 23 | R_1K_CH1 = 28 24 | R_1K_CH2 = 30 25 | R_1K_CH3 = 32 26 | R_1K_CH4 = 34 27 | R_1K_CH5 = 36 28 | R_1K_CH6 = 38 29 | R_1K_CH7 = 40 30 | R_1K_CH8 = 42 31 | R_10K_CH1 = 44 32 | R_10K_CH2 = 46 33 | R_10K_CH3 = 48 34 | R_10K_CH4 = 50 35 | R_10K_CH5 = 52 36 | R_10K_CH6 = 54 37 | R_10K_CH7 = 56 38 | R_10K_CH8 = 58 39 | CAL_VAL_ADD = 60 40 | CAL_CH_ADD = 62 # 60 41 | CAL_CMD_ADD = 63 42 | CAL_STAT_ADD = 64 43 | # TEMPERATURE_ADD = 64 44 | MODBUS_SETINGS_ADD = 65 # = (0) 45 | MODBUS_ID_OFFSET_ADD = 69 46 | 47 | RTC_YEAR_ADD = 70 48 | RTC_MONTH_ADD = 71 49 | RTC_DAY_ADD = 72 50 | RTC_HOUR_ADD = 73 51 | RTC_MINUTE_ADD = 74 52 | RTC_SECOND_ADD = 75 53 | 54 | RTC_SET_YEAR_ADD = 76 55 | RTC_SET_MONTH_ADD = 77 56 | RTC_SET_DAY_ADD = 78 57 | RTC_SET_HOUR_ADD = 79 58 | RTC_SET_MINUTE_ADD = 80 59 | RTC_SET_SECOND_ADD = 81 60 | RTC_CMD_ADD = 82 61 | 62 | I2C_MEM_WDT_RESET_ADD = 83 63 | I2C_MEM_WDT_INTERVAL_SET_ADD = 84 64 | I2C_MEM_WDT_INTERVAL_GET_ADD = I2C_MEM_WDT_INTERVAL_SET_ADD + 2 65 | I2C_MEM_WDT_INIT_INTERVAL_SET_ADD = I2C_MEM_WDT_INTERVAL_GET_ADD + 2 66 | I2C_MEM_WDT_INIT_INTERVAL_GET_ADD = I2C_MEM_WDT_INIT_INTERVAL_SET_ADD + 2 67 | I2C_MEM_WDT_RESET_COUNT_ADD = I2C_MEM_WDT_INIT_INTERVAL_GET_ADD + 2 68 | I2C_MEM_WDT_CLEAR_RESET_COUNT_ADD = I2C_MEM_WDT_RESET_COUNT_ADD + 2 69 | I2C_MEM_WDT_POWER_OFF_INTERVAL_SET_ADD = I2C_MEM_WDT_CLEAR_RESET_COUNT_ADD + 1 70 | I2C_MEM_WDT_POWER_OFF_INTERVAL_GET_ADD = I2C_MEM_WDT_POWER_OFF_INTERVAL_SET_ADD + 4 71 | I2C_MEM_DRY_CONTACT_RISING_ENABLE = I2C_MEM_WDT_POWER_OFF_INTERVAL_GET_ADD + 4 72 | I2C_MEM_DRY_CONTACT_FALLING_ENABLE = I2C_MEM_DRY_CONTACT_RISING_ENABLE + 1 73 | I2C_MEM_DRY_CONTACT_CH_CONT_RESET = I2C_MEM_DRY_CONTACT_FALLING_ENABLE 74 | 75 | DIAG_TEMPERATURE_MEM_ADD = 0x72 # = (0) 76 | DIAG_24V_MEM_ADD = 0x73 77 | DIAG_24V_MEM_ADD1 = 0x74 78 | DIAG_5V_MEM_ADD = 0x75 79 | DIAG_5V_MEM_ADD1 = 0x76 80 | CAN_REC_MPS_MEM_ADD = 0x77 81 | REVISION_HW_MAJOR_MEM_ADD = 0x78 # = (0) 82 | REVISION_HW_MINOR_MEM_ADD = 0x79 83 | REVISION_MAJOR_MEM_ADD = 0x7a 84 | REVISION_MINOR_MEM_ADD = 0x7b 85 | BUILD_DAY_MEM_ADD = 0x7c 86 | BUILD_MOTH_MEM_ADD = 0x7d 87 | BUILD_YEAR_MEM_ADD = 0x7e 88 | BOARD_TYPE_MEM_ADD = 0x7f 89 | I2C_MEM_DRY_CONTACT_COUNTERS = 0x80 90 | RELOAD_KEY = 0xca 91 | U_OUT_CH_MAX = 4 92 | U_IN_CH_MAX = 8 93 | CONTACT_CH_MAX = 8 94 | R_IN_CH_MAX = 8 95 | TRIAC_CH_MAX = 4 96 | HW_ADD = 0x48 97 | WDT_MAX_POWER_OFF_INTERVAL = 4147200 # 48 days 98 | 99 | 100 | def c2(val): 101 | if val > 32768: 102 | val = val - 65536 103 | return val 104 | 105 | 106 | def checkStack(stack): 107 | if stack < 0 or stack > 7: 108 | raise ValueError('Invalid stack level [0..7]') 109 | 110 | 111 | def checkCh(ch, max): 112 | if ch < 1 or ch > max: 113 | raise ValueError('Channel out of range [1..' + str(max) + ']') 114 | 115 | 116 | def checkOwbSns(ch): 117 | if ch < 1 or ch > 16: 118 | raise ValueError('One Wire Bus sensor number out of range [1..16]') 119 | 120 | 121 | def getVer(stack): 122 | checkStack(stack) 123 | bus = smbus2.SMBus(BUS_NO) 124 | fw_maj = bus.read_byte_data(HW_ADD + stack, REVISION_MAJOR_MEM_ADD) 125 | fw_min = bus.read_byte_data(HW_ADD + stack, REVISION_MINOR_MEM_ADD) 126 | ret = " Fw " + str(fw_maj) + "." + str(fw_min) 127 | # print(" Hardware "+str(hw_maj)+"."+str(hw_min) + " Firmware "+str(fw_maj)+"."+str(fw_min)) 128 | bus.close() 129 | return ret 130 | 131 | 132 | def setUOut(stack, ch, val): 133 | checkCh(ch, U_OUT_CH_MAX) 134 | checkStack(stack) 135 | if val < 0 or val > 10: 136 | raise ValueError('Invalid value') 137 | 138 | bus = smbus2.SMBus(BUS_NO) 139 | bus.write_word_data(HW_ADD + stack, U0_10_OUT_VAL1_ADD + (2 * (ch - 1)), int(val * 1000)) 140 | bus.close() 141 | return 1 142 | 143 | 144 | def getUOut(stack, ch): 145 | checkCh(ch, U_OUT_CH_MAX) 146 | checkStack(stack) 147 | bus = smbus2.SMBus(BUS_NO) 148 | val = bus.read_word_data(HW_ADD + stack, U0_10_OUT_VAL1_ADD + (2 * (ch - 1))) 149 | bus.close() 150 | return c2(val) / 1000.0 151 | 152 | 153 | def getUIn(stack, ch): 154 | checkCh(ch, U_IN_CH_MAX) 155 | checkStack(stack) 156 | bus = smbus2.SMBus(BUS_NO) 157 | val = bus.read_word_data(HW_ADD + stack, U0_10_IN_VAL1_ADD + (2 * (ch - 1))) 158 | bus.close() 159 | return c2(val) / 1000.0 160 | 161 | 162 | def getRIn1K(stack, ch): 163 | checkCh(ch, R_IN_CH_MAX) 164 | checkStack(stack) 165 | bus = smbus2.SMBus(BUS_NO) 166 | val = bus.read_word_data(HW_ADD + stack, R_1K_CH1 + (2 * (ch - 1))) 167 | bus.close() 168 | return val / 1000.0 169 | 170 | 171 | def getRIn10K(stack, ch): 172 | checkCh(ch, R_IN_CH_MAX) 173 | checkStack(stack) 174 | bus = smbus2.SMBus(BUS_NO) 175 | val = bus.read_word_data(HW_ADD + stack, R_10K_CH1 + (2 * (ch - 1))) 176 | bus.close() 177 | return val / 1000.0 178 | 179 | 180 | def getTriacs(stack): 181 | checkStack(stack) 182 | bus = smbus2.SMBus(BUS_NO) 183 | val = bus.read_byte_data(HW_ADD + stack, TRIACS_VAL_ADD) 184 | bus.close() 185 | return val 186 | 187 | 188 | def getTriac(stack, ch): 189 | checkStack(stack) 190 | bus = smbus2.SMBus(BUS_NO) 191 | val = bus.read_byte_data(HW_ADD + stack, TRIACS_VAL_ADD) 192 | bus.close() 193 | mask = (1 << (ch - 1)) 194 | return val & mask 195 | 196 | 197 | def setTriacs(stack, val): 198 | checkStack(stack) 199 | bus = smbus2.SMBus(BUS_NO) 200 | try: 201 | bus.write_byte_data(HW_ADD + stack, TRIACS_VAL_ADD, val) 202 | except: 203 | bus.close() 204 | return -1 205 | bus.close() 206 | return 1 207 | 208 | 209 | def setTriac(stack, ch, val): 210 | checkCh(ch, TRIAC_CH_MAX) 211 | checkStack(stack) 212 | bus = smbus2.SMBus(BUS_NO) 213 | if val != 0: 214 | bus.write_byte_data(HW_ADD + stack, TRIACS_SET_ADD, ch) 215 | else: 216 | bus.write_byte_data(HW_ADD + stack, TRIACS_CLR_ADD, ch) 217 | bus.close() 218 | return 1 219 | 220 | 221 | def togleTriac(stack, ch, delay, count): 222 | checkCh(ch, TRIAC_CH_MAX) 223 | checkStack(stack) 224 | for i in range(count): 225 | setTriac(stack, ch, 1) 226 | time.sleep(delay) 227 | setTriac(stack, ch, 0) 228 | time.sleep(delay) 229 | 230 | 231 | def getContact(stack): 232 | checkStack(stack) 233 | bus = smbus2.SMBus(BUS_NO) 234 | val = bus.read_byte_data(HW_ADD + stack, DRY_CONTACT_VAL_ADD) 235 | bus.close() 236 | return val 237 | 238 | 239 | def getContactCh(stack, ch): 240 | checkCh(ch, CONTACT_CH_MAX) 241 | checkStack(stack) 242 | bus = smbus2.SMBus(BUS_NO) 243 | val = bus.read_byte_data(HW_ADD + stack, DRY_CONTACT_VAL_ADD) 244 | bus.close() 245 | mask = 1 << (ch - 1) 246 | if val & mask: 247 | return 1 248 | return 0 249 | 250 | 251 | def getContactCounter(stack, ch): 252 | checkCh(ch, CONTACT_CH_MAX) 253 | checkStack(stack) 254 | bus = smbus2.SMBus(BUS_NO) 255 | try: 256 | buff = bus.read_i2c_block_data(HW_ADD + stack, I2C_MEM_DRY_CONTACT_COUNTERS + (ch - 1) * 4, 4) 257 | val = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24) 258 | except Exception as e: 259 | bus.close() 260 | raise ValueError(e) 261 | bus.close() 262 | return val 263 | 264 | 265 | def getContactCountEdge(stack, ch): 266 | checkCh(ch, CONTACT_CH_MAX) 267 | checkStack(stack) 268 | bus = smbus2.SMBus(BUS_NO) 269 | try: 270 | rising = bus.read_byte_data(HW_ADD + stack, I2C_MEM_DRY_CONTACT_RISING_ENABLE) 271 | falling = bus.read_byte_data(HW_ADD + stack, I2C_MEM_DRY_CONTACT_FALLING_ENABLE) 272 | except Exception as e: 273 | bus.close() 274 | raise Error(e) 275 | bus.close() 276 | val = 0 277 | if (rising & (1 << (ch - 1))) != 0: 278 | val += 1 279 | if (falling & (1 << (ch - 1))) != 0: 280 | val += 2 281 | return val 282 | 283 | 284 | def setContactCountEdge(stack, ch, edge): 285 | checkCh(ch, CONTACT_CH_MAX) 286 | checkStack(stack) 287 | if edge < 0 or edge > 3: 288 | raise ValueError('Invalid edge type, 0 - none(disable counting), 1 - rising, 2 - falling, 3 - both') 289 | bus = smbus2.SMBus(BUS_NO) 290 | try: 291 | rising = bus.read_byte_data(HW_ADD + stack, I2C_MEM_DRY_CONTACT_RISING_ENABLE) 292 | falling = bus.read_byte_data(HW_ADD + stack, I2C_MEM_DRY_CONTACT_FALLING_ENABLE) 293 | except Exception as e: 294 | bus.close() 295 | raise Error(e) 296 | if edge == 0: 297 | rising = rising & (~(1 << (ch - 1))) 298 | falling = falling & (~(1 << (ch - 1))) 299 | else: 300 | if (edge & 1) != 0: 301 | rising = rising | (1 << (ch - 1)) 302 | if (edge & 2) != 0: 303 | falling = falling | (1 << (ch - 1)) 304 | try: 305 | bus.write_byte_data(HW_ADD + stack, I2C_MEM_DRY_CONTACT_RISING_ENABLE, rising) 306 | bus.write_byte_data(HW_ADD + stack, I2C_MEM_DRY_CONTACT_FALLING_ENABLE, falling) 307 | except Exception as e: 308 | bus.close() 309 | raise Error(e) 310 | bus.close() 311 | 312 | 313 | def getInVolt(stack): 314 | checkStack(stack) 315 | bus = smbus2.SMBus(BUS_NO) 316 | val = bus.read_word_data(HW_ADD + stack, DIAG_24V_MEM_ADD) 317 | bus.close() 318 | return val / 1000.0 319 | 320 | 321 | def getRaspVolt(stack): 322 | checkStack(stack) 323 | bus = smbus2.SMBus(BUS_NO) 324 | val = bus.read_word_data(HW_ADD + stack, DIAG_5V_MEM_ADD) 325 | bus.close() 326 | return val / 1000.0 327 | 328 | 329 | def getCpuTemp(stack): 330 | checkStack(stack) 331 | bus = smbus2.SMBus(BUS_NO) 332 | val = bus.read_byte_data(HW_ADD + stack, DIAG_TEMPERATURE_MEM_ADD) 333 | bus.close() 334 | return val 335 | 336 | 337 | # watchdog functions 338 | 339 | 340 | def wdtGetPeriod(stack): 341 | checkStack(stack) 342 | bus = smbus2.SMBus(BUS_NO) 343 | try: 344 | val = bus.read_word_data(HW_ADD + stack, I2C_MEM_WDT_INTERVAL_GET_ADD) 345 | except Exception as e: 346 | bus.close() 347 | raise ValueError(e) 348 | bus.close() 349 | return val 350 | 351 | 352 | def wdtSetPeriod(stack, val): 353 | ret = 1 354 | checkStack(stack) 355 | if val < 10 or val > 65000: 356 | raise ValueError('Invalid interval value [10..65000]') 357 | bus = smbus2.SMBus(BUS_NO) 358 | try: 359 | bus.write_word_data(HW_ADD + stack, I2C_MEM_WDT_INTERVAL_SET_ADD, val) 360 | except Exception as e: 361 | bus.close() 362 | raise ValueError(e) 363 | bus.close() 364 | return ret 365 | 366 | 367 | def wdtReload(stack): 368 | ret = 1 369 | checkStack(stack) 370 | bus = smbus2.SMBus(BUS_NO) 371 | try: 372 | bus.write_byte_data(HW_ADD + stack, I2C_MEM_WDT_RESET_ADD, RELOAD_KEY) 373 | except Exception as e: 374 | bus.close() 375 | raise ValueError(e) 376 | bus.close() 377 | return ret 378 | 379 | 380 | def wdtSetDefaultPeriod(stack, val): 381 | ret = 1 382 | checkStack(stack) 383 | if val < 10 or val > 64999: 384 | raise ValueError('Invalid interval value [10..64999]') 385 | bus = smbus2.SMBus(BUS_NO) 386 | if 10 < val < 65000: 387 | try: 388 | bus.write_word_data(HW_ADD + stack, I2C_MEM_WDT_INIT_INTERVAL_SET_ADD, val) 389 | except: 390 | bus.close() 391 | raise ValueError(e) 392 | else: 393 | ret = -1 394 | return ret 395 | 396 | 397 | def wdtGetDefaultPeriod(stack): 398 | checkStack(stack) 399 | bus = smbus2.SMBus(BUS_NO) 400 | try: 401 | val = bus.read_word_data(HW_ADD + stack, I2C_MEM_WDT_INIT_INTERVAL_GET_ADD) 402 | except Exception as e: 403 | bus.close() 404 | raise ValueError(e) 405 | return val 406 | 407 | 408 | def wdtSetOffInterval(stack, val): 409 | ret = 1 410 | checkStack(stack) 411 | if 10 > val or val > WDT_MAX_POWER_OFF_INTERVAL: 412 | raise ValueError('Invalid interval value [2..4147200]') 413 | bus = smbus2.SMBus(BUS_NO) 414 | buff = [0, 0, 0, 0] 415 | buff[0] = 0xff & val 416 | buff[1] = 0xff & (val >> 8) 417 | buff[2] = 0xff & (val >> 16) 418 | buff[3] = 0xff & (val >> 24) 419 | try: 420 | bus.write_i2c_block_data(HW_ADD + stack, I2C_MEM_WDT_POWER_OFF_INTERVAL_SET_ADD, buff) 421 | except Exception as e: 422 | bus.close() 423 | raise ValueError(e) 424 | bus.close() 425 | return ret 426 | 427 | 428 | def wdtGetOffInterval(stack): 429 | checkStack(stack) 430 | bus = smbus2.SMBus(BUS_NO) 431 | try: 432 | buff = bus.read_i2c_block_data(HW_ADD + stack, I2C_MEM_WDT_POWER_OFF_INTERVAL_GET_ADD, 4) 433 | val = buff[0] + (buff[1] << 8) + (buff[2] << 16) + (buff[3] << 24) 434 | except Exception as e: 435 | bus.close() 436 | raise ValueError(e) 437 | return val 438 | 439 | 440 | def wdtGetResetCount(stack): 441 | checkStack(stack) 442 | bus = smbus2.SMBus(BUS_NO) 443 | try: 444 | val = bus.read_word_data(HW_ADD + stack, I2C_MEM_WDT_RESET_COUNT_ADD) 445 | except Exception as e: 446 | bus.close() 447 | raise ValueError(e) 448 | return val 449 | 450 | 451 | I2C_RTC_YEAR_ADD = 70 452 | I2C_RTC_MONTH_ADD = 71 453 | I2C_RTC_DAY_ADD = 72 454 | I2C_RTC_HOUR_ADD = 73 455 | I2C_RTC_MINUTE_ADD = 74 456 | I2C_RTC_SECOND_ADD = 75 457 | I2C_RTC_SET_YEAR_ADD = 76 458 | I2C_RTC_SET_MONTH_ADD = 77 459 | I2C_RTC_SET_DAY_ADD = 78 460 | I2C_RTC_SET_HOUR_ADD = 79 461 | I2C_RTC_SET_MINUTE_ADD = 80 462 | I2C_RTC_SET_SECOND_ADD = 81 463 | I2C_RTC_CMD_ADD = 82 464 | 465 | 466 | def rtcGet(stack): 467 | global I2C_RTC_YEAR_ADD 468 | checkStack(stack) 469 | bus = smbus2.SMBus(BUS_NO) 470 | try: 471 | buff = bus.read_i2c_block_data(HW_ADD + stack, I2C_RTC_YEAR_ADD, 6) 472 | except Exception as e: 473 | bus.close() 474 | raise ValueError(e) 475 | bus.close() 476 | t = (2000 + buff[0], buff[1], buff[2], buff[3], buff[4], buff[5]) 477 | return t 478 | 479 | 480 | def rtcSet(stack, y, mo, d, h, m, s): 481 | if y > 2000: 482 | y -= 2000 483 | if y < 0 or y > 255: 484 | raise ValueError("Invalid year!") 485 | if mo > 12 or mo < 1: 486 | raise ValueError("Invalid month!") 487 | if d < 1 or d > 31: 488 | raise ValueError("Invalid day!") 489 | if h < 0 or h > 23: 490 | raise ValueError("Invalid hour!") 491 | if m < 0 or m > 59: 492 | raise ValueError("Invalid minute!") 493 | if s < 0 or s > 59: 494 | raise ValueError("Invalid seconds!") 495 | checkStack(stack) 496 | bus = smbus2.SMBus(BUS_NO) 497 | buff = [int(y), int(mo), int(d), int(h), int(m), int(s), 0xaa] 498 | try: 499 | bus.write_i2c_block_data(HW_ADD + stack, I2C_RTC_SET_YEAR_ADD, buff) 500 | except Exception as e: 501 | bus.close() 502 | raise ValueError(e) 503 | bus.close() 504 | 505 | 506 | I2C_MEM_1WB_DEV = 161 507 | I2C_MEM_1WB_TEMP_ALL = 162 508 | I2C_MEM_1WB_START_SEARCH = 173 509 | I2C_MEM_1WB_T1 = 174 510 | I2C_MEM_1WB_ROM_CODE_IDX = 206 511 | I2C_MEM_1WB_ROM_CODE = 207 512 | OWB_TEMP_SIZE_B = 2 513 | OWM_ROM_CODE_SIZE_B = 8 514 | 515 | def owbScan(stack): 516 | checkStack(stack) 517 | bus = smbus2.SMBus(BUS_NO) 518 | buf = 0xaa 519 | try: 520 | bus.write_byte_data(HW_ADD + stack, I2C_MEM_1WB_START_SEARCH, buf) 521 | except Exception as e: 522 | bus.close() 523 | raise Exception("Fail to write with exception " + str(e)) 524 | bus.close() 525 | 526 | 527 | def owbGetSensorNo(stack): 528 | checkStack(stack) 529 | bus = smbus2.SMBus(BUS_NO) 530 | try: 531 | no = bus.read_byte_data(HW_ADD + stack, I2C_MEM_1WB_DEV) 532 | except Exception as e: 533 | bus.close() 534 | raise Exception("Fail to read with exception " + str(e)) 535 | bus.close() 536 | return no 537 | 538 | 539 | def owbGetTemp(stack, sensor): 540 | checkOwbSns(sensor) 541 | checkStack(stack) 542 | bus = smbus2.SMBus(BUS_NO) 543 | try: 544 | temp = bus.read_word_data(HW_ADD + stack, I2C_MEM_1WB_T1 + OWB_TEMP_SIZE_B * (sensor - 1)) 545 | except Exception as e: 546 | bus.close() 547 | raise Exception("Fail to read with exception " + str(e)) 548 | bus.close() 549 | return temp / 100.0 550 | 551 | 552 | def owbGetRomCode(stack, sensor): 553 | checkOwbSns(sensor) 554 | checkStack(stack) 555 | bus = smbus2.SMBus(BUS_NO) 556 | try: 557 | bus.write_byte_data(HW_ADD + stack, I2C_MEM_1WB_ROM_CODE_IDX, sensor - 1) # Select the sensor 558 | buff = bus.read_i2c_block_data(HW_ADD + stack, I2C_MEM_1WB_ROM_CODE, 8) 559 | except Exception as e: 560 | bus.close() 561 | raise Exception("Fail to read with exception " + str(e)) 562 | bus.close() 563 | return buff 564 | -------------------------------------------------------------------------------- /python/res/sequent.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/python/res/sequent.jpg -------------------------------------------------------------------------------- /python/setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal=1 3 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | setuptools.setup( 4 | name='smmegabas', 5 | packages=setuptools.find_packages(), 6 | version='1.0.3', 7 | license='MIT', 8 | description='Library to control Sequent Microsystems megabas Card', 9 | author='Sequent Microsystems', 10 | author_email='olcitu@gmail.com', 11 | url='https://sequentmicrosystems.com', 12 | install_requires=[ 13 | "smbus2", 14 | ], 15 | #keywords=['industrial', 'raspberry', 'power', '4-20mA', '0-10V', 'optoisolated'], 16 | classifiers=[ 17 | 'Development Status :: 4 - Beta', 18 | # Chose either "3 - Alpha", "4 - Beta" or "5 - Production/Stable" as the current state of your package 19 | 'Intended Audience :: Developers', 20 | 'Topic :: Software Development :: Build Tools', 21 | 'License :: OSI Approved :: MIT License', 22 | 'Programming Language :: Python :: 2.7', 23 | 'Programming Language :: Python :: 3', 24 | 'Programming Language :: Python :: 3.4', 25 | 'Programming Language :: Python :: 3.5', 26 | 'Programming Language :: Python :: 3.6', 27 | 'Programming Language :: Python :: 3.7', 28 | ], 29 | ) 30 | -------------------------------------------------------------------------------- /python/tests/uoutin.py: -------------------------------------------------------------------------------- 1 | import megabas as m 2 | import time 3 | 4 | print('We assume 0-10V output channels are connected to 0-10V input channels ') 5 | for i in range(1,5): 6 | m.setUOut(0, 1, 0) 7 | time.sleep(0.3) 8 | 9 | for j in range(1, 5): 10 | print('0-10V output channel ' + str(j) + " to 0-10V input channel " + str(j)) 11 | for i in range(10): 12 | m.setUOut(0, j, i) 13 | time.sleep(0.1) 14 | print(m.getUOut(0, j), m.getUIn(0, j)) 15 | 16 | for i in range(1,5): 17 | m.setUOut(0, 1, 0) 18 | time.sleep(0.3) 19 | 20 | for j in range(1, 5): 21 | print('0-10V output channel ' + str(j) + " to 0-10V input channel " + str(j+4)) 22 | for i in range(10): 23 | m.setUOut(0, j, i) 24 | time.sleep(0.1) 25 | print(m.getUOut(0, j), m.getUIn(0, j+4)) -------------------------------------------------------------------------------- /res/megabas.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/res/megabas.jpg -------------------------------------------------------------------------------- /res/sequent.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/res/sequent.jpg -------------------------------------------------------------------------------- /src/comm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * comm.c: 3 | * Communication routines "platform specific" for Raspberry Pi 4 | * 5 | * Copyright (c) 2016-2020 Sequent Microsystem 6 | * 7 | *********************************************************************** 8 | * Author: Alexandru Burcea 9 | *********************************************************************** 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "comm.h" 19 | 20 | #define I2C_SLAVE 0x0703 21 | #define I2C_SMBUS 0x0720 /* SMBus-level access */ 22 | 23 | #define I2C_SMBUS_READ 1 24 | #define I2C_SMBUS_WRITE 0 25 | 26 | // SMBus transaction types 27 | 28 | #define I2C_SMBUS_QUICK 0 29 | #define I2C_SMBUS_BYTE 1 30 | #define I2C_SMBUS_BYTE_DATA 2 31 | #define I2C_SMBUS_WORD_DATA 3 32 | #define I2C_SMBUS_PROC_CALL 4 33 | #define I2C_SMBUS_BLOCK_DATA 5 34 | #define I2C_SMBUS_I2C_BLOCK_BROKEN 6 35 | #define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ 36 | #define I2C_SMBUS_I2C_BLOCK_DATA 8 37 | 38 | // SMBus messages 39 | 40 | #define I2C_SMBUS_BLOCK_MAX 512 /* As specified in SMBus standard */ 41 | #define I2C_SMBUS_I2C_BLOCK_MAX 512 /* Not specified but we use same structure */ 42 | 43 | 44 | int i2cSetup(int addr) 45 | { 46 | int file; 47 | char filename[40]; 48 | sprintf(filename, "/dev/i2c-1"); 49 | 50 | if ( (file = open(filename, O_RDWR)) < 0) 51 | { 52 | printf("Failed to open the bus."); 53 | return -1; 54 | } 55 | if (ioctl(file, I2C_SLAVE, addr) < 0) 56 | { 57 | printf("Failed to acquire bus access and/or talk to slave.\n"); 58 | return -1; 59 | } 60 | 61 | return file; 62 | } 63 | 64 | int i2cMem8Read(int dev, int add, uint8_t* buff, int size) 65 | { 66 | uint8_t intBuff[I2C_SMBUS_BLOCK_MAX]; 67 | 68 | if (NULL == buff) 69 | { 70 | return -1; 71 | } 72 | 73 | if (size > I2C_SMBUS_BLOCK_MAX) 74 | { 75 | return -1; 76 | } 77 | 78 | intBuff[0] = 0xff & add; 79 | 80 | if (write(dev, intBuff, 1) != 1) 81 | { 82 | //printf("Fail to select mem add!\n"); 83 | return -1; 84 | } 85 | if (read(dev, buff, size) != size) 86 | { 87 | //printf("Fail to read memory!\n"); 88 | return -1; 89 | } 90 | return 0; //OK 91 | } 92 | 93 | int i2cMem8Write(int dev, int add, uint8_t* buff, int size) 94 | { 95 | uint8_t intBuff[I2C_SMBUS_BLOCK_MAX]; 96 | 97 | if (NULL == buff) 98 | { 99 | return -1; 100 | } 101 | 102 | if (size > I2C_SMBUS_BLOCK_MAX - 1) 103 | { 104 | return -1; 105 | } 106 | 107 | intBuff[0] = 0xff & add; 108 | memcpy(&intBuff[1], buff, size); 109 | 110 | if (write(dev, intBuff, size + 1) != size + 1) 111 | { 112 | //printf("Fail to write memory!\n"); 113 | return -1; 114 | } 115 | return 0; 116 | } 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /src/comm.h: -------------------------------------------------------------------------------- 1 | #ifndef COMM_H_ 2 | #define COMM_H_ 3 | 4 | #include 5 | 6 | int i2cSetup(int addr); 7 | int i2cMem8Read(int dev, int add, uint8_t* buff, int size); 8 | int i2cMem8Write(int dev, int add, uint8_t* buff, int size); 9 | 10 | 11 | #endif //COMM_H_ -------------------------------------------------------------------------------- /src/megabas.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rtd.c: 3 | * Command-line interface to the Raspberry 4 | * Pi's MEGAS-RTD board. 5 | * Copyright (c) 2016-2023 Sequent Microsystem 6 | * 7 | *********************************************************************** 8 | * Author: Alexandru Burcea 9 | *********************************************************************** 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "megabas.h" 18 | #include "comm.h" 19 | #include "thread.h" 20 | 21 | #define VERSION_BASE (int)1 22 | #define VERSION_MAJOR (int)2 23 | #define VERSION_MINOR (int)7 24 | 25 | #define UNUSED(X) (void)X /* To avoid gcc/g++ warnings */ 26 | 27 | char *warranty = 28 | " Copyright (c) 2016-2023 Sequent Microsystems\n" 29 | " \n" 30 | " This program is free software; you can redistribute it and/or modify\n" 31 | " it under the terms of the GNU Leser General Public License as published\n" 32 | " by the Free Software Foundation, either version 3 of the License, or\n" 33 | " (at your option) any later version.\n" 34 | " \n" 35 | " This program is distributed in the hope that it will be useful,\n" 36 | " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 37 | " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 38 | " GNU Lesser General Public License for more details.\n" 39 | " \n" 40 | " You should have received a copy of the GNU Lesser General Public License\n" 41 | " along with this program. If not, see ."; 42 | 43 | void usage(void) 44 | { 45 | int i = 0; 46 | while (gCmdArray[i] != NULL) 47 | { 48 | if (gCmdArray[i]->name != NULL) 49 | { 50 | if (strlen(gCmdArray[i]->usage1) > 2) 51 | { 52 | printf("%s", gCmdArray[i]->usage1); 53 | } 54 | if (strlen(gCmdArray[i]->usage2) > 2) 55 | { 56 | printf("%s", gCmdArray[i]->usage2); 57 | } 58 | } 59 | i++; 60 | } 61 | printf("Where: = Board level id = 0..7\n"); 62 | printf("Type megabas -h for more help\n"); 63 | } 64 | 65 | int doBoardInit(int stack) 66 | { 67 | int dev = 0; 68 | int add = 0; 69 | uint8_t buff[8]; 70 | 71 | if ( (stack < 0) || (stack > 7)) 72 | { 73 | printf("Invalid stack level [0..7]!"); 74 | return ERROR; 75 | } 76 | add = stack + SLAVE_OWN_ADDRESS_BASE; 77 | dev = i2cSetup(add); 78 | if (dev == -1) 79 | { 80 | return ERROR; 81 | } 82 | if (ERROR == i2cMem8Read(dev, I2C_REVISION_MAJOR_MEM_ADD, buff, 1)) 83 | { 84 | printf("MEGA-BAS id %d not detected\n", stack); 85 | return ERROR; 86 | } 87 | return dev; 88 | } 89 | 90 | int boardCheck(int stack) 91 | { 92 | int dev = 0; 93 | int add = 0; 94 | uint8_t buff[8]; 95 | 96 | if ( (stack < 0) || (stack > 7)) 97 | { 98 | printf("Invalid stack level [0..7]!"); 99 | return ERROR; 100 | } 101 | add = stack + SLAVE_OWN_ADDRESS_BASE; 102 | dev = i2cSetup(add); 103 | if (dev == -1) 104 | { 105 | return ERROR; 106 | } 107 | if (ERROR == i2cMem8Read(dev, I2C_REVISION_MAJOR_MEM_ADD, buff, 1)) 108 | { 109 | 110 | return ERROR; 111 | } 112 | return OK; 113 | } 114 | int doHelp(int argc, char *argv[]); 115 | const CliCmdType CMD_HELP = 116 | {"-h", 1, &doHelp, 117 | "\t-h Display the list of command options or one command option details\n", 118 | "\tUsage: megabas -h Display command options list\n", 119 | "\tUsage: megabas -h Display help for command option\n", 120 | "\tExample: megabas -h rread Display help for \"rread\" command option\n"}; 121 | 122 | int doHelp(int argc, char *argv[]) 123 | { 124 | int i = 0; 125 | if (argc == 3) 126 | { 127 | while (NULL != gCmdArray[i]) 128 | { 129 | if (gCmdArray[i]->name != NULL) 130 | { 131 | if (strcasecmp(argv[2], gCmdArray[i]->name) == 0) 132 | { 133 | printf("%s%s%s%s", gCmdArray[i]->help, gCmdArray[i]->usage1, 134 | gCmdArray[i]->usage2, gCmdArray[i]->example); 135 | break; 136 | } 137 | } 138 | i++; 139 | } 140 | if (NULL == gCmdArray[i]) 141 | { 142 | printf("Option \"%s\" not found\n", argv[2]); 143 | i = 0; 144 | while (NULL != gCmdArray[i]) 145 | { 146 | if (gCmdArray[i]->name != NULL) 147 | { 148 | printf("%s", gCmdArray[i]->help); 149 | break; 150 | } 151 | i++; 152 | } 153 | } 154 | } 155 | else 156 | { 157 | i = 0; 158 | while (NULL != gCmdArray[i]) 159 | { 160 | if (gCmdArray[i]->name != NULL) 161 | { 162 | printf("%s", gCmdArray[i]->help); 163 | } 164 | i++; 165 | } 166 | } 167 | return OK; 168 | } 169 | 170 | int doVersion(int argc, char *argv[]); 171 | const CliCmdType CMD_VERSION = {"-v", 1, &doVersion, 172 | "\t-v Display the megabas command version number\n", 173 | "\tUsage: megabas -v\n", "", 174 | "\tExample: megabas -v Display the version number\n"}; 175 | 176 | int doVersion(int argc, char *argv[]) 177 | { 178 | UNUSED(argc); 179 | UNUSED(argv); 180 | printf("megabas v%d.%d.%d Copyright (c) 2016 - 2023 Sequent Microsystems\n", 181 | VERSION_BASE, VERSION_MAJOR, VERSION_MINOR); 182 | printf("\nThis is free software with ABSOLUTELY NO WARRANTY.\n"); 183 | printf("For details type: megabas -warranty\n"); 184 | return OK; 185 | } 186 | 187 | int doWarranty(int argc, char *argv[]); 188 | const CliCmdType CMD_WAR = {"-warranty", 1, &doWarranty, 189 | "\t-warranty Display the warranty\n", "\tUsage: megabas -warranty\n", "", 190 | "\tExample: megabas -warranty Display the warranty text\n"}; 191 | 192 | int doWarranty(int argc UNU, char* argv[] UNU) 193 | { 194 | printf("%s\n", warranty); 195 | return OK; 196 | } 197 | 198 | int doList(int argc, char *argv[]); 199 | const CliCmdType CMD_LIST = 200 | {"-list", 1, &doList, 201 | "\t-list: List all megabas boards connected\n\t\t\treturn the # of boards and stack level for every board\n", 202 | "\tUsage: megabas -list\n", "", 203 | "\tExample: megabas -list display: 1,0 \n"}; 204 | 205 | int doList(int argc, char *argv[]) 206 | { 207 | int ids[8]; 208 | int i; 209 | int cnt = 0; 210 | 211 | UNUSED(argc); 212 | UNUSED(argv); 213 | 214 | for (i = 0; i < 8; i++) 215 | { 216 | if (boardCheck(i) == OK) 217 | { 218 | ids[cnt] = i; 219 | cnt++; 220 | } 221 | } 222 | printf("%d board(s) detected\n", cnt); 223 | if (cnt > 0) 224 | { 225 | printf("Id:"); 226 | } 227 | while (cnt > 0) 228 | { 229 | cnt--; 230 | printf(" %d", ids[cnt]); 231 | } 232 | printf("\n"); 233 | return OK; 234 | } 235 | 236 | int doBoard(int argc, char *argv[]); 237 | const CliCmdType CMD_BOARD = {"board", 2, &doBoard, 238 | "\tboard Display the board status and firmware version number\n", 239 | "\tUsage: megabas board\n", "", 240 | "\tExample: megabas 0 board Display vcc, temperature, firmware version \n"}; 241 | 242 | int doBoard(int argc, char *argv[]) 243 | { 244 | int dev = -1; 245 | u8 buff[5]; 246 | int resp = 0; 247 | int temperature = 25; 248 | float vIn = 24; 249 | float vRasp = 5; 250 | 251 | if (argc != 3) 252 | { 253 | printf("Invalid arguments number type \"megabas -h\" for details\n"); 254 | exit(1); 255 | } 256 | dev = doBoardInit(atoi(argv[1])); 257 | if (dev <= 0) 258 | { 259 | exit(1); 260 | } 261 | resp = i2cMem8Read(dev, I2C_DIAG_TEMPERATURE_MEM_ADD, buff, 5); 262 | if (FAIL == resp) 263 | { 264 | printf("Fail to read board info!\n"); 265 | exit(1); 266 | } 267 | temperature = buff[0]; 268 | memcpy(&resp, &buff[1], 2); 269 | vIn = (float)resp / 1000; //read in milivolts 270 | 271 | memcpy(&resp, &buff[3], 2); 272 | vRasp = (float)resp / 1000; //read in milivolts 273 | 274 | resp = i2cMem8Read(dev, I2C_REVISION_MAJOR_MEM_ADD, buff, 2); 275 | if (FAIL == resp) 276 | { 277 | printf("Fail to read board info!\n"); 278 | exit(1); 279 | } 280 | printf( 281 | "Firmware ver %02d.%02d, CPU temperature %d C, Power source %0.2f V, Raspberry %0.2f V\n", 282 | (int)buff[0], (int)buff[1], temperature, vIn, vRasp); 283 | return OK; 284 | } 285 | 286 | int doReset(int argc, char *argv[]); 287 | const CliCmdType CMD_RESET = {"reset", 2, &doReset, 288 | "\treset reset the Microcontroller on the card\n", 289 | "\tUsage: megabas reset\n", "", 290 | "\tExample: megabas 0 reset \n"}; 291 | 292 | int doReset(int argc, char *argv[]) 293 | { 294 | int dev = -1; 295 | u8 buff[5]; 296 | int resp = 0; 297 | 298 | if (argc != 3) 299 | { 300 | printf("Invalid arguments number type \"megabas -h\" for details\n"); 301 | exit(1); 302 | } 303 | dev = doBoardInit(atoi(argv[1])); 304 | if (dev <= 0) 305 | { 306 | exit(1); 307 | } 308 | resp = i2cMem8Write(dev, 0xaa, buff, 1); 309 | if (FAIL == resp) 310 | { 311 | printf("Fail to reset the board!\n"); 312 | exit(1); 313 | } 314 | printf("RESET...\n"); 315 | return OK; 316 | } 317 | 318 | int triacChSet(int dev, u8 channel, OutStateEnumType state) 319 | { 320 | int resp = 0; 321 | u8 buff[2]; 322 | 323 | if ( (channel < CHANNEL_NR_MIN) || (channel > TRIAC_CH_NR_MAX)) 324 | { 325 | printf("Invalid triac nr!\n"); 326 | return ERROR; 327 | } 328 | if (FAIL == i2cMem8Read(dev, I2C_TRIACS_VAL_ADD, buff, 1)) 329 | { 330 | return FAIL; 331 | } 332 | 333 | switch (state) 334 | { 335 | case OFF: 336 | buff[0] &= ~ (1 << (channel - 1)); 337 | resp = i2cMem8Write(dev, I2C_TRIACS_VAL_ADD, buff, 1); 338 | break; 339 | case ON: 340 | buff[0] |= 1 << (channel - 1); 341 | resp = i2cMem8Write(dev, I2C_TRIACS_VAL_ADD, buff, 1); 342 | break; 343 | default: 344 | printf("Invalid triac state!\n"); 345 | return ERROR; 346 | break; 347 | } 348 | return resp; 349 | } 350 | 351 | int triacChGet(int dev, u8 channel, OutStateEnumType *state) 352 | { 353 | u8 buff[2]; 354 | 355 | if (NULL == state) 356 | { 357 | return ERROR; 358 | } 359 | 360 | if ( (channel < CHANNEL_NR_MIN) || (channel > TRIAC_CH_NR_MAX)) 361 | { 362 | printf("Invalid triac nr!\n"); 363 | return ERROR; 364 | } 365 | 366 | if (FAIL == i2cMem8Read(dev, I2C_TRIACS_VAL_ADD, buff, 1)) 367 | { 368 | return ERROR; 369 | } 370 | 371 | if (buff[0] & (1 << (channel - 1))) 372 | { 373 | *state = ON; 374 | } 375 | else 376 | { 377 | *state = OFF; 378 | } 379 | return OK; 380 | } 381 | 382 | int triacSet(int dev, int val) 383 | { 384 | u8 buff[2]; 385 | 386 | buff[0] = 0x0f & val; 387 | 388 | return i2cMem8Write(dev, I2C_TRIACS_VAL_ADD, buff, 1); 389 | } 390 | 391 | int triacGet(int dev, int *val) 392 | { 393 | u8 buff[2]; 394 | 395 | if (NULL == val) 396 | { 397 | return ERROR; 398 | } 399 | if (FAIL == i2cMem8Read(dev, I2C_TRIACS_VAL_ADD, buff, 1)) 400 | { 401 | return ERROR; 402 | } 403 | *val = buff[0]; 404 | return OK; 405 | } 406 | 407 | int doTriacWrite(int argc, char *argv[]); 408 | const CliCmdType CMD_TRIAC_WRITE = {"trwr", 2, &doTriacWrite, 409 | "\ttrwr: Set triacs (AC switch) On/Off\n", 410 | "\tUsage: megabas trwr \n", 411 | "\tUsage: megabas trwr \n", 412 | "\tExample: megabas 0 trwr 2 1; Set Triac #2 on Board #0 On\n"}; 413 | 414 | int doTriacWrite(int argc, char *argv[]) 415 | { 416 | int pin = 0; 417 | OutStateEnumType state = STATE_COUNT; 418 | int val = 0; 419 | int dev = 0; 420 | OutStateEnumType stateR = STATE_COUNT; 421 | int valR = 0; 422 | int retry = 0; 423 | 424 | if ( (argc != 5) && (argc != 4)) 425 | { 426 | printf("%s", CMD_TRIAC_WRITE.usage1); 427 | printf("%s", CMD_TRIAC_WRITE.usage2); 428 | exit(1); 429 | } 430 | 431 | dev = doBoardInit(atoi(argv[1])); 432 | if (dev <= 0) 433 | { 434 | exit(1); 435 | } 436 | if (argc == 5) 437 | { 438 | pin = atoi(argv[3]); 439 | if ( (pin < CHANNEL_NR_MIN) || (pin > TRIAC_CH_NR_MAX)) 440 | { 441 | printf("Triac channel number value out of range\n"); 442 | exit(1); 443 | } 444 | 445 | /**/if ( (strcasecmp(argv[4], "up") == 0) 446 | || (strcasecmp(argv[4], "on") == 0)) 447 | state = ON; 448 | else if ( (strcasecmp(argv[4], "down") == 0) 449 | || (strcasecmp(argv[4], "off") == 0)) 450 | state = OFF; 451 | else 452 | { 453 | if ( (atoi(argv[4]) >= STATE_COUNT) || (atoi(argv[4]) < 0)) 454 | { 455 | printf("Invalid triac state!\n"); 456 | exit(1); 457 | } 458 | state = (OutStateEnumType)atoi(argv[4]); 459 | } 460 | 461 | retry = RETRY_TIMES; 462 | 463 | while ( (retry > 0) && (stateR != state)) 464 | { 465 | if (OK != triacChSet(dev, pin, state)) 466 | { 467 | printf("Fail to write triac\n"); 468 | exit(1); 469 | } 470 | if (OK != triacChGet(dev, pin, &stateR)) 471 | { 472 | printf("Fail to read triac\n"); 473 | exit(1); 474 | } 475 | retry--; 476 | } 477 | #ifdef DEBUG_I 478 | if(retry < RETRY_TIMES) 479 | { 480 | printf("retry %d times\n", 3-retry); 481 | } 482 | #endif 483 | if (retry == 0) 484 | { 485 | printf("Fail to write triac\n"); 486 | exit(1); 487 | } 488 | } 489 | else 490 | { 491 | val = atoi(argv[3]); 492 | if (val < 0 || val > 0x0f) 493 | { 494 | printf("Invalid triac value\n"); 495 | exit(1); 496 | } 497 | 498 | retry = RETRY_TIMES; 499 | valR = -1; 500 | while ( (retry > 0) && (valR != val)) 501 | { 502 | 503 | if (OK != triacSet(dev, val)) 504 | { 505 | printf("Fail to write triac!\n"); 506 | exit(1); 507 | } 508 | if (OK != triacGet(dev, &valR)) 509 | { 510 | printf("Fail to read triac!\n"); 511 | exit(1); 512 | } 513 | } 514 | if (retry == 0) 515 | { 516 | printf("Fail to write triac!\n"); 517 | exit(1); 518 | } 519 | } 520 | return OK; 521 | } 522 | 523 | int doTriacRead(int argc, char *argv[]); 524 | const CliCmdType CMD_TRIAC_READ = {"trrd", 2, &doTriacRead, 525 | "\ttrrd: Read triacs (AC switch) status\n", 526 | "\tUsage: megabas trrd \n", "\tUsage: megabas trrd\n", 527 | "\tExample: megabas 0 trrd 2; Read Status of Triac #2 on Board #0\n"}; 528 | 529 | int doTriacRead(int argc, char *argv[]) 530 | { 531 | int pin = 0; 532 | int val = 0; 533 | int dev = 0; 534 | OutStateEnumType state = STATE_COUNT; 535 | 536 | dev = doBoardInit(atoi(argv[1])); 537 | if (dev <= 0) 538 | { 539 | exit(1); 540 | } 541 | 542 | if (argc == 4) 543 | { 544 | pin = atoi(argv[3]); 545 | if ( (pin < CHANNEL_NR_MIN) || (pin > TRIAC_CH_NR_MAX)) 546 | { 547 | printf("Triac channel number value out of range!\n"); 548 | exit(1); 549 | } 550 | 551 | if (OK != triacChGet(dev, pin, &state)) 552 | { 553 | printf("Fail to read!\n"); 554 | exit(1); 555 | } 556 | if (state != 0) 557 | { 558 | printf("1\n"); 559 | } 560 | else 561 | { 562 | printf("0\n"); 563 | } 564 | } 565 | else if (argc == 3) 566 | { 567 | if (OK != triacGet(dev, &val)) 568 | { 569 | printf("Fail to read!\n"); 570 | exit(1); 571 | } 572 | printf("%d\n", val); 573 | } 574 | else 575 | { 576 | printf("%s", CMD_TRIAC_READ.usage1); 577 | printf("%s", CMD_TRIAC_READ.usage2); 578 | exit(1); 579 | } 580 | return OK; 581 | } 582 | 583 | int doTriacTest(int argc, char *argv[]); 584 | const CliCmdType CMD_TEST = {"trtest", 2, &doTriacTest, 585 | "\ttrtest: Turn ON and OFF the triacs until press a key\n", 586 | "\tUsage: megabas trtest\n", "", "\tExample: megabas 0 trtest\n"}; 587 | 588 | int doTriacTest(int argc, char *argv[]) 589 | { 590 | int dev = 0; 591 | int i = 0; 592 | int retry = 0; 593 | int trVal; 594 | int valR; 595 | int triacResult = 0; 596 | FILE *file = NULL; 597 | const u8 triacOrder[4] = {1, 2, 3, 4, }; 598 | 599 | dev = doBoardInit(atoi(argv[1])); 600 | if (dev <= 0) 601 | { 602 | exit(1); 603 | } 604 | if (argc == 4) 605 | { 606 | file = fopen(argv[3], "w"); 607 | if (!file) 608 | { 609 | printf("Fail to open result file\n"); 610 | //return -1; 611 | } 612 | } 613 | //triac test**************************** 614 | if (strcasecmp(argv[2], "trtest") == 0) 615 | { 616 | trVal = 0; 617 | printf( 618 | "Are all triacs and LEDs turning on and off in sequence?\nPress y for Yes or any key for No...."); 619 | startThread(); 620 | while (triacResult == 0) 621 | { 622 | for (i = 0; i < 4; i++) 623 | { 624 | triacResult = checkThreadResult(); 625 | if (triacResult != 0) 626 | { 627 | break; 628 | } 629 | valR = 0; 630 | trVal = (u8)1 << (triacOrder[i] - 1); 631 | 632 | retry = RETRY_TIMES; 633 | while ( (retry > 0) && ( (valR & trVal) == 0)) 634 | { 635 | if (OK != triacChSet(dev, triacOrder[i], ON)) 636 | { 637 | retry = 0; 638 | break; 639 | } 640 | 641 | if (OK != triacGet(dev, &valR)) 642 | { 643 | retry = 0; 644 | } 645 | } 646 | if (retry == 0) 647 | { 648 | printf("Fail to write triac\n"); 649 | if (file) 650 | fclose(file); 651 | exit(1); 652 | } 653 | busyWait(150); 654 | } 655 | 656 | for (i = 0; i < 4; i++) 657 | { 658 | triacResult = checkThreadResult(); 659 | if (triacResult != 0) 660 | { 661 | break; 662 | } 663 | valR = 0xff; 664 | trVal = (u8)1 << (triacOrder[i] - 1); 665 | retry = RETRY_TIMES; 666 | while ( (retry > 0) && ( (valR & trVal) != 0)) 667 | { 668 | if (OK != triacChSet(dev, triacOrder[i], OFF)) 669 | { 670 | retry = 0; 671 | } 672 | if (OK != triacGet(dev, &valR)) 673 | { 674 | retry = 0; 675 | } 676 | } 677 | if (retry == 0) 678 | { 679 | printf("Fail to write triac!\n"); 680 | if (file) 681 | fclose(file); 682 | exit(1); 683 | } 684 | busyWait(150); 685 | } 686 | } 687 | } 688 | else 689 | { 690 | usage(); 691 | exit(1); 692 | } 693 | if (triacResult == YES) 694 | { 695 | if (file) 696 | { 697 | fprintf(file, "Triac Test ............................ PASS\n"); 698 | } 699 | else 700 | { 701 | printf("Triac Test ............................ PASS\n"); 702 | } 703 | } 704 | else 705 | { 706 | if (file) 707 | { 708 | fprintf(file, "Triac Test ............................ FAIL!\n"); 709 | } 710 | else 711 | { 712 | printf("Triac Test ............................ FAIL!\n"); 713 | } 714 | } 715 | if (file) 716 | { 717 | fclose(file); 718 | } 719 | triacSet(dev, 0); 720 | return OK; 721 | } 722 | 723 | int contactChGet(int dev, u8 channel, OutStateEnumType *state) 724 | { 725 | u8 buff[2]; 726 | 727 | if (NULL == state) 728 | { 729 | return ERROR; 730 | } 731 | 732 | if ( (channel < CHANNEL_NR_MIN) || (channel > CONTACT_CH_NR_MAX)) 733 | { 734 | printf("Invalid DRY CONTACT nr!\n"); 735 | return ERROR; 736 | } 737 | 738 | if (FAIL == i2cMem8Read(dev, I2C_DRY_CONTACT_VAL_ADD, buff, 1)) 739 | { 740 | return ERROR; 741 | } 742 | 743 | if (buff[0] & (1 << (channel - 1))) 744 | { 745 | *state = ON; 746 | } 747 | else 748 | { 749 | *state = OFF; 750 | } 751 | return OK; 752 | } 753 | 754 | int contactGet(int dev, int *val) 755 | { 756 | u8 buff[2]; 757 | 758 | if (NULL == val) 759 | { 760 | return ERROR; 761 | } 762 | if (FAIL == i2cMem8Read(dev, I2C_DRY_CONTACT_VAL_ADD, buff, 1)) 763 | { 764 | return ERROR; 765 | } 766 | *val = buff[0]; 767 | return OK; 768 | } 769 | 770 | int contactCountGet(int dev, u8 ch, u32 *val) 771 | { 772 | u8 buff[4]; 773 | 774 | if (NULL == val) 775 | { 776 | return ERROR; 777 | } 778 | if ( (ch < CHANNEL_NR_MIN) || (ch > CONTACT_CH_NR_MAX)) 779 | { 780 | printf("Invalid DRY CONTACT nr!\n"); 781 | return ERROR; 782 | } 783 | if (FAIL 784 | == i2cMem8Read(dev, I2C_MEM_DRY_CONTACT_CONTORS + 4 * (ch - 1), buff, 4)) 785 | { 786 | return ERROR; 787 | } 788 | memcpy(val, buff, 4); 789 | return OK; 790 | } 791 | 792 | int contactCountReset(int dev, u8 channel) 793 | { 794 | u8 buff[4]; 795 | 796 | if ( (channel < CHANNEL_NR_MIN) || (channel > CONTACT_CH_NR_MAX)) 797 | { 798 | printf("Invalid DRY CONTACT nr!\n"); 799 | return ERROR; 800 | } 801 | buff[0] = channel; 802 | if (FAIL == i2cMem8Write(dev, I2C_MEM_DRY_CONTACT_CH_CONT_RESET, buff, 1)) 803 | { 804 | printf("Fail to reset contor! \n"); 805 | return ERROR; 806 | } 807 | return OK; 808 | } 809 | 810 | int contactCountRisingSet(int dev, u8 channel, u8 state) 811 | { 812 | u8 buff[4]; 813 | 814 | if ( (channel < CHANNEL_NR_MIN) || (channel > CONTACT_CH_NR_MAX)) 815 | { 816 | printf("Invalid DRY CONTACT nr!\n"); 817 | return ERROR; 818 | } 819 | 820 | if (FAIL == i2cMem8Read(dev, I2C_MEM_DRY_CONTACT_RISING_ENABLE, buff, 1)) 821 | { 822 | return ERROR; 823 | } 824 | if (state != 0) 825 | { 826 | buff[0] |= 1 << (channel - 1); 827 | } 828 | else 829 | { 830 | buff[0] &= ~ (1 << (channel - 1)); 831 | } 832 | if (FAIL == i2cMem8Write(dev, I2C_MEM_DRY_CONTACT_RISING_ENABLE, buff, 1)) 833 | { 834 | return ERROR; 835 | } 836 | return OK; 837 | } 838 | 839 | int contactCountFallingSet(int dev, u8 channel, u8 state) 840 | { 841 | u8 buff[4]; 842 | 843 | if ( (channel < CHANNEL_NR_MIN) || (channel > CONTACT_CH_NR_MAX)) 844 | { 845 | printf("Invalid DRY CONTACT nr!\n"); 846 | return ERROR; 847 | } 848 | 849 | if (FAIL == i2cMem8Read(dev, I2C_MEM_DRY_CONTACT_FALLING_ENABLE, buff, 1)) 850 | { 851 | return ERROR; 852 | } 853 | if (state != 0) 854 | { 855 | buff[0] |= 1 << (channel - 1); 856 | } 857 | else 858 | { 859 | buff[0] &= ~ (1 << (channel - 1)); 860 | } 861 | if (FAIL == i2cMem8Write(dev, I2C_MEM_DRY_CONTACT_FALLING_ENABLE, buff, 1)) 862 | { 863 | return ERROR; 864 | } 865 | return OK; 866 | } 867 | 868 | int contactCountRisingGet(int dev, u8 channel, u8 *state) 869 | { 870 | u8 buff[4]; 871 | 872 | if (NULL == state) 873 | { 874 | return ERROR; 875 | } 876 | if ( (channel < CHANNEL_NR_MIN) || (channel > CONTACT_CH_NR_MAX)) 877 | { 878 | printf("Invalid DRY CONTACT nr!\n"); 879 | return ERROR; 880 | } 881 | 882 | if (FAIL == i2cMem8Read(dev, I2C_MEM_DRY_CONTACT_RISING_ENABLE, buff, 1)) 883 | { 884 | return ERROR; 885 | } 886 | if ( (buff[0] & (1 << (channel - 1))) != 0) 887 | { 888 | *state = 1; 889 | } 890 | else 891 | { 892 | *state = 0; 893 | } 894 | return OK; 895 | } 896 | 897 | int contactCountFallingGet(int dev, u8 channel, u8 *state) 898 | { 899 | u8 buff[4]; 900 | 901 | if (NULL == state) 902 | { 903 | return ERROR; 904 | } 905 | if ( (channel < CHANNEL_NR_MIN) || (channel > CONTACT_CH_NR_MAX)) 906 | { 907 | printf("Invalid DRY CONTACT nr!\n"); 908 | return ERROR; 909 | } 910 | 911 | if (FAIL == i2cMem8Read(dev, I2C_MEM_DRY_CONTACT_FALLING_ENABLE, buff, 1)) 912 | { 913 | return ERROR; 914 | } 915 | if ( (buff[0] & (1 << (channel - 1))) != 0) 916 | { 917 | *state = 1; 918 | } 919 | else 920 | { 921 | *state = 0; 922 | } 923 | return OK; 924 | } 925 | 926 | int doContactRead(int argc, char *argv[]); 927 | const CliCmdType CMD_CONTACT_READ = 928 | {"contactrd", 2, &doContactRead, 929 | "\tcontactrd: Read dry contact status\n\t\t\tWarning: For this measurements to be valid place the jumper in position \"1K\" \n", 930 | "\tUsage: megabas contactrd \n", 931 | "\tUsage: megabas contactrd\n", 932 | "\tExample: megabas 0 contactrd 2; Read Status of Dry contact pin #2 on Board #0\n"}; 933 | 934 | int doContactRead(int argc, char *argv[]) 935 | { 936 | int pin = 0; 937 | int val = 0; 938 | int dev = 0; 939 | OutStateEnumType state = STATE_COUNT; 940 | 941 | dev = doBoardInit(atoi(argv[1])); 942 | if (dev <= 0) 943 | { 944 | exit(1); 945 | } 946 | 947 | if (argc == 4) 948 | { 949 | pin = atoi(argv[3]); 950 | if ( (pin < CHANNEL_NR_MIN) || (pin > CONTACT_CH_NR_MAX)) 951 | { 952 | printf("Dry contact number value out of range!\n"); 953 | exit(1); 954 | } 955 | 956 | if (OK != contactChGet(dev, pin, &state)) 957 | { 958 | printf("Fail to read!\n"); 959 | exit(1); 960 | } 961 | if (state != 0) 962 | { 963 | printf("1\n"); 964 | } 965 | else 966 | { 967 | printf("0\n"); 968 | } 969 | } 970 | else if (argc == 3) 971 | { 972 | if (OK != contactGet(dev, &val)) 973 | { 974 | printf("Fail to read!\n"); 975 | exit(1); 976 | } 977 | printf("%d\n", val); 978 | } 979 | else 980 | { 981 | printf("%s", CMD_CONTACT_READ.usage1); 982 | printf("%s", CMD_CONTACT_READ.usage2); 983 | exit(1); 984 | } 985 | return OK; 986 | } 987 | 988 | int doCountRead(int argc, char *argv[]); 989 | const CliCmdType CMD_COUNTER_READ = 990 | {"countrd", 2, &doCountRead, 991 | "\tcountrd: Read dry contact transitions count\n\t\t\tWarning: For this measurements to be valid place the jumper in position \"1K\" \n", 992 | "\tUsage: megabas countrd \n", "", 993 | "\tExample: megabas 0 countrd 2; Read transitions count of dry contact pin #2 on Board #0\n"}; 994 | 995 | int doCountRead(int argc, char *argv[]) 996 | { 997 | u8 pin = 0; 998 | u32 val = 0; 999 | int dev = 0; 1000 | 1001 | dev = doBoardInit(atoi(argv[1])); 1002 | if (dev <= 0) 1003 | { 1004 | exit(1); 1005 | } 1006 | 1007 | if (argc == 4) 1008 | { 1009 | pin = (u8)atoi(argv[3]); 1010 | 1011 | if (OK != contactCountGet(dev, pin, &val)) 1012 | { 1013 | printf("Fail to read!\n"); 1014 | exit(1); 1015 | } 1016 | printf("%u\n", (unsigned int)val); 1017 | } 1018 | else 1019 | { 1020 | printf("%s", CMD_COUNTER_READ.usage1); 1021 | exit(1); 1022 | } 1023 | return OK; 1024 | } 1025 | 1026 | int doCountReset(int argc, char *argv[]); 1027 | const CliCmdType CMD_COUNTER_RST = 1028 | {"countrst", 2, &doCountReset, 1029 | "\tcountrst: Reset dry contact transitions count\n", 1030 | "\tUsage: megabas countrst \n", "", 1031 | "\tExample: megabas 0 countrst 2; Reset transitions count of dry contact pin #2 on Board #0\n"}; 1032 | 1033 | int doCountReset(int argc, char *argv[]) 1034 | { 1035 | u8 pin = 0; 1036 | int dev = 0; 1037 | 1038 | dev = doBoardInit(atoi(argv[1])); 1039 | if (dev <= 0) 1040 | { 1041 | exit(1); 1042 | } 1043 | 1044 | if (argc == 4) 1045 | { 1046 | pin = (u8)atoi(argv[3]); 1047 | 1048 | if (OK != contactCountReset(dev, pin)) 1049 | { 1050 | printf("Fail to read!\n"); 1051 | exit(1); 1052 | } 1053 | printf("done\n"); 1054 | } 1055 | else 1056 | { 1057 | printf("%s", CMD_COUNTER_RST.usage1); 1058 | exit(1); 1059 | } 1060 | return OK; 1061 | } 1062 | 1063 | int doEdgeRead(int argc, char *argv[]); 1064 | const CliCmdType CMD_EDGE_READ = 1065 | {"edgerd", 2, &doEdgeRead, 1066 | "\tedgerd: Read dry contact transitions type, ret 0 - disable, 1 - rising, 2 - falling, 3 - both\n", 1067 | "\tUsage: megabas edgerd \n", "", 1068 | "\tExample: megabas 0 edgerd 2; Read transitions type of dry contact pin #2 on Board #0\n"}; 1069 | 1070 | int doEdgeRead(int argc, char *argv[]) 1071 | { 1072 | u8 pin = 0; 1073 | u8 rising = 0; 1074 | u8 falling = 0; 1075 | int dev = 0; 1076 | 1077 | dev = doBoardInit(atoi(argv[1])); 1078 | if (dev <= 0) 1079 | { 1080 | exit(1); 1081 | } 1082 | 1083 | if (argc == 4) 1084 | { 1085 | pin = (u8)atoi(argv[3]); 1086 | 1087 | if (OK != contactCountRisingGet(dev, pin, &rising)) 1088 | { 1089 | printf("Fail to read!\n"); 1090 | exit(1); 1091 | } 1092 | if (OK != contactCountFallingGet(dev, pin, &falling)) 1093 | { 1094 | printf("Fail to read!\n"); 1095 | exit(1); 1096 | } 1097 | printf("%d\n", (int) (rising + falling * 2)); 1098 | } 1099 | else 1100 | { 1101 | printf("%s", CMD_EDGE_READ.usage1); 1102 | exit(1); 1103 | } 1104 | return OK; 1105 | } 1106 | 1107 | int doEdgeWrite(int argc, char *argv[]); 1108 | const CliCmdType CMD_EDGE_WRITE = 1109 | {"edgewr", 2, &doEdgeWrite, 1110 | "\tedgewr: Write dry contact transitions type: 0 - disable, 1 - rising, 2 - falling, 3 - both\n", 1111 | "\tUsage: megabas edgewr \n", "", 1112 | "\tExample: megabas 0 edgewr 2 1; Set transitions type of dry contact pin #2 on Board #0 to rising\n"}; 1113 | 1114 | int doEdgeWrite(int argc, char *argv[]) 1115 | { 1116 | u8 pin = 0; 1117 | u8 rising = 0; 1118 | u8 falling = 0; 1119 | int dev = 0; 1120 | 1121 | dev = doBoardInit(atoi(argv[1])); 1122 | if (dev <= 0) 1123 | { 1124 | exit(1); 1125 | } 1126 | 1127 | if (argc == 5) 1128 | { 1129 | pin = (u8)atoi(argv[3]); 1130 | 1131 | if ( (1 & atoi(argv[4])) != 0) 1132 | { 1133 | rising = 1; 1134 | } 1135 | if ( (2 & atoi(argv[4])) != 0) 1136 | { 1137 | falling = 1; 1138 | } 1139 | if (OK != contactCountRisingSet(dev, pin, rising)) 1140 | { 1141 | printf("Fail to write!\n"); 1142 | exit(1); 1143 | } 1144 | if (OK != contactCountFallingSet(dev, pin, falling)) 1145 | { 1146 | printf("Fail to write!\n"); 1147 | exit(1); 1148 | } 1149 | 1150 | } 1151 | else 1152 | { 1153 | printf("%s", CMD_EDGE_WRITE.usage1); 1154 | exit(1); 1155 | } 1156 | return OK; 1157 | } 1158 | 1159 | int buttonIntCfgSet(int dev, u8 state) 1160 | { 1161 | u8 buff[4]; 1162 | 1163 | if (state > 1) 1164 | { 1165 | state = 1; 1166 | } 1167 | buff[0] = state; 1168 | if (FAIL == i2cMem8Write(dev, I2C_EXT_INT_OUT_ENABLE, buff, 1)) 1169 | { 1170 | return ERROR; 1171 | } 1172 | return OK; 1173 | } 1174 | 1175 | int buttonIntCfgGet(int dev, u8 *state) 1176 | { 1177 | u8 buff[2]; 1178 | 1179 | if (state == NULL) 1180 | { 1181 | return ERROR; 1182 | } 1183 | if (FAIL == i2cMem8Read(dev, I2C_EXT_INT_OUT_ENABLE, buff, 1)) 1184 | { 1185 | return ERROR; 1186 | } 1187 | *state = buff[0]; 1188 | return OK; 1189 | } 1190 | 1191 | int buttonGetState(int dev, u8 *state) 1192 | { 1193 | u8 buff[2]; 1194 | 1195 | if (state == NULL) 1196 | { 1197 | return ERROR; 1198 | } 1199 | if (FAIL == i2cMem8Read(dev, I2C_BUTTON_STATE, buff, 1)) 1200 | { 1201 | return ERROR; 1202 | } 1203 | *state = buff[0]; 1204 | return OK; 1205 | } 1206 | 1207 | int doExtiCfgRead(int argc, char *argv[]); 1208 | const CliCmdType CMD_EXTI_READ = 1209 | {"exticfgrd", 2, &doExtiCfgRead, 1210 | "\texticfgrd: Read the external interrupt output enable flag, returns 0 = disabled, 1 = enabled \n", 1211 | "\tUsage: megabas exticfgrd \n", "", 1212 | "\tExample: megabas 0 exticfgrd ; Read the interrupt output enable flag on Board #0\n"}; 1213 | 1214 | int doExtiCfgRead(int argc, char *argv[]) 1215 | { 1216 | u8 val = 0; 1217 | int dev = 0; 1218 | 1219 | dev = doBoardInit(atoi(argv[1])); 1220 | if (dev <= 0) 1221 | { 1222 | exit(1); 1223 | } 1224 | 1225 | if (argc == 3) 1226 | { 1227 | 1228 | if (OK != buttonIntCfgGet(dev, &val)) 1229 | { 1230 | printf("Fail to read!\n"); 1231 | exit(1); 1232 | } 1233 | printf("%d\n", (int)val); 1234 | } 1235 | else 1236 | { 1237 | printf("%s", CMD_EXTI_READ.usage1); 1238 | exit(1); 1239 | } 1240 | return OK; 1241 | } 1242 | 1243 | int doExtiCfgWrite(int argc, char *argv[]); 1244 | const CliCmdType CMD_EXTI_WRITE = 1245 | {"exticfgwr", 2, &doExtiCfgWrite, 1246 | "\texticfgwr: Write the external interrupt output enable flag \n", 1247 | "\tUsage: megabas exticfgwr <0/1> \n", "", 1248 | "\tExample: megabas 0 exticfgwr 1; Enable the interrupt output on Board #0\n"}; 1249 | 1250 | int doExtiCfgWrite(int argc, char *argv[]) 1251 | { 1252 | int dev = 0; 1253 | u8 state = 0; 1254 | 1255 | dev = doBoardInit(atoi(argv[1])); 1256 | if (dev <= 0) 1257 | { 1258 | exit(1); 1259 | } 1260 | 1261 | if (argc == 4) 1262 | { 1263 | state = (u8)atoi(argv[3]); 1264 | 1265 | if (OK != buttonIntCfgSet(dev, state)) 1266 | { 1267 | printf("Fail to write!\n"); 1268 | exit(1); 1269 | } 1270 | printf("Done\n"); 1271 | } 1272 | else 1273 | { 1274 | printf("%s", CMD_EXTI_WRITE.usage1); 1275 | exit(1); 1276 | } 1277 | return OK; 1278 | } 1279 | 1280 | int doButtonRead(int argc, char *argv[]); 1281 | const CliCmdType CMD_BUTTON_READ = 1282 | {"btn", 2, &doButtonRead, 1283 | "\tbtn: Read the button state\n", 1284 | "\tUsage: megabas btn \n", "", 1285 | "\tExample: megabas 0 btn ; Read the button state on Board #0\n"}; 1286 | 1287 | int doButtonRead(int argc, char *argv[]) 1288 | { 1289 | u8 val = 0; 1290 | int dev = 0; 1291 | 1292 | dev = doBoardInit(atoi(argv[1])); 1293 | if (dev <= 0) 1294 | { 1295 | exit(1); 1296 | } 1297 | 1298 | if (argc == 3) 1299 | { 1300 | if (OK != buttonGetState(dev, &val)) 1301 | { 1302 | printf("Fail to read!\n"); 1303 | exit(1); 1304 | } 1305 | printf("%d\n", (int)val); 1306 | } 1307 | else 1308 | { 1309 | printf("%s", CMD_EXTI_READ.usage1); 1310 | exit(1); 1311 | } 1312 | return OK; 1313 | } 1314 | 1315 | int dacGet(int dev, int ch, float *val) 1316 | { 1317 | u8 buff[2] = {0, 0}; 1318 | u16 raw = 0; 1319 | 1320 | if ( (ch < CHANNEL_NR_MIN) || (ch > DAC_CH_NR_MAX)) 1321 | { 1322 | printf("DAC channel out of range!\n"); 1323 | return ERROR; 1324 | } 1325 | if (OK != i2cMem8Read(dev, I2C_U0_10_OUT_VAL1_ADD + 2 * (ch - 1), buff, 2)) 1326 | { 1327 | printf("Fail to read!\n"); 1328 | return ERROR; 1329 | } 1330 | memcpy(&raw, buff, 2); 1331 | *val = (float)raw / 1000; 1332 | return OK; 1333 | } 1334 | 1335 | int dacSet(int dev, int ch, float val) 1336 | { 1337 | u8 buff[2] = {0, 0}; 1338 | u16 raw = 0; 1339 | 1340 | if ( (ch < CHANNEL_NR_MIN) || (ch > DAC_CH_NR_MAX)) 1341 | { 1342 | printf("DAC channel out of range!\n"); 1343 | return ERROR; 1344 | } 1345 | if (val < 0) 1346 | { 1347 | val = 0; 1348 | } 1349 | if (val > 10) 1350 | { 1351 | val = 10; 1352 | } 1353 | raw = (u16)ceil(val * 1000); //transform to milivolts 1354 | memcpy(buff, &raw, 2); 1355 | if (OK != i2cMem8Write(dev, I2C_U0_10_OUT_VAL1_ADD + 2 * (ch - 1), buff, 2)) 1356 | { 1357 | printf("Fail to write!\n"); 1358 | return ERROR; 1359 | } 1360 | return OK; 1361 | } 1362 | 1363 | int doDacRead(int argc, char *argv[]); 1364 | const CliCmdType CMD_DAC_READ = 1365 | {"dacrd", 2, &doDacRead, "\tdacrd: Read DAC voltage value (0 - 10V)\n", 1366 | "\tUsage: megabas dacrd \n", "", 1367 | "\tExample: megabas 0 dacrd 2; Read the voltage on 0-10V out channel #2 on Board #0\n"}; 1368 | 1369 | int doDacRead(int argc, char *argv[]) 1370 | { 1371 | int ch = 0; 1372 | float val = 0; 1373 | int dev = 0; 1374 | 1375 | dev = doBoardInit(atoi(argv[1])); 1376 | if (dev <= 0) 1377 | { 1378 | exit(1); 1379 | } 1380 | 1381 | if (argc == 4) 1382 | { 1383 | ch = atoi(argv[3]); 1384 | if ( (ch < CHANNEL_NR_MIN) || (ch > DAC_CH_NR_MAX)) 1385 | { 1386 | printf("DAC channel out of range!\n"); 1387 | exit(1); 1388 | } 1389 | 1390 | if (OK != dacGet(dev, ch, &val)) 1391 | { 1392 | printf("Fail to read!\n"); 1393 | exit(1); 1394 | } 1395 | 1396 | printf("%0.3f\n", val); 1397 | } 1398 | else 1399 | { 1400 | printf("Invalid params number:\n %s", CMD_DAC_READ.usage1); 1401 | exit(1); 1402 | } 1403 | return OK; 1404 | } 1405 | 1406 | int doDacWrite(int argc, char *argv[]); 1407 | const CliCmdType CMD_DAC_WRITE = 1408 | {"dacwr", 2, &doDacWrite, 1409 | "\tdacwr: Write DAC output voltage value (0..10V)\n", 1410 | "\tUsage: megabas dacwr \n", "", 1411 | "\tExample: megabas 0 dacwr 2 2.5; Write 2.5V to 0-10V out channel #2 on Board #0\n"}; 1412 | 1413 | int doDacWrite(int argc, char *argv[]) 1414 | { 1415 | int ch = 0; 1416 | int dev = 0; 1417 | float volt = 0; 1418 | 1419 | dev = doBoardInit(atoi(argv[1])); 1420 | if (dev <= 0) 1421 | { 1422 | exit(1); 1423 | } 1424 | 1425 | if (argc == 5) 1426 | { 1427 | ch = atoi(argv[3]); 1428 | if ( (ch < CHANNEL_NR_MIN) || (ch > DAC_CH_NR_MAX)) 1429 | { 1430 | printf("DAC channel out of range!\n"); 1431 | exit(1); 1432 | } 1433 | volt = atof(argv[4]); 1434 | if (volt < 0 || volt > 10) 1435 | { 1436 | printf("Invalid DAC voltage value, must be 0..10 \n"); 1437 | exit(1); 1438 | } 1439 | 1440 | if (OK != dacSet(dev, ch, volt)) 1441 | { 1442 | printf("Fail to write!\n"); 1443 | exit(1); 1444 | } 1445 | printf("done\n"); 1446 | } 1447 | else 1448 | { 1449 | printf("Invalid params number:\n %s", CMD_DAC_WRITE.usage1); 1450 | exit(1); 1451 | } 1452 | return OK; 1453 | } 1454 | 1455 | int adcGet(int dev, int ch, float *val) 1456 | { 1457 | u8 buff[2] = {0, 0}; 1458 | u16 raw = 0; 1459 | 1460 | if ( (ch < CHANNEL_NR_MIN) || (ch > ADC_CH_NR_MAX)) 1461 | { 1462 | printf("ADC channel out of range!\n"); 1463 | return ERROR; 1464 | } 1465 | if (OK != i2cMem8Read(dev, I2C_U0_10_IN_VAL1_ADD + 2 * (ch - 1), buff, 2)) 1466 | { 1467 | printf("Fail to read!\n"); 1468 | return ERROR; 1469 | } 1470 | memcpy(&raw, buff, 2); 1471 | *val = (float)raw / 1000; 1472 | return OK; 1473 | } 1474 | 1475 | int doAdcRead(int argc, char *argv[]); 1476 | const CliCmdType CMD_ADC_READ = 1477 | {"adcrd", 2, &doAdcRead, 1478 | "\tadcrd: Read ADC input voltage value (0 - 10V)\n\t\t\tWarning: For this measurements to be valid place the jumper in position \"0-10V\" \n", 1479 | "\tUsage: megabas adcrd \n", "", 1480 | "\tExample: megabas 0 adcrd 2; Read the voltage input on 0-10V in channel #2 on Board #0\n"}; 1481 | 1482 | int doAdcRead(int argc, char *argv[]) 1483 | { 1484 | int ch = 0; 1485 | float val = 0; 1486 | int dev = 0; 1487 | 1488 | dev = doBoardInit(atoi(argv[1])); 1489 | if (dev <= 0) 1490 | { 1491 | exit(1); 1492 | } 1493 | 1494 | if (argc == 4) 1495 | { 1496 | ch = atoi(argv[3]); 1497 | if ( (ch < CHANNEL_NR_MIN) || (ch > ADC_CH_NR_MAX)) 1498 | { 1499 | printf("ADC channel out of range!\n"); 1500 | exit(1); 1501 | } 1502 | 1503 | if (OK != adcGet(dev, ch, &val)) 1504 | { 1505 | printf("Fail to read!\n"); 1506 | exit(1); 1507 | } 1508 | 1509 | printf("%0.3f\n", val); 1510 | } 1511 | else 1512 | { 1513 | printf("Invalid params number:\n %s", CMD_ADC_READ.usage1); 1514 | exit(1); 1515 | } 1516 | return OK; 1517 | } 1518 | 1519 | ///////////////////////////////////////////////////////////////////////////////////////////////////////// 1520 | int r1kGet(int dev, int ch, float *val) 1521 | { 1522 | u8 buff[2] = {0, 0}; 1523 | u16 raw = 0; 1524 | 1525 | if ( (ch < CHANNEL_NR_MIN) || (ch > ADC_CH_NR_MAX)) 1526 | { 1527 | printf("ADC channel out of range!\n"); 1528 | return ERROR; 1529 | } 1530 | if (OK != i2cMem8Read(dev, I2C_R_1K_CH1 + 2 * (ch - 1), buff, 2)) 1531 | { 1532 | printf("Fail to read!\n"); 1533 | return ERROR; 1534 | } 1535 | memcpy(&raw, buff, 2); 1536 | *val = (float)raw / 1000; 1537 | return OK; 1538 | } 1539 | 1540 | int doR1kRead(int argc, char *argv[]); 1541 | const CliCmdType CMD_R1K_READ = 1542 | {"r1krd", 2, &doR1kRead, 1543 | "\tr1krd: Read resistor input value (1k) in kiloOhms, Warning: You must palce the jumper in position \"1K\".\n\t\t\tReturn 30kOhm for resistor out of range\n", 1544 | "\tUsage: megabas r1krd \n", "", 1545 | "\tExample: megabas 0 r1krd 2; Read the resistance input on channel #2 on Board #0\n"}; 1546 | 1547 | int doR1kRead(int argc, char *argv[]) 1548 | { 1549 | int ch = 0; 1550 | float val = 0; 1551 | int dev = 0; 1552 | 1553 | dev = doBoardInit(atoi(argv[1])); 1554 | if (dev <= 0) 1555 | { 1556 | exit(1); 1557 | } 1558 | 1559 | if (argc == 4) 1560 | { 1561 | ch = atoi(argv[3]); 1562 | if ( (ch < CHANNEL_NR_MIN) || (ch > ADC_CH_NR_MAX)) 1563 | { 1564 | printf("Resistor read channel out of range!\n"); 1565 | exit(1); 1566 | } 1567 | 1568 | if (OK != r1kGet(dev, ch, &val)) 1569 | { 1570 | printf("Fail to read!\n"); 1571 | exit(1); 1572 | } 1573 | 1574 | printf("%0.3f\n", val); 1575 | } 1576 | else 1577 | { 1578 | printf("Invalid params number:\n %s", CMD_ADC_READ.usage1); 1579 | exit(1); 1580 | } 1581 | return OK; 1582 | } 1583 | 1584 | int r10kGet(int dev, int ch, float *val) 1585 | { 1586 | u8 buff[2] = {0, 0}; 1587 | u16 raw = 0; 1588 | 1589 | if ( (ch < CHANNEL_NR_MIN) || (ch > ADC_CH_NR_MAX)) 1590 | { 1591 | printf("ADC channel out of range!\n"); 1592 | return ERROR; 1593 | } 1594 | if (OK != i2cMem8Read(dev, I2C_R_10K_CH1 + 2 * (ch - 1), buff, 2)) 1595 | { 1596 | printf("Fail to read!\n"); 1597 | return ERROR; 1598 | } 1599 | memcpy(&raw, buff, 2); 1600 | *val = (float)raw / 1000; 1601 | return OK; 1602 | } 1603 | 1604 | int doR10kRead(int argc, char *argv[]); 1605 | const CliCmdType CMD_R10K_READ = 1606 | {"r10krd", 2, &doR10kRead, 1607 | "\tr10krd: Read resistor input value (10k) in kiloOhms, Warning: You must palce the jumper in position \"10K\".\n\t\t\tReturn 30kOhm for resistor out of range\n", 1608 | "\tUsage: megabas r10krd \n", "", 1609 | "\tExample: megabas 0 r10krd 2; Read the resistance input on channel #2 on Board #0\n"}; 1610 | 1611 | int doR10kRead(int argc, char *argv[]) 1612 | { 1613 | int ch = 0; 1614 | float val = 0; 1615 | int dev = 0; 1616 | 1617 | dev = doBoardInit(atoi(argv[1])); 1618 | if (dev <= 0) 1619 | { 1620 | exit(1); 1621 | } 1622 | 1623 | if (argc == 4) 1624 | { 1625 | ch = atoi(argv[3]); 1626 | if ( (ch < CHANNEL_NR_MIN) || (ch > ADC_CH_NR_MAX)) 1627 | { 1628 | printf("Resistor read channel out of range!\n"); 1629 | exit(1); 1630 | } 1631 | 1632 | if (OK != r10kGet(dev, ch, &val)) 1633 | { 1634 | printf("Fail to read!\n"); 1635 | exit(1); 1636 | } 1637 | 1638 | printf("%0.3f\n", val); 1639 | } 1640 | else 1641 | { 1642 | printf("Invalid params number:\n %s", CMD_ADC_READ.usage1); 1643 | exit(1); 1644 | } 1645 | return OK; 1646 | } 1647 | 1648 | void getCalStat(int dev) 1649 | { 1650 | u8 buff[2]; 1651 | 1652 | busyWait(100); 1653 | if (OK != i2cMem8Read(dev, I2C_MEM_CALIB_STATUS, buff, 1)) 1654 | { 1655 | printf("Fail to read calibration status!\n"); 1656 | exit(1); 1657 | } 1658 | switch (buff[0]) 1659 | { 1660 | case 0: 1661 | printf("Calibration in progress\n"); 1662 | break; 1663 | case 1: 1664 | printf("Calibration done\n"); 1665 | break; 1666 | case 2: 1667 | printf("Calibration error!\n"); 1668 | break; 1669 | default: 1670 | printf("Unknown calibration status\n"); 1671 | break; 1672 | } 1673 | } 1674 | 1675 | int doAdcCal(int argc, char *argv[]); 1676 | const CliCmdType CMD_ADC_CAL = 1677 | {"adccal", 2, &doAdcCal, 1678 | "\tadccal: Calibrate one ADC channel, the calibration must be done in 2 points at min 5V apart\n", 1679 | "\tUsage: megabas adccal \n", "", 1680 | "\tExample: megabas 0 adccal 2 0.5; Calibrate the voltage input on ADC channel #2 on Board #0 at 0.5V\n"}; 1681 | 1682 | int doAdcCal(int argc, char *argv[]) 1683 | { 1684 | int ch = 0; 1685 | float val = 0; 1686 | int dev = 0; 1687 | u8 buff[4] = {0, 0}; 1688 | u16 raw = 0; 1689 | 1690 | dev = doBoardInit(atoi(argv[1])); 1691 | if (dev <= 0) 1692 | { 1693 | exit(1); 1694 | } 1695 | 1696 | if (argc == 5) 1697 | { 1698 | ch = atoi(argv[3]); 1699 | if ( (ch < CHANNEL_NR_MIN) || (ch > ADC_CH_NR_MAX)) 1700 | { 1701 | printf("ADC channel out of range!\n"); 1702 | exit(1); 1703 | } 1704 | 1705 | val = atof(argv[4]); 1706 | if ( (val < 0) || (val > 10)) 1707 | { 1708 | printf("ADC calibration value out of range!\n"); 1709 | exit(1); 1710 | } 1711 | raw = (u16)ceil(val * VOLT_TO_MILIVOLT); 1712 | memcpy(buff, &raw, 2); 1713 | buff[2] = ch + CAL_0_10V_IN_START_ID - 1; 1714 | buff[3] = CALIBRATION_KEY; 1715 | 1716 | if (OK != i2cMem8Write(dev, I2C_MEM_CALIB_VALUE, buff, 4)) 1717 | { 1718 | printf("Fail to write calibration data!\n"); 1719 | exit(1); 1720 | } 1721 | 1722 | getCalStat(dev); 1723 | } 1724 | else 1725 | { 1726 | printf("Invalid params number:\n %s", CMD_ADC_CAL.usage1); 1727 | exit(1); 1728 | } 1729 | return OK; 1730 | } 1731 | 1732 | int doAdcCalRst(int argc, char *argv[]); 1733 | const CliCmdType CMD_ADC_CAL_RST = 1734 | {"adccalrst", 2, &doAdcCalRst, 1735 | "\tadccalrst: Reset the calibration for one ADC channel\n", 1736 | "\tUsage: megabas adccalrst \n", "", 1737 | "\tExample: megabas 0 adccalrst 2 ; Reset the calibration on ADC channel #2 on Board #0 at factory default\n"}; 1738 | 1739 | int doAdcCalRst(int argc, char *argv[]) 1740 | { 1741 | int ch = 0; 1742 | 1743 | int dev = 0; 1744 | u8 buff[4] = {0, 0, 0, 0}; 1745 | 1746 | dev = doBoardInit(atoi(argv[1])); 1747 | if (dev <= 0) 1748 | { 1749 | exit(1); 1750 | } 1751 | 1752 | if (argc == 4) 1753 | { 1754 | ch = atoi(argv[3]); 1755 | if ( (ch < CHANNEL_NR_MIN) || (ch > ADC_CH_NR_MAX)) 1756 | { 1757 | printf("ADC channel out of range!\n"); 1758 | exit(1); 1759 | } 1760 | 1761 | buff[2] = ch + CAL_0_10V_IN_START_ID - 1; 1762 | ; 1763 | buff[3] = RESET_CALIBRATION_KEY; 1764 | 1765 | if (OK != i2cMem8Write(dev, I2C_MEM_CALIB_VALUE, buff, 4)) 1766 | { 1767 | printf("Fail to write calibration data!\n"); 1768 | exit(1); 1769 | } 1770 | 1771 | getCalStat(dev); 1772 | } 1773 | else 1774 | { 1775 | printf("Invalid params number:\n %s", CMD_ADC_CAL_RST.usage1); 1776 | exit(1); 1777 | } 1778 | return OK; 1779 | } 1780 | 1781 | int doDacCal(int argc, char *argv[]); 1782 | const CliCmdType CMD_DAC_CAL = 1783 | {"daccal", 2, &doDacCal, 1784 | "\tdaccal: Calibrate one DAC channel, the calibration must be done in 2 points at min 5V apart\n", 1785 | "\tUsage: megabas daccal \n", "", 1786 | "\tExample: megabas 0 daccal 2 0.5; Calibrate the voltage outputs on DAC channel #2 on Board #0 at 0.5V\n"}; 1787 | 1788 | int doDacCal(int argc, char *argv[]) 1789 | { 1790 | int ch = 0; 1791 | float val = 0; 1792 | int dev = 0; 1793 | u8 buff[4] = {0, 0}; 1794 | u16 raw = 0; 1795 | 1796 | dev = doBoardInit(atoi(argv[1])); 1797 | if (dev <= 0) 1798 | { 1799 | exit(1); 1800 | } 1801 | 1802 | if (argc == 5) 1803 | { 1804 | ch = atoi(argv[3]); 1805 | if ( (ch < CHANNEL_NR_MIN) || (ch > DAC_CH_NR_MAX)) 1806 | { 1807 | printf("DAC channel out of range!\n"); 1808 | exit(1); 1809 | } 1810 | 1811 | val = atof(argv[4]); 1812 | if ( (val < 0) || (val > 10)) 1813 | { 1814 | printf("DAC calibration value out of range!\n"); 1815 | exit(1); 1816 | } 1817 | raw = (u16)ceil(val * VOLT_TO_MILIVOLT); 1818 | memcpy(buff, &raw, 2); 1819 | buff[2] = ch + CAL_0_10V_OUT_START_ID - 1; 1820 | buff[3] = CALIBRATION_KEY; 1821 | 1822 | if (OK != i2cMem8Write(dev, I2C_MEM_CALIB_VALUE, buff, 4)) 1823 | { 1824 | printf("Fail to write calibration data!\n"); 1825 | exit(1); 1826 | } 1827 | 1828 | getCalStat(dev); 1829 | } 1830 | else 1831 | { 1832 | printf("Invalid params number:\n %s", CMD_DAC_CAL.usage1); 1833 | exit(1); 1834 | } 1835 | return OK; 1836 | } 1837 | 1838 | int doDacCalRst(int argc, char *argv[]); 1839 | const CliCmdType CMD_DAC_CAL_RST = 1840 | {"daccalrst", 2, &doDacCalRst, 1841 | "\tdaccalrst: Reset calibration for one DAC channel\n", 1842 | "\tUsage: megabas daccalrst \n", "", 1843 | "\tExample: megabas 0 daccalrst 2; Reset calibration data on DAC channel #2 on Board #0 at factory default\n"}; 1844 | 1845 | int doDacCalRst(int argc, char *argv[]) 1846 | { 1847 | int ch = 0; 1848 | 1849 | int dev = 0; 1850 | u8 buff[4] = {0, 0, 0, 0}; 1851 | u16 raw = 0; 1852 | 1853 | dev = doBoardInit(atoi(argv[1])); 1854 | if (dev <= 0) 1855 | { 1856 | exit(1); 1857 | } 1858 | 1859 | if (argc == 4) 1860 | { 1861 | ch = atoi(argv[3]); 1862 | if ( (ch < CHANNEL_NR_MIN) || (ch > DAC_CH_NR_MAX)) 1863 | { 1864 | printf("DAC channel out of range!\n"); 1865 | exit(1); 1866 | } 1867 | 1868 | memcpy(buff, &raw, 2); 1869 | buff[2] = ch + CAL_0_10V_OUT_START_ID - 1; 1870 | buff[3] = RESET_CALIBRATION_KEY; 1871 | 1872 | if (OK != i2cMem8Write(dev, I2C_MEM_CALIB_VALUE, buff, 4)) 1873 | { 1874 | printf("Fail to write calibration data!\n"); 1875 | exit(1); 1876 | } 1877 | getCalStat(dev); 1878 | } 1879 | else 1880 | { 1881 | printf("Invalid params number:\n %s", CMD_DAC_CAL_RST.usage1); 1882 | exit(1); 1883 | } 1884 | return OK; 1885 | } 1886 | 1887 | int doWdtReload(int argc, char *argv[]); 1888 | const CliCmdType CMD_WDT_RELOAD = 1889 | {"wdtr", 2, &doWdtReload, 1890 | "\twdtr: Reload the watchdog timer and enable the watchdog if is disabled\n", 1891 | "\tUsage: megabas wdtr\n", "", 1892 | "\tExample: megabas 0 wdtr; Reload the watchdog timer on Board #0 with the period \n"}; 1893 | 1894 | int doWdtReload(int argc, char *argv[]) 1895 | { 1896 | int dev = 0; 1897 | u8 buff[2] = {0, 0}; 1898 | 1899 | dev = doBoardInit(atoi(argv[1])); 1900 | if (dev <= 0) 1901 | { 1902 | exit(1); 1903 | } 1904 | 1905 | if (argc == 3) 1906 | { 1907 | buff[0] = WDT_RESET_SIGNATURE; 1908 | if (OK != i2cMem8Write(dev, I2C_MEM_WDT_RESET_ADD, buff, 1)) 1909 | { 1910 | printf("Fail to write watchdog reset key!\n"); 1911 | exit(1); 1912 | } 1913 | } 1914 | else 1915 | { 1916 | printf("Invalid params number:\n %s", CMD_WDT_RELOAD.usage1); 1917 | exit(1); 1918 | } 1919 | return OK; 1920 | } 1921 | 1922 | int doWdtSetPeriod(int argc, char *argv[]); 1923 | const CliCmdType CMD_WDT_SET_PERIOD = 1924 | {"wdtpwr", 2, &doWdtSetPeriod, 1925 | "\twdtpwr: Set the watchdog period in seconds, \n\t\t\treload command must be issue in this interval to prevent Raspberry Pi power off\n", 1926 | "\tUsage: megabas wdtpwr \n", "", 1927 | "\tExample: megabas 0 wdtpwr 10; Set the watchdog timer period on Board #0 at 10 seconds \n"}; 1928 | 1929 | int doWdtSetPeriod(int argc, char *argv[]) 1930 | { 1931 | int dev = 0; 1932 | u16 period; 1933 | u8 buff[2] = {0, 0}; 1934 | 1935 | dev = doBoardInit(atoi(argv[1])); 1936 | if (dev <= 0) 1937 | { 1938 | exit(1); 1939 | } 1940 | 1941 | if (argc == 4) 1942 | { 1943 | period = (u16)atoi(argv[3]); 1944 | if (0 == period) 1945 | { 1946 | printf("Invalid period!\n"); 1947 | exit(1); 1948 | } 1949 | memcpy(buff, &period, 2); 1950 | if (OK != i2cMem8Write(dev, I2C_MEM_WDT_INTERVAL_SET_ADD, buff, 2)) 1951 | { 1952 | printf("Fail to write watchdog period!\n"); 1953 | exit(1); 1954 | } 1955 | } 1956 | else 1957 | { 1958 | printf("Invalid params number:\n %s", CMD_WDT_SET_PERIOD.usage1); 1959 | exit(1); 1960 | } 1961 | return OK; 1962 | } 1963 | 1964 | int doWdtGetPeriod(int argc, char *argv[]); 1965 | const CliCmdType CMD_WDT_GET_PERIOD = 1966 | {"wdtprd", 2, &doWdtGetPeriod, 1967 | "\twdtprd: Get the watchdog period in seconds, \n\t\t\treload command must be issue in this interval to prevent Raspberry Pi power off\n", 1968 | "\tUsage: megabas wdtprd \n", "", 1969 | "\tExample: megabas 0 wdtprd; Get the watchdog timer period on Board #0\n"}; 1970 | 1971 | int doWdtGetPeriod(int argc, char *argv[]) 1972 | { 1973 | int dev = 0; 1974 | u16 period; 1975 | u8 buff[2] = {0, 0}; 1976 | 1977 | dev = doBoardInit(atoi(argv[1])); 1978 | if (dev <= 0) 1979 | { 1980 | exit(1); 1981 | } 1982 | 1983 | if (argc == 3) 1984 | { 1985 | if (OK != i2cMem8Read(dev, I2C_MEM_WDT_INTERVAL_GET_ADD, buff, 2)) 1986 | { 1987 | printf("Fail to read watchdog period!\n"); 1988 | exit(1); 1989 | } 1990 | memcpy(&period, buff, 2); 1991 | printf("%d\n", (int)period); 1992 | } 1993 | else 1994 | { 1995 | printf("Invalid params number:\n %s", CMD_WDT_GET_PERIOD.usage1); 1996 | exit(1); 1997 | } 1998 | return OK; 1999 | } 2000 | 2001 | int doWdtSetInitPeriod(int argc, char *argv[]); 2002 | const CliCmdType CMD_WDT_SET_INIT_PERIOD = 2003 | {"wdtipwr", 2, &doWdtSetInitPeriod, 2004 | "\twdtipwr: Set the watchdog initial period in seconds, \n\t\t\tThis period is loaded after power cycle, giving Raspberry time to boot\n", 2005 | "\tUsage: megabas wdtipwr \n", "", 2006 | "\tExample: megabas 0 wdtipwr 10; Set the watchdog timer initial period on Board #0 at 10 seconds \n"}; 2007 | 2008 | int doWdtSetInitPeriod(int argc, char *argv[]) 2009 | { 2010 | int dev = 0; 2011 | u16 period; 2012 | u8 buff[2] = {0, 0}; 2013 | 2014 | dev = doBoardInit(atoi(argv[1])); 2015 | if (dev <= 0) 2016 | { 2017 | exit(1); 2018 | } 2019 | 2020 | if (argc == 4) 2021 | { 2022 | period = (u16)atoi(argv[3]); 2023 | if (0 == period) 2024 | { 2025 | printf("Invalid period!\n"); 2026 | exit(1); 2027 | } 2028 | memcpy(buff, &period, 2); 2029 | if (OK != i2cMem8Write(dev, I2C_MEM_WDT_INIT_INTERVAL_SET_ADD, buff, 2)) 2030 | { 2031 | printf("Fail to write watchdog period!\n"); 2032 | exit(1); 2033 | } 2034 | } 2035 | else 2036 | { 2037 | printf("Invalid params number:\n %s", CMD_WDT_SET_INIT_PERIOD.usage1); 2038 | exit(1); 2039 | } 2040 | return OK; 2041 | } 2042 | 2043 | int doWdtGetInitPeriod(int argc, char *argv[]); 2044 | const CliCmdType CMD_WDT_GET_INIT_PERIOD = 2045 | {"wdtiprd", 2, &doWdtGetInitPeriod, 2046 | "\twdtiprd: Get the watchdog initial period in seconds. \n\t\t\tThis period is loaded after power cycle, giving Raspberry time to boot\n", 2047 | "\tUsage: megabas wdtiprd \n", "", 2048 | "\tExample: megabas 0 wdtiprd; Get the watchdog timer initial period on Board #0\n"}; 2049 | 2050 | int doWdtGetInitPeriod(int argc, char *argv[]) 2051 | { 2052 | int dev = 0; 2053 | u16 period; 2054 | u8 buff[2] = {0, 0}; 2055 | 2056 | dev = doBoardInit(atoi(argv[1])); 2057 | if (dev <= 0) 2058 | { 2059 | exit(1); 2060 | } 2061 | 2062 | if (argc == 3) 2063 | { 2064 | if (OK != i2cMem8Read(dev, I2C_MEM_WDT_INIT_INTERVAL_GET_ADD, buff, 2)) 2065 | { 2066 | printf("Fail to read watchdog period!\n"); 2067 | exit(1); 2068 | } 2069 | memcpy(&period, buff, 2); 2070 | printf("%d\n", (int)period); 2071 | } 2072 | else 2073 | { 2074 | printf("Invalid params number:\n %s", CMD_WDT_GET_INIT_PERIOD.usage1); 2075 | exit(1); 2076 | } 2077 | return OK; 2078 | } 2079 | 2080 | int doWdtSetOffPeriod(int argc, char *argv[]); 2081 | const CliCmdType CMD_WDT_SET_OFF_PERIOD = 2082 | {"wdtopwr", 2, &doWdtSetOffPeriod, 2083 | "\twdtopwr: Set the watchdog off period in seconds (max 48 days). \n\t\t\tThis is the time that watchdog mantain Raspberry turned off \n", 2084 | "\tUsage: megabas wdtopwr \n", "", 2085 | "\tExample: megabas 0 wdtopwr 10; Set the watchdog off interval on Board #0 at 10 seconds \n"}; 2086 | 2087 | int doWdtSetOffPeriod(int argc, char *argv[]) 2088 | { 2089 | int dev = 0; 2090 | u32 period; 2091 | u8 buff[4] = {0, 0, 0, 0}; 2092 | 2093 | dev = doBoardInit(atoi(argv[1])); 2094 | if (dev <= 0) 2095 | { 2096 | exit(1); 2097 | } 2098 | 2099 | if (argc == 4) 2100 | { 2101 | period = (u32)atoi(argv[3]); 2102 | if ( (0 == period) || (period > WDT_MAX_OFF_INTERVAL_S)) 2103 | { 2104 | printf("Invalid period!\n"); 2105 | exit(1); 2106 | } 2107 | memcpy(buff, &period, 4); 2108 | if (OK 2109 | != i2cMem8Write(dev, I2C_MEM_WDT_POWER_OFF_INTERVAL_SET_ADD, buff, 4)) 2110 | { 2111 | printf("Fail to write watchdog period!\n"); 2112 | exit(1); 2113 | } 2114 | } 2115 | else 2116 | { 2117 | printf("Invalid params number:\n %s", CMD_WDT_SET_OFF_PERIOD.usage1); 2118 | exit(1); 2119 | } 2120 | return OK; 2121 | } 2122 | 2123 | int doWdtGetOffPeriod(int argc, char *argv[]); 2124 | const CliCmdType CMD_WDT_GET_OFF_PERIOD = 2125 | {"wdtoprd", 2, &doWdtGetOffPeriod, 2126 | "\twdtoprd: Get the watchdog off period in seconds (max 48 days) \n\t\t\tThis is the time that watchdog mantain Raspberry turned off \n", 2127 | "\tUsage: megabas wdtoprd \n", "", 2128 | "\tExample: megabas 0 wdtoprd; Get the watchdog off period on Board #0\n"}; 2129 | 2130 | int doWdtGetOffPeriod(int argc, char *argv[]) 2131 | { 2132 | int dev = 0; 2133 | u32 period; 2134 | u8 buff[4] = {0, 0, 0, 0}; 2135 | 2136 | dev = doBoardInit(atoi(argv[1])); 2137 | if (dev <= 0) 2138 | { 2139 | exit(1); 2140 | } 2141 | 2142 | if (argc == 3) 2143 | { 2144 | if (OK 2145 | != i2cMem8Read(dev, I2C_MEM_WDT_POWER_OFF_INTERVAL_GET_ADD, buff, 4)) 2146 | { 2147 | printf("Fail to read watchdog period!\n"); 2148 | exit(1); 2149 | } 2150 | memcpy(&period, buff, 4); 2151 | printf("%d\n", (int)period); 2152 | } 2153 | else 2154 | { 2155 | printf("Invalid params number:\n %s", CMD_WDT_GET_OFF_PERIOD.usage1); 2156 | exit(1); 2157 | } 2158 | return OK; 2159 | } 2160 | 2161 | int rs485Set(int dev, u8 mode, u32 baud, u8 stopB, u8 parity, u8 add) 2162 | { 2163 | ModbusSetingsType settings; 2164 | u8 buff[5]; 2165 | 2166 | if (0 == mode) //disable modbus 2167 | { 2168 | baud = 9600; 2169 | stopB = 1; 2170 | parity = 0; 2171 | add = 1; 2172 | } 2173 | 2174 | if (baud > 920600 || baud < 1200) 2175 | { 2176 | printf("Invalid RS485 Baudrate [1200, 920600]!\n"); 2177 | return ERROR; 2178 | } 2179 | if (mode > 1) 2180 | { 2181 | printf("Invalid RS485 mode : 0 = disable, 1= Modbus RTU (Slave)!\n"); 2182 | return ERROR; 2183 | } 2184 | if (stopB < 1 || stopB > 2) 2185 | { 2186 | printf("Invalid RS485 stop bits [1, 2]!\n"); 2187 | return ERROR; 2188 | } 2189 | if (parity > 2) 2190 | { 2191 | printf("Invalid RS485 parity 0 = none; 1 = even; 2 = odd! \n"); 2192 | return ERROR; 2193 | } 2194 | if (add < 1) 2195 | { 2196 | printf("Invalid MODBUS device address: [1, 255]!\n"); 2197 | } 2198 | settings.mbBaud = baud; 2199 | settings.mbType = mode; 2200 | settings.mbParity = parity; 2201 | settings.mbStopB = stopB; 2202 | settings.add = add; 2203 | 2204 | memcpy(buff, &settings, sizeof(ModbusSetingsType)); 2205 | if (OK != i2cMem8Write(dev, I2C_MODBUS_SETINGS_ADD, buff, 5)) 2206 | { 2207 | printf("Fail to write RS485 settings!\n"); 2208 | return ERROR; 2209 | } 2210 | return OK; 2211 | } 2212 | 2213 | int rs485Get(int dev) 2214 | { 2215 | ModbusSetingsType settings; 2216 | u8 buff[5]; 2217 | 2218 | if (OK != i2cMem8Read(dev, I2C_MODBUS_SETINGS_ADD, buff, 5)) 2219 | { 2220 | printf("Fail to read RS485 settings!\n"); 2221 | return ERROR; 2222 | } 2223 | memcpy(&settings, buff, sizeof(ModbusSetingsType)); 2224 | printf(" %d %d %d %d %d\n", 2225 | (int)settings.mbType, (int)settings.mbBaud, (int)settings.mbStopB, 2226 | (int)settings.mbParity, (int)settings.add); 2227 | return OK; 2228 | } 2229 | 2230 | int doRs485Read(int argc, char *argv[]); 2231 | const CliCmdType CMD_RS485_READ = {"rs485rd", 2, &doRs485Read, 2232 | "\trs485rd: Read the RS485 communication settings\n", 2233 | "\tUsage: megabas rs485rd\n", "", 2234 | "\tExample: megabas 0 rs485rd; Read the RS485 settings on Board #0\n"}; 2235 | 2236 | int doRs485Read(int argc, char *argv[]) 2237 | { 2238 | int dev = 0; 2239 | 2240 | dev = doBoardInit(atoi(argv[1])); 2241 | if (dev <= 0) 2242 | { 2243 | exit(1); 2244 | } 2245 | 2246 | if (argc == 3) 2247 | { 2248 | if (OK != rs485Get(dev)) 2249 | { 2250 | exit(1); 2251 | } 2252 | } 2253 | else 2254 | { 2255 | printf("Invalid params number:\n %s", CMD_RS485_READ.usage1); 2256 | exit(1); 2257 | } 2258 | return OK; 2259 | } 2260 | 2261 | int doRs485Write(int argc, char *argv[]); 2262 | const CliCmdType CMD_RS485_WRITE = 2263 | {"rs485wr", 2, &doRs485Write, 2264 | "\trs485wr: Write the RS485 communication settings\n", 2265 | "\tUsage: megabas rs485wr \n", 2266 | "", 2267 | "\tExample: megabas 0 rs485wr 1 9600 1 0 1; Write the RS485 settings on Board #0 \n\t\t\t(mode = Modbus RTU; baudrate = 9600 bps; stop bits one; parity none; modbus slave address = 1)\n"}; 2268 | 2269 | int doRs485Write(int argc, char *argv[]) 2270 | { 2271 | int dev = 0; 2272 | u8 mode = 0; 2273 | u32 baud = 1200; 2274 | u8 stopB = 1; 2275 | u8 parity = 0; 2276 | u8 add = 0; 2277 | 2278 | dev = doBoardInit(atoi(argv[1])); 2279 | if (dev <= 0) 2280 | { 2281 | exit(1); 2282 | } 2283 | 2284 | if (argc == 8) 2285 | { 2286 | mode = 0xff & atoi(argv[3]); 2287 | baud = atoi(argv[4]); 2288 | stopB = 0xff & atoi(argv[5]); 2289 | parity = 0xff & atoi(argv[6]); 2290 | add = 0xff & atoi(argv[7]); 2291 | if (OK != rs485Set(dev, mode, baud, stopB, parity, add)) 2292 | { 2293 | exit(1); 2294 | } 2295 | printf("done\n"); 2296 | } 2297 | else 2298 | { 2299 | printf("Invalid params number:\n %s", CMD_RS485_WRITE.usage1); 2300 | exit(1); 2301 | } 2302 | return OK; 2303 | } 2304 | 2305 | int doRTCGet(int argc, char *argv[]); 2306 | const CliCmdType CMD_RTC_GET = 2307 | {"rtcrd", 2, &doRTCGet, 2308 | "\trtcrd: Get the internal RTC date and time(mm/dd/yy hh:mm:ss)\n", 2309 | "\tUsage: megabas rtcrd \n", "", 2310 | "\tExample: megabas 0 rtcrd; Get the nternal RTC time and date on Board #0\n"}; 2311 | 2312 | int doRTCGet(int argc, char *argv[]) 2313 | { 2314 | int dev = 0; 2315 | u8 buff[6]; 2316 | 2317 | dev = doBoardInit(atoi(argv[1])); 2318 | if (dev <= 0) 2319 | { 2320 | exit(1); 2321 | } 2322 | 2323 | if (argc == 3) 2324 | { 2325 | if (OK != i2cMem8Read(dev, I2C_RTC_YEAR_ADD, buff, 6)) 2326 | { 2327 | printf("Fail to read RTC!\n"); 2328 | exit(1); 2329 | } 2330 | 2331 | printf("%02u/%02u/%02u %02u:%02u:%02u\n", buff[1], buff[2], buff[0], 2332 | buff[3], buff[4], buff[5]); 2333 | } 2334 | else 2335 | { 2336 | printf("Invalid params number:\n %s", CMD_RTC_GET.usage1); 2337 | exit(1); 2338 | } 2339 | return OK; 2340 | } 2341 | 2342 | int doRTCSet(int argc, char *argv[]); 2343 | const CliCmdType CMD_RTC_SET = 2344 | {"rtcwr", 2, &doRTCSet, 2345 | "\trtcwr: Set the internal RTC date and time(mm/dd/yy hh:mm:ss)\n", 2346 | "\tUsage: megabas rtcwr
\n", "", 2347 | "\tExample: megabas 0 rtcwr 9 15 20 21 43 15; Set the internal RTC time and date on Board #0 at Sept/15/2020 21:43:15\n"}; 2348 | 2349 | int doRTCSet(int argc, char *argv[]) 2350 | { 2351 | int dev = 0; 2352 | u8 buff[7]; 2353 | int i = 0; 2354 | 2355 | dev = doBoardInit(atoi(argv[1])); 2356 | if (dev <= 0) 2357 | { 2358 | exit(1); 2359 | } 2360 | 2361 | if (argc == 9) 2362 | { 2363 | i = atoi(argv[3]); //month 2364 | if (i < 1 || i > 12) 2365 | { 2366 | printf("Invalid month!\n"); 2367 | exit(1); 2368 | } 2369 | buff[1] = i; 2370 | i = atoi(argv[4]); 2371 | if (i < 1 || i > 31) 2372 | { 2373 | printf("Invalid date!\n"); 2374 | exit(1); 2375 | } 2376 | buff[2] = i; 2377 | i = atoi(argv[5]); 2378 | if (i < 0 || i > 99) 2379 | { 2380 | printf("Invalid year!\n"); 2381 | exit(1); 2382 | } 2383 | buff[0] = i; 2384 | i = atoi(argv[6]); 2385 | if (i < 0 || i > 23) 2386 | { 2387 | printf("Invalid hour!\n"); 2388 | exit(1); 2389 | } 2390 | buff[3] = i; 2391 | i = atoi(argv[7]); 2392 | if (i < 0 || i > 59) 2393 | { 2394 | printf("Invalid minute!\n"); 2395 | exit(1); 2396 | } 2397 | buff[4] = i; 2398 | i = atoi(argv[8]); 2399 | if (i < 0 || i > 59) 2400 | { 2401 | printf("Invalid second!\n"); 2402 | exit(1); 2403 | } 2404 | buff[5] = i; 2405 | buff[6] = CALIBRATION_KEY; 2406 | if (OK != i2cMem8Write(dev, I2C_RTC_SET_YEAR_ADD, buff, 7)) 2407 | { 2408 | printf("Fail to read RTC!\n"); 2409 | exit(1); 2410 | } 2411 | printf("done\n"); 2412 | } 2413 | else 2414 | { 2415 | printf("Invalid params number:\n %s", CMD_RTC_SET.usage1); 2416 | exit(1); 2417 | } 2418 | return OK; 2419 | } 2420 | 2421 | int doOwbGet(int argc, char *argv[]); 2422 | const CliCmdType CMD_OWB_RD = 2423 | {"owbtrd", 2, &doOwbGet, 2424 | "\towbtrd Display the temperature readed from a one wire bus connected sensor\n", 2425 | "\tUsage: megabas owbtrd \n", "", 2426 | "\tExample: megabas 0 owbtrd 1 Display the temperature of the sensor #1\n"}; 2427 | 2428 | int doOwbGet(int argc, char *argv[]) 2429 | { 2430 | int dev = -1; 2431 | u8 buff[5]; 2432 | int resp = 0; 2433 | int channel = 0; 2434 | float temp = 0; 2435 | 2436 | if (argc != 4) 2437 | { 2438 | return ARG_CNT_ERR; 2439 | } 2440 | channel = atoi(argv[3]); 2441 | if (channel < 1 || channel > 16) 2442 | { 2443 | return ERROR; 2444 | } 2445 | dev = doBoardInit(atoi(argv[1])); 2446 | if (dev <= 0) 2447 | { 2448 | return ERROR; 2449 | } 2450 | resp = i2cMem8Read(dev, I2C_MEM_1WB_DEV, buff, 1); 2451 | if (FAIL == resp) 2452 | { 2453 | printf("Fail to read one wire bus info!\n"); 2454 | return ERROR; 2455 | } 2456 | if (channel > buff[0]) 2457 | { 2458 | printf("Invalid channel number, only %d sensors connected!\n", buff[0]); 2459 | return ERROR; 2460 | } 2461 | 2462 | resp = i2cMem8Read(dev, I2C_MEM_1WB_T1 + (channel - 1) * OWB_TEMP_SIZE_B, 2463 | buff, OWB_TEMP_SIZE_B); 2464 | if (FAIL == resp) 2465 | { 2466 | printf("Fail to read one wire bus info!\n"); 2467 | return ERROR; 2468 | } 2469 | // if (buff[0] == 0) 2470 | // { 2471 | // printf("No sensor connected!\n"); 2472 | // return OK; 2473 | // } 2474 | memcpy(&resp, &buff[0], 2); 2475 | temp = (float)resp / 100; 2476 | 2477 | printf("%0.2f C\n", temp); 2478 | return OK; 2479 | } 2480 | 2481 | int doOwbIdGet(int argc, char *argv[]); 2482 | const CliCmdType CMD_OWB_ID_RD = 2483 | {"owbidrd", 2, &doOwbIdGet, 2484 | "\towbidrd Display the 64bits ROM ID of the one wire bus connected sensor\n", 2485 | "\tUsage: megabas owbidrd \n", "", 2486 | "\tExample: megabas 0 owbidrd 1 Display the ROM ID of the sensor #1\n"}; 2487 | 2488 | int doOwbIdGet(int argc, char *argv[]) 2489 | { 2490 | int dev = -1; 2491 | u8 buff[8]; 2492 | int resp = 0; 2493 | int channel = 0; 2494 | uint64_t romID = 0; 2495 | 2496 | if (argc != 4) 2497 | { 2498 | return ARG_CNT_ERR; 2499 | } 2500 | channel = atoi(argv[3]); 2501 | if (channel < 1 || channel > 16) 2502 | { 2503 | return ERROR; 2504 | } 2505 | dev = doBoardInit(atoi(argv[1])); 2506 | if (dev <= 0) 2507 | { 2508 | return ERROR; 2509 | } 2510 | buff[0] = 0xff & (channel - 1); 2511 | resp = i2cMem8Write(dev, I2C_MEM_1WB_ROM_CODE_IDX, buff, 1); //Select sensor ID to read 2512 | if (FAIL == resp) 2513 | { 2514 | printf("Fail to read one wire bus info!\n"); 2515 | return ERROR; 2516 | } 2517 | resp = i2cMem8Read(dev, I2C_MEM_1WB_DEV, buff, 1); //check the number of connected sensors 2518 | if (FAIL == resp) 2519 | { 2520 | printf("Fail to read one wire bus info!\n"); 2521 | return ERROR; 2522 | } 2523 | if (channel > buff[0]) 2524 | { 2525 | printf("Invalid channel number, only %d sensors connected!\n", buff[0]); 2526 | return ERROR; 2527 | } 2528 | 2529 | resp = i2cMem8Read(dev, I2C_MEM_1WB_ROM_CODE, buff, 8); 2530 | if (FAIL == resp) 2531 | { 2532 | printf("Fail to read one wire bus info!\n"); 2533 | return ERROR; 2534 | } 2535 | 2536 | memcpy(&romID, &buff[0], 8); 2537 | 2538 | printf("0x%lx\n", romID); 2539 | return OK; 2540 | } 2541 | 2542 | int doOwbSensCountRead(int argc, char *argv[]); 2543 | const CliCmdType CMD_OWB_SNS_CNT_RD = {"owbcntrd", 2, &doOwbSensCountRead, 2544 | "\towbcntrd Display the number of One Wire Bus connected sensors\n", 2545 | "\tUsage: megabas owbcntrd\n", "", 2546 | "\tExample: megabas 0 owbcntrd Display the number of sensors connected\n"}; 2547 | 2548 | int doOwbSensCountRead(int argc, char *argv[]) 2549 | { 2550 | int dev = -1; 2551 | u8 buff[2]; 2552 | int resp = 0; 2553 | 2554 | if (argc != 3) 2555 | { 2556 | return ARG_CNT_ERR; 2557 | } 2558 | dev = doBoardInit(atoi(argv[1])); 2559 | if (dev <= 0) 2560 | { 2561 | return ERROR; 2562 | } 2563 | resp = i2cMem8Read(dev, I2C_MEM_1WB_DEV, buff, 1); 2564 | if (FAIL == resp) 2565 | { 2566 | printf("Fail to read!\n"); 2567 | return ERROR; 2568 | } 2569 | 2570 | printf("%d\n", buff[0]); 2571 | return OK; 2572 | } 2573 | 2574 | int doOwbScan(int argc, char *argv[]); 2575 | const CliCmdType CMD_OWB_SCAN = {"owbscan", 2, &doOwbScan, 2576 | "\towbscan Start One Wire Bus scaning procedure\n", 2577 | "\tUsage: megabas owbscan\n", "", 2578 | "\tExample: megabas 0 owbscan Start One Wire Bus scaning procedure\n"}; 2579 | 2580 | int doOwbScan(int argc, char *argv[]) 2581 | { 2582 | int dev = -1; 2583 | u8 buff[2]; 2584 | int resp = 0; 2585 | 2586 | if (argc != 3) 2587 | { 2588 | return ARG_CNT_ERR; 2589 | } 2590 | dev = doBoardInit(atoi(argv[1])); 2591 | if (dev <= 0) 2592 | { 2593 | return ERROR; 2594 | } 2595 | buff[0] = 0xaa; 2596 | resp = i2cMem8Write(dev, I2C_MEM_1WB_START_SEARCH, buff, 1); 2597 | if (FAIL == resp) 2598 | { 2599 | printf("Fail to write!\n"); 2600 | return ERROR; 2601 | } 2602 | 2603 | printf("OK\n"); 2604 | return OK; 2605 | } 2606 | 2607 | 2608 | int doInCfgWrite(int argc, char *argv[]); 2609 | const CliCmdType CMD_IN_CONFIG_WRITE = 2610 | {"incfgwr", 2, &doInCfgWrite, 2611 | "\tincfgwr: Config input type to 0-10V(0); 1k Thermistor(1) or 10k Thermistor(2)\n", 2612 | "\tUsage: megabas incfgwr <0/1/2>\n", 2613 | "", 2614 | "\tExample: megabas 0 incfgwr 2 1; Set channel #2 on Board #0 as 1k thermistor input\n" 2615 | }; 2616 | 2617 | int doInCfgWrite(int argc, char *argv[]) 2618 | { 2619 | int pin = 0; 2620 | int val = 0; 2621 | int dev = 0; 2622 | int resp = 0; 2623 | uint8_t buff[3]; 2624 | 2625 | if ( argc != 5) 2626 | { 2627 | printf("%s", CMD_IN_CONFIG_WRITE.usage1); 2628 | exit(1); 2629 | } 2630 | 2631 | dev = doBoardInit(atoi(argv[1])); 2632 | if (dev <= 0) 2633 | { 2634 | exit(1); 2635 | } 2636 | 2637 | pin = atoi(argv[3]); 2638 | if ( (pin < CHANNEL_NR_MIN) || (pin > ADC_CH_NR_MAX)) 2639 | { 2640 | printf("Input channel number value out of range\n"); 2641 | exit(1); 2642 | } 2643 | val = atoi(argv[4]); 2644 | 2645 | 2646 | resp = i2cMem8Read(dev, I2C_MEM_UIN_SEL, buff, 3); 2647 | if (FAIL == resp) 2648 | { 2649 | printf("Fail to read config!\n"); 2650 | return ERROR; 2651 | } 2652 | switch (val) 2653 | { 2654 | case 0: 2655 | buff[0] |= 1 << (pin - 1); 2656 | buff[1] &= ~(1 << (pin - 1)); 2657 | buff[2] &= ~(1 << (pin - 1)); 2658 | break; 2659 | case 1: 2660 | buff[1] |= 1 << (pin - 1); 2661 | buff[0] &= ~(1 << (pin - 1)); 2662 | buff[2] &= ~(1 << (pin - 1)); 2663 | break; 2664 | case 2: 2665 | buff[2] |= 1 << (pin - 1); 2666 | buff[1] &= ~(1 << (pin - 1)); 2667 | buff[0] &= ~(1 << (pin - 1)); 2668 | break; 2669 | default: 2670 | printf("Invalid input type (0->0-10V; 1->1K; 2->10k)!\n"); 2671 | exit(1); 2672 | break; 2673 | } 2674 | 2675 | resp = i2cMem8Write(dev, I2C_MEM_UIN_SEL, buff, 3); 2676 | if (FAIL == resp) 2677 | { 2678 | printf("Fail to write tconfiguration\n"); 2679 | exit(1); 2680 | } 2681 | 2682 | return OK; 2683 | } 2684 | 2685 | 2686 | int doInCfgRead(int argc, char *argv[]); 2687 | const CliCmdType CMD_IN_CONFIG_READ = 2688 | {"incfgrd", 2, &doInCfgRead, 2689 | "\tincfgrd: Display input type 0-10V(0); 1k Thermistor(1) or 10k Thermistor(2)\n", 2690 | "\tUsage: megabas incfgrd \n", 2691 | "", 2692 | "\tExample: megabas 0 incfgrd 2; Display channel #2 on Board #0 input type\n" 2693 | }; 2694 | 2695 | int doInCfgRead(int argc, char *argv[]) 2696 | { 2697 | int pin = 0; 2698 | int dev = 0; 2699 | int resp = 0; 2700 | uint8_t buff[3]; 2701 | 2702 | 2703 | if ( argc != 4) 2704 | { 2705 | printf("%s", CMD_IN_CONFIG_READ.usage1); 2706 | exit(1); 2707 | } 2708 | 2709 | dev = doBoardInit(atoi(argv[1])); 2710 | if (dev <= 0) 2711 | { 2712 | exit(1); 2713 | } 2714 | 2715 | pin = atoi(argv[3]); 2716 | if ( (pin < CHANNEL_NR_MIN) || (pin > ADC_CH_NR_MAX)) 2717 | { 2718 | printf("Input channel number value out of range\n"); 2719 | exit(1); 2720 | } 2721 | 2722 | 2723 | resp = i2cMem8Read(dev, I2C_MEM_UIN_SEL, buff, 3); 2724 | if (FAIL == resp) 2725 | { 2726 | printf("Fail to read config!\n"); 2727 | return ERROR; 2728 | } 2729 | if(0 != (buff[0] & (1 << (pin - 1)))) 2730 | { 2731 | printf("0\n"); 2732 | } 2733 | else if(0 != (buff[1] & (1 << (pin - 1)))) 2734 | { 2735 | printf("1\n"); 2736 | } 2737 | else if(0 != (buff[2] & (1 << (pin - 1)))) 2738 | { 2739 | printf("2\n"); 2740 | } 2741 | else 2742 | { 2743 | printf("Invalid configuration detected!\n"); 2744 | } 2745 | return OK; 2746 | } 2747 | 2748 | 2749 | const CliCmdType *gCmdArray[] = {&CMD_VERSION, &CMD_HELP, &CMD_WAR, &CMD_LIST, 2750 | &CMD_BOARD, &CMD_RESET, &CMD_TRIAC_WRITE, &CMD_TRIAC_READ, &CMD_TEST, &CMD_CONTACT_READ, 2751 | &CMD_COUNTER_READ, &CMD_COUNTER_RST, &CMD_EDGE_READ, &CMD_EDGE_WRITE, 2752 | &CMD_DAC_READ, &CMD_DAC_WRITE, &CMD_ADC_READ, &CMD_R1K_READ, &CMD_R10K_READ, 2753 | &CMD_ADC_CAL, &CMD_ADC_CAL_RST, &CMD_DAC_CAL, &CMD_DAC_CAL_RST, 2754 | &CMD_WDT_RELOAD, &CMD_WDT_SET_PERIOD, &CMD_WDT_GET_PERIOD, 2755 | &CMD_WDT_SET_INIT_PERIOD, &CMD_WDT_GET_INIT_PERIOD, &CMD_WDT_SET_OFF_PERIOD, 2756 | &CMD_WDT_GET_OFF_PERIOD, &CMD_RS485_READ, &CMD_RS485_WRITE, &CMD_RTC_GET, 2757 | &CMD_RTC_SET, &CMD_OWB_RD, &CMD_OWB_ID_RD, &CMD_OWB_SNS_CNT_RD, 2758 | &CMD_OWB_SCAN,&CMD_EXTI_READ, &CMD_EXTI_WRITE, &CMD_BUTTON_READ,&CMD_IN_CONFIG_WRITE,&CMD_IN_CONFIG_READ, 2759 | NULL}; //null terminated array of cli structure pointers 2760 | 2761 | int main(int argc, char *argv[]) 2762 | { 2763 | int i = 0; 2764 | int ret = OK; 2765 | 2766 | if (argc == 1) 2767 | { 2768 | usage(); 2769 | return -1; 2770 | } 2771 | while (NULL != gCmdArray[i]) 2772 | { 2773 | if ( (gCmdArray[i]->name != NULL) && (gCmdArray[i]->namePos < argc)) 2774 | { 2775 | if (strcasecmp(argv[gCmdArray[i]->namePos], gCmdArray[i]->name) == 0) 2776 | { 2777 | ret = gCmdArray[i]->pFunc(argc, argv); 2778 | if (ARG_CNT_ERR == ret) 2779 | { 2780 | printf("Invalid parameters number!\n"); 2781 | printf("%s", gCmdArray[i]->usage1); 2782 | if (strlen(gCmdArray[i]->usage2) > 2) 2783 | { 2784 | printf("%s", gCmdArray[i]->usage2); 2785 | } 2786 | } 2787 | else if (COMM_ERR == ret) 2788 | { 2789 | printf("Unable to communicate with the card!\n"); 2790 | } 2791 | return ret; 2792 | } 2793 | } 2794 | i++; 2795 | } 2796 | printf("Invalid command option\n"); 2797 | usage(); 2798 | 2799 | return -1; 2800 | } 2801 | -------------------------------------------------------------------------------- /src/megabas.h: -------------------------------------------------------------------------------- 1 | #ifndef RELAY8_H_ 2 | #define RELAY8_H_ 3 | 4 | #include 5 | 6 | #define ADC_CH_NO 8 7 | #define DAC_CH_NO 4 8 | #define ADC_RAW_VAL_SIZE 2 9 | #define DAC_MV_VAL_SIZE 2 10 | #define VOLT_TO_MILIVOLT 1000 11 | #define OPTO_CH_NO 8 12 | #define GPIO_CH_NO 4 13 | #define COUNTER_SIZE 4 14 | #define DRY_CONTACT_COUNT 8 15 | #define DRY_CONTACT_CONTOR_SIZE 4 16 | 17 | #define RETRY_TIMES 10 18 | #define CALIBRATION_KEY 0xaa 19 | #define RESET_CALIBRATION_KEY 0x55 20 | #define WDT_RESET_SIGNATURE 0xCA 21 | #define WDT_MAX_OFF_INTERVAL_S 4147200 //48 days 22 | 23 | #define OWB_SENS_CNT 16 24 | #define OWB_TEMP_SIZE_B 2 25 | 26 | enum 27 | { 28 | I2C_TRIACS_VAL_ADD = 0, 29 | I2C_TRIACS_SET_ADD, 30 | I2C_TRIACS_CLR_ADD, 31 | I2C_DRY_CONTACT_VAL_ADD, 32 | 33 | I2C_U0_10_OUT_VAL1_ADD, 34 | SPARE9, 35 | I2C_U0_10_OUT_VAL2_ADD, 36 | SPARE10, 37 | I2C_U0_10_OUT_VAL3_ADD, 38 | SPARE11, 39 | I2C_U0_10_OUT_VAL4_ADD, 40 | SPARE12, 41 | I2C_U0_10_IN_VAL1_ADD, 42 | SPARE17, 43 | I2C_U0_10_IN_VAL2_ADD, 44 | SPARE18, 45 | I2C_U0_10_IN_VAL3_ADD, 46 | SPARE19, 47 | I2C_U0_10_IN_VAL4_ADD, 48 | SPARE20, 49 | I2C_U0_10_IN_VAL5_ADD, 50 | SPARE1, 51 | I2C_U0_10_IN_VAL6_ADD, 52 | SPARE2, 53 | I2C_U0_10_IN_VAL7_ADD, 54 | SPARE3, 55 | I2C_U0_10_IN_VAL8_ADD, 56 | SPARE4, 57 | I2C_R_1K_CH1, 58 | SP21, 59 | I2C_R_1K_CH2, 60 | SP22, 61 | I2C_R_1K_CH3, 62 | SP23, 63 | I2C_R_1K_CH4, 64 | SP24, 65 | I2C_R_1K_CH5, 66 | SP31, 67 | I2C_R_1K_CH6, 68 | SP32, 69 | I2C_R_1K_CH7, 70 | SP33, 71 | I2C_R_1K_CH8, 72 | SP34, 73 | I2C_R_10K_CH1, 74 | SP121, 75 | I2C_R_10K_CH2, 76 | SP122, 77 | I2C_R_10K_CH3, 78 | SP123, 79 | I2C_R_10K_CH4, 80 | SP124, 81 | I2C_R_10K_CH5, 82 | SP131, 83 | I2C_R_10K_CH6, 84 | SP132, 85 | I2C_R_10K_CH7, 86 | SP133, 87 | I2C_R_10K_CH8, 88 | SP134, 89 | I2C_MEM_CALIB_VALUE, 90 | I2C_MEM_CALIB_CHANNEL = I2C_MEM_CALIB_VALUE + 2, //0-10V out [1,4]; 0-10V in [5, 12]; R 1K in [13, 20]; R 10K in [21, 28] 91 | I2C_MEM_CALIB_KEY, //set calib point 0xaa; reset calibration on the channel 0x55 92 | I2C_MEM_CALIB_STATUS, 93 | I2C_MODBUS_SETINGS_ADD = 65, 94 | I2C_NBS1, 95 | I2C_MBS2, 96 | I2C_MBS3, 97 | I2C_MODBUS_ID_OFFSET_ADD, 98 | I2C_RTC_YEAR_ADD, 99 | I2C_RTC_MONTH_ADD, 100 | I2C_RTC_DAY_ADD, 101 | I2C_RTC_HOUR_ADD, 102 | I2C_RTC_MINUTE_ADD, 103 | I2C_RTC_SECOND_ADD, 104 | I2C_RTC_SET_YEAR_ADD, 105 | I2C_RTC_SET_MONTH_ADD, 106 | I2C_RTC_SET_DAY_ADD, 107 | I2C_RTC_SET_HOUR_ADD, 108 | I2C_RTC_SET_MINUTE_ADD, 109 | I2C_RTC_SET_SECOND_ADD, 110 | I2C_RTC_CMD_ADD, 111 | I2C_MEM_WDT_RESET_ADD, 112 | I2C_MEM_WDT_INTERVAL_SET_ADD, 113 | I2C_MEM_WDT_INTERVAL_GET_ADD = I2C_MEM_WDT_INTERVAL_SET_ADD + 2, 114 | I2C_MEM_WDT_INIT_INTERVAL_SET_ADD = I2C_MEM_WDT_INTERVAL_GET_ADD + 2, 115 | I2C_MEM_WDT_INIT_INTERVAL_GET_ADD = I2C_MEM_WDT_INIT_INTERVAL_SET_ADD + 2, 116 | I2C_MEM_WDT_RESET_COUNT_ADD = I2C_MEM_WDT_INIT_INTERVAL_GET_ADD + 2, 117 | I2C_MEM_WDT_CLEAR_RESET_COUNT_ADD = I2C_MEM_WDT_RESET_COUNT_ADD + 2, 118 | I2C_MEM_WDT_POWER_OFF_INTERVAL_SET_ADD, 119 | I2C_MEM_WDT_POWER_OFF_INTERVAL_GET_ADD = I2C_MEM_WDT_POWER_OFF_INTERVAL_SET_ADD 120 | + 4, 121 | I2C_MEM_DRY_CONTACT_RISING_ENABLE = I2C_MEM_WDT_POWER_OFF_INTERVAL_GET_ADD 122 | + 4, 123 | I2C_MEM_DRY_CONTACT_FALLING_ENABLE, 124 | I2C_MEM_DRY_CONTACT_CH_CONT_RESET, 125 | I2C_DIAG_TEMPERATURE_MEM_ADD = 0x72, 126 | I2C_DIAG_24V_MEM_ADD, 127 | I2C_DIAG_24V_MEM_ADD1, 128 | I2C_DIAG_5V_MEM_ADD, 129 | I2C_DIAG_5V_MEM_ADD1, 130 | I2C_CAN_REC_MPS_MEM_ADD, 131 | I2C_REVISION_HW_MAJOR_MEM_ADD = 0x78, 132 | I2C_REVISION_HW_MINOR_MEM_ADD, 133 | I2C_REVISION_MAJOR_MEM_ADD, 134 | I2C_REVISION_MINOR_MEM_ADD, 135 | I2C_BUILD_DAY_MEM_ADD, 136 | I2C_BUILD_MOTH_MEM_ADD, 137 | I2C_BUILD_YEAR_MEM_ADD, 138 | I2C_BOARD_TYPE_MEM_ADD, 139 | I2C_MEM_DRY_CONTACT_CONTORS, 140 | I2C_MEM_DRY_CONTACT_CONTROL_END = 1 + I2C_MEM_DRY_CONTACT_CONTORS 141 | + DRY_CONTACT_COUNT * DRY_CONTACT_CONTOR_SIZE, 142 | I2C_MEM_1WB_DEV = I2C_MEM_DRY_CONTACT_CONTROL_END, 143 | I2C_MEM_1WB_TEMP_ALL, 144 | I2C_EXT_INT_OUT_ENABLE = I2C_MEM_1WB_TEMP_ALL + 2, 145 | I2C_EXT_INT_OUT_FLAGS = I2C_EXT_INT_OUT_ENABLE+ 2, 146 | I2C_BUTTON_STATE = I2C_EXT_INT_OUT_FLAGS + 2, 147 | 148 | I2C_MEM_CPU_RESET = 0xaa, 149 | I2C_MEM_HSI_LO, 150 | I2C_MEM_HSI_HI, 151 | I2C_MEM_1WB_START_SEARCH, 152 | I2C_MEM_1WB_T1, 153 | I2C_MEM_1WB_T16_END =I2C_MEM_1WB_T1 + OWB_SENS_CNT * OWB_TEMP_SIZE_B - 1, 154 | I2C_MEM_1WB_ROM_CODE_IDX = I2C_MEM_1WB_T1 + OWB_SENS_CNT * OWB_TEMP_SIZE_B, 155 | I2C_MEM_1WB_ROM_CODE,//rom code 64 bits 156 | I2C_MEM_1WB_ROM_CODE_END = I2C_MEM_1WB_ROM_CODE + 7, 157 | I2C_MEM_UIN_SEL, 158 | I2C_MEM_1K_SEL, 159 | I2C_MEM_10K_SEL, 160 | 161 | SLAVE_BUFF_SIZE = 255 162 | }; 163 | 164 | enum CAL_CH_START_ID{ 165 | CAL_0_10V_OUT_START_ID = 1, 166 | CAL_0_10V_OUT_STOP_ID = 4, 167 | CAL_0_10V_IN_START_ID, 168 | CAL_0_10V_IN_STOP_ID = 12, 169 | CAL_1K_IN_START_ID, 170 | CAL_1K_IN_STOP_ID = 20, 171 | CAL_10K_IN_START_ID, 172 | CAL_10K_IN_STOP_ID = 28 173 | 174 | }; 175 | 176 | 177 | #define CHANNEL_NR_MIN 1 178 | #define TRIAC_CH_NR_MAX 8 179 | 180 | #define CONTACT_CH_NR_MAX 8 181 | #define OD_CH_NR_MAX 4 182 | #define DAC_CH_NR_MAX 4 183 | #define ADC_CH_NR_MAX 8 184 | 185 | #define OD_PWM_VAL_MAX 10000 186 | 187 | #define ERROR -1 188 | #define OK 0 189 | #define FAIL -1 190 | #define ARG_CNT_ERR -3 191 | #define COMM_ERR -4 192 | 193 | #define SLAVE_OWN_ADDRESS_BASE 0x48 194 | 195 | typedef uint8_t u8; 196 | typedef uint16_t u16; 197 | typedef uint32_t u32; 198 | 199 | typedef enum 200 | { 201 | OFF = 0, 202 | ON, 203 | STATE_COUNT 204 | } OutStateEnumType; 205 | 206 | typedef struct 207 | { 208 | const char* name; 209 | const int namePos; 210 | int(*pFunc)(int, char**); 211 | const char* help; 212 | const char* usage1; 213 | const char* usage2; 214 | const char* example; 215 | }CliCmdType; 216 | 217 | typedef struct 218 | __attribute__((packed)) 219 | { 220 | unsigned int mbBaud :24; 221 | unsigned int mbType :4; 222 | unsigned int mbParity :2; 223 | unsigned int mbStopB :2; 224 | unsigned int add:8; 225 | } ModbusSetingsType; 226 | const CliCmdType* gCmdArray[]; 227 | #endif //RELAY8_H_ 228 | -------------------------------------------------------------------------------- /src/thread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "thread.h" 7 | 8 | 9 | static pthread_mutex_t piMutexes [4]; 10 | 11 | int piHiPri (const int pri); 12 | int piThreadCreate (void *(*fn)(void *)); 13 | static volatile int globalResponse = 0; 14 | 15 | PI_THREAD (waitForKey) 16 | { 17 | char resp; 18 | int respI = NO; 19 | 20 | 21 | struct termios info; 22 | tcgetattr(0, &info); /* get current terminal attirbutes; 0 is the file descriptor for stdin */ 23 | info.c_lflag &= ~ICANON; /* disable canonical mode */ 24 | info.c_cc[VMIN] = 1; /* wait until at least one keystroke available */ 25 | info.c_cc[VTIME] = 0; /* no timeout */ 26 | tcsetattr(0, TCSANOW, &info); /* set i */ 27 | 28 | (void)piHiPri (10) ; // Set this thread to be high priority 29 | resp = getchar(); 30 | if((resp == 'y')||(resp == 'Y')) 31 | { 32 | respI = YES; 33 | } 34 | 35 | pthread_mutex_lock(&piMutexes[COUNT_KEY]); 36 | globalResponse = respI; 37 | pthread_mutex_unlock(&piMutexes[COUNT_KEY]); 38 | 39 | info.c_lflag |= ICANON; /* disable canonical mode */ 40 | info.c_cc[VMIN] = 0; /* wait until at least one keystroke available */ 41 | info.c_cc[VTIME] = 0; /* no timeout */ 42 | tcsetattr(0, TCSANOW, &info); /* set i */ 43 | printf("\n"); 44 | return &waitForKey; 45 | } 46 | 47 | /* 48 | * upHiPri: 49 | * Attempt to set a high priority scheduling for the running program 50 | ********************************************************************************* 51 | */ 52 | 53 | int piHiPri (const int pri) 54 | { 55 | struct sched_param sched ; 56 | 57 | memset (&sched, 0, sizeof(sched)) ; 58 | 59 | if (pri > sched_get_priority_max (SCHED_RR)) 60 | sched.sched_priority = sched_get_priority_max (SCHED_RR) ; 61 | else 62 | sched.sched_priority = pri ; 63 | 64 | return sched_setscheduler (0, SCHED_RR, &sched) ; 65 | } 66 | 67 | /* 68 | * upThreadCreate: 69 | * Create and start a thread 70 | ********************************************************************************* 71 | */ 72 | 73 | int piThreadCreate (void *(*fn)(void *)) 74 | { 75 | pthread_t myThread ; 76 | 77 | return pthread_create (&myThread, NULL, fn, NULL) ; 78 | } 79 | 80 | void startThread(void) 81 | { 82 | piThreadCreate(waitForKey); 83 | } 84 | 85 | int checkThreadResult(void) 86 | { 87 | int res; 88 | pthread_mutex_lock(&piMutexes[COUNT_KEY]); 89 | res = globalResponse; 90 | pthread_mutex_unlock(&piMutexes[COUNT_KEY]); 91 | return res; 92 | } 93 | 94 | /* 95 | * busyWait: 96 | * Wait for some number of milliseconds 97 | ********************************************************************************* 98 | */ 99 | 100 | void busyWait(int ms) 101 | { 102 | struct timespec sleeper, dummy ; 103 | 104 | sleeper.tv_sec = (time_t)(ms / 1000) ; 105 | sleeper.tv_nsec = (long)(ms % 1000) * 1000000 ; 106 | 107 | nanosleep (&sleeper, &dummy) ; 108 | } 109 | -------------------------------------------------------------------------------- /src/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef _THREAD_H_ 2 | #define _THREAD_H_ 3 | 4 | #define COUNT_KEY 0 5 | #define YES 1 6 | #define NO 2 7 | #define UNU __attribute__((unused)) 8 | 9 | #define PI_THREAD(X) void *X (UNU void *dummy) 10 | 11 | 12 | void busyWait(int ms); 13 | void startThread(void); 14 | int checkThreadResult(void); 15 | 16 | #endif -------------------------------------------------------------------------------- /update/README.md: -------------------------------------------------------------------------------- 1 | # update 2 | 3 | This is the [Sequent Microsystems](https://www.sequentmicrosystems.com) Building automation systems board firmware update tool. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | ~$ git clone https://github.com/SequentMicrosystems/megabas-rpi.git 9 | ~$ cd megabas-rpi/update/ 10 | ~/megabas-rpi/update$ ./update 0 11 | ``` 12 | 13 | For Ubuntu users, do the following: 14 | ```bash 15 | ~$ git clone https://github.com/SequentMicrosystems/megabas-rpi.git 16 | ~$ cd megabas-rpi/update/ubuntu/ 17 | ~/megabas-rpi/update/ubuntu$ sudo ./update64 0 18 | ``` 19 | 20 | For 64-bit Linux users, do the following: 21 | ```bash 22 | ~$ git clone https://github.com/SequentMicrosystems/megabas-rpi.git 23 | ~$ cd megabas-rpi/update/ 24 | ~/megabas-rpi/update$ sudo ./update64 0 25 | ``` 26 | 27 | If you clone the repository, skip the first step. 28 | The command will download the newest firmware version from our server and write it to the board. 29 | The stack level of the board must be provided as a parameter. 30 | Make sure no one (Python scripts, or sell scripts, or Node-RED flow) tries to access the card during the update process. 31 | During firmware update, we strongly recommend disconnecting all outputs from the board since they can change state unpredictably. 32 | 33 | 34 | -------------------------------------------------------------------------------- /update/fwrevhist.md: -------------------------------------------------------------------------------- 1 | # MEGA-BAS Firmware revision history 2 | 3 | ## 1.01 Initial release 4 | All basic I/O functionality implemented 5 | 6 | ## 1.03 7 | Add calibration method for ADC and DAC. 8 | 9 | Add watchdog functionality. 10 | 11 | Add RS485 settings 12 | 13 | Add dry contact contors 14 | 15 | ## 1.04 16 | RTC routines 17 | 18 | ## 1.05 19 | Modbus access on dry contact counters and edge selection 20 | Minor Modbus debug 21 | 22 | -------------------------------------------------------------------------------- /update/update: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/update/update -------------------------------------------------------------------------------- /update/update64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SequentMicrosystems/megabas-rpi/2db14eea074f8547d518c4651dab1ac216a70d10/update/update64 --------------------------------------------------------------------------------