From 7b98c2081aa50a50123af6704702ce8315e6c93a Mon Sep 17 00:00:00 2001 From: Katya Date: Wed, 29 Nov 2023 13:41:19 +0300 Subject: [PATCH] add master --- idiBusMaster/.gitignore | 4 + .../ArduinoIdiBusSketch.ino | 103 +++ .../IdiBusCallbackInterface.h | 29 + .../IdiBusInterruptsDisable.h | 18 + .../IdiBusInterruptsList.cpp | 65 ++ .../IdiBusInterruptsList.h | 48 + .../_lib/IdiBusLib/IdiBusDateTime.cpp | 57 ++ .../_lib/IdiBusLib/IdiBusDateTime.h | 32 + .../_lib/IdiBusLib/IdiBusMes.cpp | 128 +++ .../IdiBus_Arduino/_lib/IdiBusLib/IdiBusMes.h | 50 + .../_lib/IdiBusLib/IdiBusSerial.cpp | 621 +++++++++++++ .../_lib/IdiBusLib/IdiBusSerial.h | 123 +++ .../_lib/IdiBusLib/IdiBusSerialDefs.h | 138 +++ .../_lib/IdiBusLib/IdiBusSerialLine.cpp | 122 +++ .../_lib/IdiBusLib/IdiBusSerialLine.h | 17 + .../_lib/IdiBusLib/IdiBusSlave.cpp | 349 +++++++ .../_lib/IdiBusLib/IdiBusSlave.h | 121 +++ .../_lib/IdiBusLib/IdiBusSystem.h | 25 + .../_lib/IdiBusLib/IdibusDefs.h | 446 +++++++++ .../_lib/IdiBusLib/MODBUS_CRC.cpp | 134 +++ .../_lib/IdiBusLib/MODBUS_CRC.h | 20 + .../_lib/IdiBusSlaves/IDIBUS_4DC.cpp | 663 ++++++++++++++ .../_lib/IdiBusSlaves/IDIBUS_4DC.h | 178 ++++ .../1xGenTest/1xGenTest.componentinfo.xml | 86 ++ .../IdiBus_Master/1xGenTest/1xGenTest.cppproj | 161 ++++ .../IdiBus_Master/1xGenTest/main.cpp | 150 +++ .../IdiBus_Master/IDIBUS_MASTER.atsln | 28 + .../ArduinoCore/ArduinoCore.componentinfo.xml | 86 ++ .../ArduinoCore/ArduinoCore.cppproj | 395 ++++++++ .../ArduinoCore/include/core/Arduino.h | 260 ++++++ .../ArduinoCore/include/core/Client.h | 45 + .../ArduinoCore/include/core/HardwareSerial.h | 161 ++++ .../include/core/HardwareSerial_private.h | 123 +++ .../ArduinoCore/include/core/IPAddress.h | 78 ++ .../ArduinoCore/include/core/PluggableUSB.h | 74 ++ .../ArduinoCore/include/core/Print.h | 93 ++ .../ArduinoCore/include/core/Printable.h | 40 + .../ArduinoCore/include/core/Server.h | 30 + .../ArduinoCore/include/core/Stream.h | 129 +++ .../ArduinoCore/include/core/USBAPI.h | 209 +++++ .../ArduinoCore/include/core/USBCore.h | 304 ++++++ .../ArduinoCore/include/core/USBDesc.h | 46 + .../ArduinoCore/include/core/Udp.h | 89 ++ .../ArduinoCore/include/core/WCharacter.h | 168 ++++ .../ArduinoCore/include/core/WString.h | 229 +++++ .../ArduinoCore/include/core/binary.h | 534 +++++++++++ .../ArduinoCore/include/core/new.h | 31 + .../ArduinoCore/include/core/wiring_private.h | 72 ++ .../include/variants/mega/pins_arduino.h | 413 +++++++++ .../IDIBUS_MASTER/ArduinoCore/library.cpp | 16 + .../ArduinoCore/src/core/CDC.cpp | 302 ++++++ .../ArduinoCore/src/core/HardwareSerial.cpp | 281 ++++++ .../ArduinoCore/src/core/HardwareSerial0.cpp | 79 ++ .../ArduinoCore/src/core/HardwareSerial1.cpp | 69 ++ .../ArduinoCore/src/core/HardwareSerial2.cpp | 57 ++ .../ArduinoCore/src/core/HardwareSerial3.cpp | 57 ++ .../ArduinoCore/src/core/IPAddress.cpp | 114 +++ .../ArduinoCore/src/core/PluggableUSB.cpp | 115 +++ .../core/PreprocessingAssembly/wiring_pulse.S | 178 ++++ .../ArduinoCore/src/core/Print.cpp | 266 ++++++ .../ArduinoCore/src/core/Stream.cpp | 318 +++++++ .../ArduinoCore/src/core/Tone.cpp | 619 +++++++++++++ .../ArduinoCore/src/core/USBCore.cpp | 863 ++++++++++++++++++ .../ArduinoCore/src/core/WInterrupts.c | 379 ++++++++ .../ArduinoCore/src/core/WMath.cpp | 58 ++ .../ArduinoCore/src/core/WString.cpp | 750 +++++++++++++++ .../ArduinoCore/src/core/abi.cpp | 35 + .../ArduinoCore/src/core/hooks.c | 31 + .../ArduinoCore/src/core/main.cpp | 52 ++ .../ArduinoCore/src/core/new.cpp | 41 + .../ArduinoCore/src/core/wiring.c | 392 ++++++++ .../ArduinoCore/src/core/wiring_analog.c | 294 ++++++ .../ArduinoCore/src/core/wiring_digital.c | 179 ++++ .../ArduinoCore/src/core/wiring_pulse.c | 93 ++ .../ArduinoCore/src/core/wiring_shift.c | 56 ++ .../IdiBus_Master/1xGen_Test.cpp | 0 .../IdiBusCallbackInterface.h | 29 + .../IdiBusInterruptsDisable.h | 18 + .../IdiBusInterruptsList.cpp | 65 ++ .../IdiBusInterruptsList.h | 48 + .../IdiBusLib/IdiBusDateTime.cpp | 57 ++ .../IdiBus_Master/IdiBusLib/IdiBusDateTime.h | 32 + .../IdiBus_Master/IdiBusLib/IdiBusMes.cpp | 128 +++ .../IdiBus_Master/IdiBusLib/IdiBusMes.h | 50 + .../IdiBus_Master/IdiBusLib/IdiBusSerial.cpp | 621 +++++++++++++ .../IdiBus_Master/IdiBusLib/IdiBusSerial.h | 123 +++ .../IdiBusLib/IdiBusSerialDefs.h | 138 +++ .../IdiBusLib/IdiBusSerialLine.cpp | 122 +++ .../IdiBusLib/IdiBusSerialLine.h | 17 + .../IdiBus_Master/IdiBusLib/IdiBusSlave.cpp | 351 +++++++ .../IdiBus_Master/IdiBusLib/IdiBusSlave.h | 122 +++ .../IdiBus_Master/IdiBusLib/IdiBusSystem.h | 25 + .../IdiBus_Master/IdiBusLib/IdibusDefs.h | 446 +++++++++ .../IdiBus_Master/IdiBusLib/MODBUS_CRC.cpp | 134 +++ .../IdiBus_Master/IdiBusLib/MODBUS_CRC.h | 20 + .../IdiBusSlaves/IDIBUS_1Wire.cpp | 157 ++++ .../IdiBus_Master/IdiBusSlaves/IDIBUS_1Wire.h | 51 ++ .../IdiBusSlaves/IDIBUS_1xGen.cpp | 52 ++ .../IdiBus_Master/IdiBusSlaves/IDIBUS_1xGen.h | 47 + .../IdiBusSlaves/IDIBUS_2SALTMETER.cpp | 160 ++++ .../IdiBusSlaves/IDIBUS_2SALTMETER.h | 51 ++ .../IdiBusSlaves/IDIBUS_3Thermo1HT.cpp | 250 +++++ .../IdiBusSlaves/IDIBUS_3Thermo1HT.h | 68 ++ .../IdiBusSlaves/IDIBUS_4ADC.cpp | 109 +++ .../IdiBus_Master/IdiBusSlaves/IDIBUS_4ADC.h | 46 + .../IdiBusSlaves/IDIBUS_4CNT.cpp | 131 +++ .../IdiBus_Master/IdiBusSlaves/IDIBUS_4CNT.h | 44 + .../IdiBusSlaves/IDIBUS_4CNTtoPWM.cpp | 158 ++++ .../IdiBusSlaves/IDIBUS_4CNTtoPWM.h | 46 + .../IdiBus_Master/IdiBusSlaves/IDIBUS_4DC.cpp | 663 ++++++++++++++ .../IdiBus_Master/IdiBusSlaves/IDIBUS_4DC.h | 178 ++++ .../IdiBus_Master/IdiBusSlaves/IDIBUS_CO2.cpp | 81 ++ .../IdiBus_Master/IdiBusSlaves/IDIBUS_CO2.h | 41 + .../IdiBusSlaves/IDIBUS_NEXTION.cpp | 52 ++ .../IdiBusSlaves/IDIBUS_NEXTION.h | 31 + .../IdiBusSlaves/IDIBUS_Speedster.cpp | 81 ++ .../IdiBusSlaves/IDIBUS_Speedster.h | 38 + .../IdiBus_Master/MBOARD_POWER.c | 66 ++ .../IdiBus_Master/MBOARD_POWER.h | 29 + .../IDIBUS_MASTER/IdiBus_Master/PID.cpp | 27 + .../IDIBUS_MASTER/IdiBus_Master/PID.h | 25 + .../IDIBUS_MASTER/IdiBus_Master/Sketch.cpp | 311 +++++++ .../IdiBus_Master/SketchBack.cpp | 299 ++++++ .../IDIBUS_MASTER/IdiBus_Master/SketchCO2.cpp | 216 +++++ .../IdiBus_Master/SketchSalt.cpp | 296 ++++++ .../IdiBus_Master/SketchSpeedster.cpp | 219 +++++ .../idiBus_Master.componentinfo.xml | 86 ++ .../IdiBus_Master/idiBus_Master.cppproj | 421 +++++++++ .../IdiBus_Master/IdiBusMaster.pdf | Bin 0 -> 316534 bytes .../IdiBus_Master/Sketch — копия.cpp | 9 + .../idiBus_MasterLib/IdiBus_Master/Sketch.cpp | 9 + .../IdiBus_Master/SketchCO2.cpp | 9 + .../idiBus_MasterLib/v0.26 | 1 + 133 files changed, 20323 insertions(+) create mode 100644 idiBusMaster/.gitignore create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/ArduinoIdiBusSketch/ArduinoIdiBusSketch.ino create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusCallbackInterface.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsDisable.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsList.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsList.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusDateTime.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusDateTime.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusMes.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusMes.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerial.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerial.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialDefs.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialLine.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialLine.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSlave.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSlave.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSystem.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdibusDefs.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/MODBUS_CRC.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/MODBUS_CRC.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusSlaves/IDIBUS_4DC.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusSlaves/IDIBUS_4DC.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/1xGenTest.componentinfo.xml create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/1xGenTest.cppproj create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/main.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER.atsln create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/ArduinoCore.componentinfo.xml create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/ArduinoCore.cppproj create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Arduino.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Client.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/HardwareSerial.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/HardwareSerial_private.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/IPAddress.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/PluggableUSB.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Print.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Printable.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Server.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Stream.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBAPI.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBCore.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBDesc.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Udp.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/WCharacter.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/WString.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/binary.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/new.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/wiring_private.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/variants/mega/pins_arduino.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/library.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/CDC.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial0.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial1.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial2.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial3.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/IPAddress.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/PluggableUSB.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/PreprocessingAssembly/wiring_pulse.S create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Print.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Stream.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Tone.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/USBCore.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/WInterrupts.c create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/WMath.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/WString.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/abi.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/hooks.c create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/main.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/new.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring.c create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_analog.c create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_digital.c create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_pulse.c create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_shift.c create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/1xGen_Test.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusCallbackInterface.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsDisable.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsList.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsList.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusDateTime.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusDateTime.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusMes.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusMes.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerial.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerial.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialDefs.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialLine.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialLine.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSlave.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSlave.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSystem.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdibusDefs.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/MODBUS_CRC.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/MODBUS_CRC.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1Wire.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1Wire.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1xGen.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1xGen.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_2SALTMETER.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_2SALTMETER.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_3Thermo1HT.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_3Thermo1HT.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4ADC.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4ADC.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNT.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNT.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNTtoPWM.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNTtoPWM.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4DC.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4DC.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_CO2.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_CO2.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_NEXTION.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_NEXTION.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_Speedster.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_Speedster.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/MBOARD_POWER.c create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/MBOARD_POWER.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/PID.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/PID.h create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/Sketch.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchBack.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchCO2.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchSalt.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchSpeedster.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/idiBus_Master.componentinfo.xml create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/idiBus_Master.cppproj create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IdiBusMaster.pdf create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/Sketch — копия.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/Sketch.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/SketchCO2.cpp create mode 100644 idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/v0.26 diff --git a/idiBusMaster/.gitignore b/idiBusMaster/.gitignore new file mode 100644 index 0000000..3a5df9d --- /dev/null +++ b/idiBusMaster/.gitignore @@ -0,0 +1,4 @@ +Debug +Release +.vs +desktop.ini diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/ArduinoIdiBusSketch/ArduinoIdiBusSketch.ino b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/ArduinoIdiBusSketch/ArduinoIdiBusSketch.ino new file mode 100644 index 0000000..e2f0ff2 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/ArduinoIdiBusSketch/ArduinoIdiBusSketch.ino @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#ifdef F_CPU +#undef F_CPU +#endif +#define F_CPU 16000000UL +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +#include "IdiBusSerialLine.h" +#include "IDIBUS_4DC.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +//IDIBUS MASTER V0.26 beta + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSerialLine Serial_Line0; +IdiBusSerialLine Serial_Line1; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void setup() +{ + delay(50); //Power on delay for external periphery + //Arduino Variant + IDIBUS_SERIAL_INIT_TYPEDEF L0Init; + L0Init.USART_NUMBER = IDIBUS_SERIAL_USART2; + L0Init.TIMER_NUMBER = IDIBUS_TIMER_1; + L0Init.CONFIG = IDIBUS_SERIAL_8N2; + L0Init.RS485_DIR_PIN = 6; + L0Init.BAUDRATE_DIPSW_S0_PIN = 9; + L0Init.BAUDRATE_DIPSW_S1_PIN = 8; + L0Init.BAUDRATE_DIPSW_S2_PIN = 7; + Serial_Line0.Init(&L0Init); + Serial_Line0.UpdateBaudrateFromDipSwitch(); + Serial_Line0.Start(); + + // Standard pinout variant + IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF L1Init; + L1Init.USART_NUMBER = IDIBUS_SERIAL_USART1; + L1Init.TIMER_NUMBER = IDIBUS_TIMER_3; + L1Init.CONFIG = IDIBUS_SERIAL_8N2; + L1Init.RS485_DIR_GPIO.PORT = &PORTL; + L1Init.RS485_DIR_GPIO.PIN_NUM = 6; + L1Init.BAUDRATE_DIPSW.S0.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S0.PIN_NUM = 1; + L1Init.BAUDRATE_DIPSW.S1.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S1.PIN_NUM = 0; + L1Init.BAUDRATE_DIPSW.S2.PORT = &PORTL; + L1Init.BAUDRATE_DIPSW.S2.PIN_NUM = 7; + Serial_Line1.Init(&L1Init); + Serial_Line1.UpdateBaudrateFromDipSwitch(); + Serial_Line1.Start(); + + Serial.begin(SERIAL_8N2); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +volatile uint8_t ErrorCode[10]; +IdiBusLongOpData LopData; +IdiBus_4DC_INPVChannel INPV_Data; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void loop() +{ + IdiBus_4DC IDB4DC(&Serial_Line1, 122); + /* + //ErrorCode = IDB4DC.c_Init(10); + ErrorCode = IDB4DC.c_Init(); + delay(1000); + ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 0, 10); + ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 2, 10); + + uint8_t TxData; + IdiBusMMESG Group1(IDIBUS_GROUP_10_ADDR, &TxData, 1); + Group1.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + + while (1) + { + Serial.write((uint8_t*)"echo", sizeof("echo")-1); + + TxData = 0; + Serial_Line1.sendMMESG(&Group1); + delay(2000); + TxData = 1; + Serial_Line1.sendMMESG(&Group1); + delay(2000); + }*/ + + ErrorCode[0] = IDB4DC.c_Init(); + delay(1000); + ErrorCode[1] = IDB4DC.c_WriteSnIPv4IPv6(0xAABBCCDD, 0xA1A2A3A4, 0xA5A6A7A8, 0xB1B2B3B4, 0xB5B6B7B8); + do { ErrorCode[2] = IDB4DC.c_CheckModuleLongOp(); } + while ( (LopData = IDB4DC.getModuleLongOpData()).State == IDILONGOP_STATE_IN_PROC ); + + ErrorCode[3] = IDB4DC.INPV_DEV.getInputVoltage(); + INPV_Data = IDB4DC.INPV_DEV.getChData(); + + IDB4DC.PSUC_DEV.setAllChVoltage(5000, 6000, 7000, 8000); + IDB4DC.PSUC_DEV.setAllChState(1); + while (1) + { + IDB4DC.PSUC_DEV.setAllChState(0, 1, 0, 1); + delay(2000); + IDB4DC.PSUC_DEV.setAllChState(1, 0, 1, 0); + delay(2000); + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusCallbackInterface.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusCallbackInterface.h new file mode 100644 index 0000000..8b31dad --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusCallbackInterface.h @@ -0,0 +1,29 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_CALLBACK_INTERFACE_H_ +#define _IDIBUS_CALLBACK_INTERFACE_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusCallbackInterface { + public: + static void USART_Callback_InterruptTX (IdiBusCallbackInterface *inst) { inst->USART_TxInterruptFunc(); } + static void USART_Callback_InterruptRX (IdiBusCallbackInterface *inst) { inst->USART_RxInterruptFunc(); } + static void USART_Callback_InterruptUDRE (IdiBusCallbackInterface *inst) { inst->USART_UdreInterruptFunc(); } + virtual void USART_RxInterruptFunc(void) {} + virtual void USART_TxInterruptFunc(void) {} + virtual void USART_UdreInterruptFunc(void) {} + + static void TIM_Callback_InterruptCOMPA (IdiBusCallbackInterface *inst) { inst->TIM_COMPA_InterruptFunc(); } + static void TIM_Callback_InterruptCOMPB (IdiBusCallbackInterface *inst) { inst->TIM_COMPB_InterruptFunc(); } + static void TIM_Callback_InterruptCOMPC (IdiBusCallbackInterface *inst) { inst->TIM_COMPC_InterruptFunc(); } + static void TIM_Callback_InterruptOVF (IdiBusCallbackInterface *inst) { inst->TIM_OVF_InterruptFunc(); } + virtual void TIM_COMPA_InterruptFunc (void) {} + virtual void TIM_COMPB_InterruptFunc (void) {} + virtual void TIM_COMPC_InterruptFunc (void) {} + virtual void TIM_OVF_InterruptFunc (void) {} + }; + +typedef void (*CallbackTypeFunction)(IdiBusCallbackInterface*); +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_CALLBACK_INTERFACE_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsDisable.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsDisable.h new file mode 100644 index 0000000..627b0d3 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsDisable.h @@ -0,0 +1,18 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_INTERRUPTS_DISABLE_H_ +#define _IDIBUS_INTERRUPTS_DISABLE_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_USART0_ISR_DISABLE +//#define IDIBUS_USART1_ISR_DISABLE +//#define IDIBUS_USART2_ISR_DISABLE +//#define IDIBUS_USART3_ISR_DISABLE + +#define IDIBUS_TIM0_ISR_DISABLE +//#define IDIBUS_TIM1_ISR_DISABLE +//#define IDIBUS_TIM2_ISR_DISABLE +//#define IDIBUS_TIM3_ISR_DISABLE +//#define IDIBUS_TIM4_ISR_DISABLE +//#define IDIBUS_TIM5_ISR_DISABLE +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_INTERRUPTS_DISABLE_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsList.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsList.cpp new file mode 100644 index 0000000..0b9f7c5 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsList.cpp @@ -0,0 +1,65 @@ +//############################################################################################################################################################################################################# +#include "IdiBusInterruptsList.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +struct IDIBUS_INTERRUPT_LISTENERS_STR InterruptListenersList; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#ifndef IDIBUS_USART0_ISR_DISABLE +ISR(USART0_RX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptRX(InterruptListenersList.USART0_CallbackInstance); } +ISR(USART0_TX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptTX(InterruptListenersList.USART0_CallbackInstance); } +ISR(USART0_UDRE_vect) { IdiBusCallbackInterface::USART_Callback_InterruptUDRE(InterruptListenersList.USART0_CallbackInstance); } +#endif +#ifndef IDIBUS_USART1_ISR_DISABLE +ISR(USART1_RX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptRX(InterruptListenersList.USART1_CallbackInstance); } +ISR(USART1_TX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptTX(InterruptListenersList.USART1_CallbackInstance); } +ISR(USART1_UDRE_vect) { IdiBusCallbackInterface::USART_Callback_InterruptUDRE(InterruptListenersList.USART1_CallbackInstance); } +#endif +#ifndef IDIBUS_USART2_ISR_DISABLE +ISR(USART2_RX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptRX(InterruptListenersList.USART2_CallbackInstance); } +ISR(USART2_TX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptTX(InterruptListenersList.USART2_CallbackInstance); } +ISR(USART2_UDRE_vect) { IdiBusCallbackInterface::USART_Callback_InterruptUDRE(InterruptListenersList.USART2_CallbackInstance); } +#endif +#ifndef IDIBUS_USART3_ISR_DISABLE +ISR(USART3_RX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptRX(InterruptListenersList.USART3_CallbackInstance); } +ISR(USART3_TX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptTX(InterruptListenersList.USART3_CallbackInstance); } +ISR(USART3_UDRE_vect) { IdiBusCallbackInterface::USART_Callback_InterruptUDRE(InterruptListenersList.USART3_CallbackInstance); } +#endif +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#ifndef IDIBUS_TIM0_ISR_DISABLE +ISR(TIMER0_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM0_CallbackInstance); } +ISR(TIMER0_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM0_CallbackInstance); } +ISR(TIMER0_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM0_CallbackInstance); } +#endif +#ifndef IDIBUS_TIM1_ISR_DISABLE +ISR(TIMER1_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM1_CallbackInstance); } +ISR(TIMER1_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM1_CallbackInstance); } +ISR(TIMER1_COMPC_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPC(InterruptListenersList.TIM1_CallbackInstance); } +ISR(TIMER1_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM1_CallbackInstance); } +#endif +#ifndef IDIBUS_TIM2_ISR_DISABLE +ISR(TIMER2_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM2_CallbackInstance); } +ISR(TIMER2_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM2_CallbackInstance); } +ISR(TIMER2_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM2_CallbackInstance); } +#endif +#ifndef IDIBUS_TIM3_ISR_DISABLE +ISR(TIMER3_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM3_CallbackInstance); } +ISR(TIMER3_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM3_CallbackInstance); } +ISR(TIMER3_COMPC_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPC(InterruptListenersList.TIM3_CallbackInstance); } +ISR(TIMER3_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM3_CallbackInstance); } +#endif +#ifndef IDIBUS_TIM4_ISR_DISABLE +ISR(TIMER4_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM4_CallbackInstance); } +ISR(TIMER4_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM4_CallbackInstance); } +ISR(TIMER4_COMPC_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPC(InterruptListenersList.TIM4_CallbackInstance); } +ISR(TIMER4_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM4_CallbackInstance); } +#endif +#ifndef IDIBUS_TIM5_ISR_DISABLE +ISR(TIMER5_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM5_CallbackInstance); } +ISR(TIMER5_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM5_CallbackInstance); } +ISR(TIMER5_COMPC_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPC(InterruptListenersList.TIM5_CallbackInstance); } +ISR(TIMER5_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM5_CallbackInstance); } +#endif +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsList.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsList.h new file mode 100644 index 0000000..d660d42 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusComInterrupts/IdiBusInterruptsList.h @@ -0,0 +1,48 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_INTERRUPTS_LIST_H_ +#define _IDIBUS_INTERRUPTS_LIST_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +#include +#include +#include "IdiBusCallbackInterface.h" +#include "IdiBusInterruptsDisable.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +struct IDIBUS_INTERRUPT_LISTENERS_STR { + #ifndef IDIBUS_USART0_ISR_DISABLE + IdiBusCallbackInterface *USART0_CallbackInstance; + #endif + #ifndef IDIBUS_USART1_ISR_DISABLE + IdiBusCallbackInterface *USART1_CallbackInstance; + #endif + #ifndef IDIBUS_USART2_ISR_DISABLE + IdiBusCallbackInterface *USART2_CallbackInstance; + #endif + #ifndef IDIBUS_USART3_ISR_DISABLE + IdiBusCallbackInterface *USART3_CallbackInstance; + #endif + + #ifndef IDIBUS_TIM0_ISR_DISABLE + IdiBusCallbackInterface *TIM0_CallbackInstance; + #endif + #ifndef IDIBUS_TIM1_ISR_DISABLE + IdiBusCallbackInterface *TIM1_CallbackInstance; + #endif + #ifndef IDIBUS_TIM2_ISR_DISABLE + IdiBusCallbackInterface *TIM2_CallbackInstance; + #endif + #ifndef IDIBUS_TIM3_ISR_DISABLE + IdiBusCallbackInterface *TIM3_CallbackInstance; + #endif + #ifndef IDIBUS_TIM4_ISR_DISABLE + IdiBusCallbackInterface *TIM4_CallbackInstance; + #endif + #ifndef IDIBUS_TIM5_ISR_DISABLE + IdiBusCallbackInterface *TIM5_CallbackInstance; + #endif + }; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern struct IDIBUS_INTERRUPT_LISTENERS_STR InterruptListenersList; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //_IDIBUS_INTERRUPTS_LIST_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusDateTime.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusDateTime.cpp new file mode 100644 index 0000000..4685cac --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusDateTime.cpp @@ -0,0 +1,57 @@ +//############################################################################################################################################################################################################# +#include "IdiBusDateTime.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiDateFormat::IdiDateFormat(uint8_t day, uint8_t month, uint8_t century, uint8_t year99) +{ + this->Day = day; + this->Month = month; + this->Century = century; + this->Year99 = year99; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiDateFormat::isValid(void) +{ + if ( (this->Day == 0) || (this->Day > 31) || + (this->Month == 0) || (this->Month > 12) || + (this->Century > 99) || (this->Year99 > 99) ) { return 0; } +return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiDateFormat::getSize(void) { return IDIDATE_FORMAT_LENGTH; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiDateFormat::getBufForMMES(uint8_t *Data) +{ + Data[IDIDATE_FORMAT_DAY_Pos] = this->Day; + Data[IDIDATE_FORMAT_MONTH_Pos] = this->Month; + Data[IDIDATE_FORMAT_CENTURY_Pos] = this->Century; + Data[IDIDATE_FORMAT_YEAR99_Pos] = this->Year99; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +IdiTimeFormat::IdiTimeFormat(uint8_t seconds, uint8_t minutes, uint8_t hours, int8_t timezone) +{ + this->Seconds = seconds; + this->Minutes = minutes; + this->Hours = hours; + this->TimeZone = timezone; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiTimeFormat::isValid(void) +{ + if ( (this->Seconds > 60) || (this->Minutes > 60) || (this->Hours > 23) || + (this->TimeZone < IDITIME_FORMAT_TIMEZONE_MIN) || (this->TimeZone > IDITIME_FORMAT_TIMEZONE_MAX) ) { return 0; } + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiTimeFormat::getSize(void) { return IDITIME_FORMAT_LENGTH; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiTimeFormat::getBufForMMES(uint8_t *Data) +{ + Data[IDITIME_FORMAT_SECONDS_Pos] = this->Seconds; + Data[IDITIME_FORMAT_MINUTES_Pos] = this->Minutes; + Data[IDITIME_FORMAT_HOURS_Pos] = this->Hours; + Data[IDITIME_FORMAT_TIMEZONE_Pos] = (uint8_t)this->TimeZone; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusDateTime.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusDateTime.h new file mode 100644 index 0000000..0bebb1b --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusDateTime.h @@ -0,0 +1,32 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_DATE_TIME_H_ +#define _IDIBUS_DATE_TIME_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiDateFormat { + public: + IdiDateFormat(uint8_t day, uint8_t month, uint8_t century, uint8_t year99); + uint8_t Day; + uint8_t Month; + uint8_t Century; + uint8_t Year99; + uint8_t isValid(void); + uint8_t getSize(void); + void getBufForMMES(uint8_t *Data); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiTimeFormat { + public: + IdiTimeFormat(uint8_t seconds, uint8_t minutes, uint8_t hours, int8_t timezone); + uint8_t Seconds; + uint8_t Minutes; + uint8_t Hours; + int8_t TimeZone; + uint8_t isValid(void); + uint8_t getSize(void); + void getBufForMMES(uint8_t *Data); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_DATE_TIME_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusMes.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusMes.cpp new file mode 100644 index 0000000..af55832 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusMes.cpp @@ -0,0 +1,128 @@ +//############################################################################################################################################################################################################# +#include "IdiBusMes.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMessage::IsGroupAddr(void) { return ( (this->SlAddr >= IDIBUS_GROUP_0_ADDR)&&(this->SlAddr <= IDIBUS_GROUP_15_ADDR) ) ? 1 : 0; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMessage::IsCommand(void) { return ( this->ComFunc >= IDIMMES_COM_START_NUM ) ? 1 : 0; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMessage::IsModuleError(uint8_t ErrCode) { return ((ErrCode >= IDIER_MODULE_NUM_START)&&(ErrCode <= IDIER_MODULE_NUM_END)) ? 1 : 0; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMessage::IsModuleCommand(void) +{ + switch (this->ComFunc) + { + case(IDIMMES_COM_C_Init) : + case(IDIMMES_COM_C_ShtDown) : + case(IDIMMES_COM_C_Freeze) : + case(IDIMMES_COM_C_Resume) : + case(IDIMMES_COM_C_SetAlarmL12) : + case(IDIMMES_COM_C_SetAlarmL) : + case(IDIMMES_COM_C_SyncRead) : + case(IDIMMES_COM_C_SyncDoChnl) : + case(IDIMMES_COM_C_SyncDo) : + case(IDIMMES_COM_C_SyncClear) : + case(IDIMMES_COM_C_SendTimeDate) : + case(IDIMMES_COM_C_MkTimedMaster) : + case(IDIMMES_COM_C_FmwUpd) : + case(IDIMMES_COM_C_EndFmwUpd) : + case(IDIMMES_COM_C_FmwWrite) : + case(IDIMMES_COM_C_ReadDevFullSN_MS) : + case(IDIMMES_COM_C_WriteSnIPv4IPv6) : + case(IDIMMES_COM_C_WriteSnVerifyDates) : + case(IDIMMES_COM_C_WriteSnAES256) : + case(IDIMMES_COM_C_DummyModule) : + case(IDIMMES_COM_C_CheckModuleLongOp) : { return 1; } + default : {} + } + return 0; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +IdiBusMMES::IdiBusMMES (uint8_t SlAddr, uint8_t *TX_DataP, uint16_t TX_DataLength) +{ + this->SlAddr = SlAddr; + this->MMPS.LongMes = 0; + this->MMPS.AlarmMes = 0; + this->MMPS.EncryptedAes = 0; + this->DEV.NUM = 0; + this->DEV.ALLCH = 0; + this->CHNL.ALLSAME = 0; + this->CHNL.NUM = 0; + this->ComFunc = 1; + + this->TxData = TX_DataP; + this->TxDataLength = TX_DataLength; + this->RxData = NULL; + this->RxDataLength = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusMMES::IdiBusMMES (uint8_t SlAddr) +{ + this->SlAddr = SlAddr; + this->MMPS.LongMes = 0; + this->MMPS.AlarmMes = 0; + this->MMPS.EncryptedAes = 0; + this->DEV.NUM = 0; + this->DEV.ALLCH = 0; + this->CHNL.ALLSAME = 0; + this->CHNL.NUM = 0; + this->ComFunc = IDIMMES_COM_C_Dummy; + + this->TxData = NULL; + this->TxDataLength = 0; + this->RxData = NULL; + this->RxDataLength = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMMES::IsValid(void) +{ + if ( (this->ComFunc == 0) || this->IsModuleCommand() || this->IsGroupAddr() ) { return 0; } + return 1; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +IdiBusMMESG::IdiBusMMESG (uint8_t SlAddr, uint8_t *TX_DataP, uint16_t TX_DataLength) +{ + this->SlAddr = SlAddr; + this->MMPS.LongMes = 0; + this->MMPS.AlarmMes = 0; + this->MMPS.EncryptedAes = 0; + this->ComFunc = IDIMMES_COM_C_DummyModule; + + this->TxData = TX_DataP; + this->TxDataLength = TX_DataLength; + this->RxData = NULL; + this->RxDataLength = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusMMESG::IdiBusMMESG (uint8_t SlAddr) +{ + this->SlAddr = SlAddr; + this->MMPS.LongMes = 0; + this->MMPS.AlarmMes = 0; + this->MMPS.EncryptedAes = 0; + this->ComFunc = IDIMMES_COM_C_Dummy; + + this->TxData = NULL; + this->TxDataLength = 0; + this->RxData = NULL; + this->RxDataLength = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMMESG::IsValid(void) +{ + uint8_t isModuleCommand = this->IsModuleCommand(); + uint8_t isGroupAddress = this->IsGroupAddr(); + + if ( this->ComFunc == IDIMMES_NOT_FAST_FUNC ) { return 0; } + if ( isGroupAddress ) + { + if ( isModuleCommand != 0 ) { return 0; } + } + else if ( isModuleCommand == 0 ) { return 0; } + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusMes.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusMes.h new file mode 100644 index 0000000..78a75fc --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusMes.h @@ -0,0 +1,50 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_MES_H_ +#define _IDIBUS_MES_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusMessage { + public : + uint8_t SlAddr; + struct { + uint8_t LongMes : 1; + uint8_t AlarmMes : 1; + uint8_t EncryptedAes : 1; + } MMPS; + uint8_t ComFunc; + uint8_t *TxData; + uint8_t TxDataLength; + uint8_t *RxData; + uint8_t RxDataLength; + + uint8_t IsGroupAddr(void); + uint8_t IsModuleCommand(void); + uint8_t IsCommand(void); + uint8_t IsModuleError(uint8_t ErrCode); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusMMES : public IdiBusMessage { + public : + IdiBusMMES (uint8_t SlAddr, uint8_t *TX_DataP, uint16_t TX_DataLength); + IdiBusMMES (uint8_t SlAddr); + struct { + uint8_t NUM : 5; + uint8_t ALLCH : 1; + } DEV; + struct { + uint8_t NUM : 7; + uint8_t ALLSAME : 1; + } CHNL; + uint8_t IsValid(void); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusMMESG : public IdiBusMessage { + public : + IdiBusMMESG (uint8_t SlAddr, uint8_t *TX_DataP, uint16_t TX_DataLength); + IdiBusMMESG (uint8_t SlAddr); + uint8_t IsValid(void); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_MES_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerial.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerial.cpp new file mode 100644 index 0000000..813dbeb --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerial.cpp @@ -0,0 +1,621 @@ +//############################################################################################################################################################################################################# +#include "IdiBusSerial.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSerial::IdiBusSerial(void) +{ + this->RS485_DIR_GPIO.DDR = (uint8_t*)&this->InitProtectionVar; + this->RS485_DIR_GPIO.PIN = (uint8_t*)&this->InitProtectionVar; + this->RS485_DIR_GPIO.PORT = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S0_Gpio.DDR = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S0_Gpio.PIN = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S0_Gpio.PORT = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S1_Gpio.DDR = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S1_Gpio.PIN = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S1_Gpio.PORT = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S2_Gpio.DDR = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S2_Gpio.PIN = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S2_Gpio.PORT = (uint8_t*)&this->InitProtectionVar; + this->USARTN.UCSRNA = (uint8_t*)&this->InitProtectionVar; + this->USARTN.UCSRNB = (uint8_t*)&this->InitProtectionVar; + this->USARTN.UCSRNC = (uint8_t*)&this->InitProtectionVar; + this->USARTN.UBRRN = (uint16_t*)&this->InitProtectionVar; + this->USARTN.UDRN = (uint8_t*)&this->InitProtectionVar; + this->TIMN.TCCRNA = (uint8_t*)&this->InitProtectionVar; + this->TIMN.TCCRNB = (uint8_t*)&this->InitProtectionVar; + this->TIMN.TIMSKN = (uint8_t*)&this->InitProtectionVar; + this->TIMN.TIFRN = (uint8_t*)&this->InitProtectionVar; + this->TIMN.OCRNA = (uint16_t*)&this->InitProtectionVar; + this->TIMN.OCRNB = (uint16_t*)&this->InitProtectionVar; + this->TIMN.TCNTN = (uint16_t*)&this->InitProtectionVar; + this->InitState = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::Init(IDIBUS_SERIAL_INIT_TYPEDEF *InitT) +{ + if ( (this->GetGpioParamsArduino(InitT->RS485_DIR_PIN, &this->RS485_DIR_GPIO) == 0) || + (this->GetGpioParamsArduino(InitT->BAUDRATE_DIPSW_S0_PIN, &this->BAUDRATE_DIPSW.S0_Gpio) == 0) || + (this->GetGpioParamsArduino(InitT->BAUDRATE_DIPSW_S1_PIN, &this->BAUDRATE_DIPSW.S1_Gpio) == 0) || + (this->GetGpioParamsArduino(InitT->BAUDRATE_DIPSW_S2_PIN, &this->BAUDRATE_DIPSW.S2_Gpio) == 0) ) { return 0; } + + return this->BaseInit(InitT->USART_NUMBER, InitT->TIMER_NUMBER, InitT->CONFIG); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::Init(IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF *InitT) +{ + if ( (this->GetGpioParams(&InitT->RS485_DIR_GPIO, &this->RS485_DIR_GPIO) == 0) || + (this->GetGpioParams(&InitT->BAUDRATE_DIPSW.S0, &this->BAUDRATE_DIPSW.S0_Gpio) == 0) || + (this->GetGpioParams(&InitT->BAUDRATE_DIPSW.S1, &this->BAUDRATE_DIPSW.S1_Gpio) == 0) || + (this->GetGpioParams(&InitT->BAUDRATE_DIPSW.S2, &this->BAUDRATE_DIPSW.S2_Gpio) == 0) ) { return 0; } + + return this->BaseInit(InitT->USART_NUMBER, InitT->TIMER_NUMBER, InitT->CONFIG); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::BaseInit( enum IDIBUS_SERIAL_USARTN_NUMBER USART_NUM, enum IDIBUS_SERIAL_TIMER_NUMBER TIMER_NUM, enum IDIBUS_SERIAL_USARTN_CONFIG CONF) +{ + // Pointers Init + switch (USART_NUM) + { + case (IDIBUS_SERIAL_USART0) : { + #if defined IDIBUS_USART0_ISR_DISABLE + return 0; + #else + this->USARTN.UCSRNA = &(UCSR0A); + this->USARTN.UCSRNB = &(UCSR0B); + this->USARTN.UCSRNC = &(UCSR0C); + this->USARTN.UBRRN = &(UBRR0); + this->USARTN.UDRN = &(UDR0); + InterruptListenersList.USART0_CallbackInstance = this; + #endif + break; } + case (IDIBUS_SERIAL_USART1) : { + #if defined IDIBUS_USART1_ISR_DISABLE + return 0; + #else + this->USARTN.UCSRNA = &(UCSR1A); + this->USARTN.UCSRNB = &(UCSR1B); + this->USARTN.UCSRNC = &(UCSR1C); + this->USARTN.UBRRN = &(UBRR1); + this->USARTN.UDRN = &(UDR1); + InterruptListenersList.USART1_CallbackInstance = this; + #endif + break; } + case (IDIBUS_SERIAL_USART2) : { + #if defined IDIBUS_USART2_ISR_DISABLE + return 0; + #else + this->USARTN.UCSRNA = &(UCSR2A); + this->USARTN.UCSRNB = &(UCSR2B); + this->USARTN.UCSRNC = &(UCSR2C); + this->USARTN.UBRRN = &(UBRR2); + this->USARTN.UDRN = &(UDR2); + InterruptListenersList.USART2_CallbackInstance = this; + #endif + break; } + case (IDIBUS_SERIAL_USART3) : { + #if defined IDIBUS_USART3_ISR_DISABLE + return 0; + #else + this->USARTN.UCSRNA = &(UCSR3A); + this->USARTN.UCSRNB = &(UCSR3B); + this->USARTN.UCSRNC = &(UCSR3C); + this->USARTN.UBRRN = &(UBRR3); + this->USARTN.UDRN = &(UDR3); + InterruptListenersList.USART3_CallbackInstance = this; + #endif + break; } + default : { return 0; } + } + + switch (TIMER_NUM) + { + case (IDIBUS_TIMER_1) : { + #if defined IDIBUS_TIM1_ISR_DISABLE + return 0; + #else + this->TIMN.TCCRNA = &(TCCR1A); + this->TIMN.TCCRNB = &(TCCR1B); + this->TIMN.TIMSKN = &(TIMSK1); + this->TIMN.TIFRN = &(TIFR1); + this->TIMN.OCRNA = &(OCR1A); + this->TIMN.OCRNB = &(OCR1B); + this->TIMN.TCNTN = &(TCNT1); + InterruptListenersList.TIM1_CallbackInstance = this; + #endif + break; } + case (IDIBUS_TIMER_3) : { + #if defined IDIBUS_TIM3_ISR_DISABLE + return 0; + #else + this->TIMN.TCCRNA = &(TCCR3A); + this->TIMN.TCCRNB = &(TCCR3B); + this->TIMN.TIMSKN = &(TIMSK3); + this->TIMN.TIFRN = &(TIFR3); + this->TIMN.OCRNA = &(OCR3A); + this->TIMN.OCRNB = &(OCR3B); + this->TIMN.TCNTN = &(TCNT3); + InterruptListenersList.TIM3_CallbackInstance = this; + #endif + break; } + case (IDIBUS_TIMER_4) : { + #if defined IDIBUS_TIM4_ISR_DISABLE + return 0; + #else + this->TIMN.TCCRNA = &(TCCR4A); + this->TIMN.TCCRNB = &(TCCR4B); + this->TIMN.TIMSKN = &(TIMSK4); + this->TIMN.TIFRN = &(TIFR4); + this->TIMN.OCRNA = &(OCR4A); + this->TIMN.OCRNB = &(OCR4B); + this->TIMN.TCNTN = &(TCNT4); + InterruptListenersList.TIM4_CallbackInstance = this; + #endif + break; } + case (IDIBUS_TIMER_5) : { + #if defined IDIBUS_TIM5_ISR_DISABLE + return 0; + #else + this->TIMN.TCCRNA = &(TCCR5A); + this->TIMN.TCCRNB = &(TCCR5B); + this->TIMN.TIMSKN = &(TIMSK5); + this->TIMN.TIFRN = &(TIFR5); + this->TIMN.OCRNA = &(OCR5A); + this->TIMN.OCRNB = &(OCR5B); + this->TIMN.TCNTN = &(TCNT5); + InterruptListenersList.TIM5_CallbackInstance = this; + #endif + break; } + default : { return 0; } + } + + // GPIO Init + uint8_t SREG_Temp = SREG; + cli(); + *this->RS485_DIR_GPIO.PORT &= ~this->RS485_DIR_GPIO.PIN_MASK; + *this->RS485_DIR_GPIO.DDR |= this->RS485_DIR_GPIO.PIN_MASK; + + *this->BAUDRATE_DIPSW.S0_Gpio.PORT &= ~this->BAUDRATE_DIPSW.S0_Gpio.PIN_MASK; + *this->BAUDRATE_DIPSW.S0_Gpio.DDR &= ~this->BAUDRATE_DIPSW.S0_Gpio.PIN_MASK; + + *this->BAUDRATE_DIPSW.S1_Gpio.PORT &= ~this->BAUDRATE_DIPSW.S1_Gpio.PIN_MASK; + *this->BAUDRATE_DIPSW.S1_Gpio.DDR &= ~this->BAUDRATE_DIPSW.S1_Gpio.PIN_MASK; + + *this->BAUDRATE_DIPSW.S2_Gpio.PORT &= ~this->BAUDRATE_DIPSW.S2_Gpio.PIN_MASK; + *this->BAUDRATE_DIPSW.S2_Gpio.DDR &= ~this->BAUDRATE_DIPSW.S2_Gpio.PIN_MASK; + if ( SREG_Temp & (0x01U << SREG_I) ) { sei(); } + + // USART Init + *this->USARTN.UBRRN = 0; + *this->USARTN.UCSRNA = (1U<USARTN.UCSRNB = 0; + this->BAUDRATE = 0; + switch (CONF) + { + case (IDIBUS_SERIAL_8N1) : { *this->USARTN.UCSRNC = (1U<USARTN.UCSRNC = (1U<USARTN.UCSRNC = (1U<USARTN.UCSRNC = (1U<USARTN.UCSRNC = (1U<USARTN.UCSRNC = (1U<TIMN.TCCRNB = 0; // Counter stop + *this->TIMN.TCCRNA = 0; // Normal Mode + *this->TIMN.TIMSKN = 0; + + this->InitState = 1; + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::SetBaudrate(enum IDIBUS_SERIAL_BAUDRATE Baudrate) +{ + switch ( Baudrate ) + { + case (IDIBUS_BAUDRATE_DSW_CODE_2400B) : { + this->SetBaudrateLL(2400); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_2400B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_2400B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint32_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_9600B) : { + this->SetBaudrateLL(9600); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_9600B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_9600B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint32_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_19200B) : { + this->SetBaudrateLL(19200); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_19200B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_19200B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_115200B) : { + this->SetBaudrateLL(115200); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_115200B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_115200B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_250K) : { + this->SetBaudrateLL(250000); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_250K_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_250K_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_500K) : { + this->SetBaudrateLL(500000); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_500K_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_500K_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_1M) : { + this->SetBaudrateLL(1000000); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_1M_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_1M_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_10M) : { + this->SetBaudrateLL(10000000); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_10M_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_10M_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + default : { return; } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::UpdateBaudrateFromDipSwitch(void) +{ + uint8_t BaudrateCode = 0; + uint32_t BaudrateCodeValue; + if ( (*this->BAUDRATE_DIPSW.S2_Gpio.PIN & this->BAUDRATE_DIPSW.S2_Gpio.PIN_MASK) != 0 ) { BaudrateCode |= 0x04; } + if ( (*this->BAUDRATE_DIPSW.S1_Gpio.PIN & this->BAUDRATE_DIPSW.S1_Gpio.PIN_MASK) != 0 ) { BaudrateCode |= 0x02; } + if ( (*this->BAUDRATE_DIPSW.S0_Gpio.PIN & this->BAUDRATE_DIPSW.S0_Gpio.PIN_MASK) != 0 ) { BaudrateCode |= 0x01; } + + switch (BaudrateCode) + { + case (IDIBUS_BAUDRATE_DSW_CODE_2400B) : { BaudrateCodeValue = 2400U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_9600B) : { BaudrateCodeValue = 9600U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_19200B) : { BaudrateCodeValue = 19200U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_115200B) : { BaudrateCodeValue = 115200U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_250K) : { BaudrateCodeValue = 250000U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_500K) : { BaudrateCodeValue = 500000U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_1M) : { BaudrateCodeValue = 1000000U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_10M) : { BaudrateCodeValue = 10000000U; break; } + default : { return; } + } + if ( this->BAUDRATE != BaudrateCodeValue ) + { + this->SetBaudrateLL(BaudrateCodeValue); + switch ( BaudrateCode ) + { + case (IDIBUS_BAUDRATE_DSW_CODE_2400B) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_2400B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_2400B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_9600B) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_9600B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_9600B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_19200B) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_19200B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_19200B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_115200B) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_115200B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_115200B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_250K) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_250K_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_250K_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_500K) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_500K_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_500K_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_1M) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_1M_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_1M_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_10M) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_10M_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_10M_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + default : { return; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::SetBaudrateLL(uint32_t Baudrate) +{ + uint16_t UBRR_2X; + if ( ((F_CPU / 8U) % Baudrate) < (Baudrate / 2) ) + { + UBRR_2X = (uint16_t)( ((uint32_t)F_CPU / 8U) / Baudrate ); + if ( UBRR_2X != 0 ) { UBRR_2X--; } + } + else { UBRR_2X = (uint16_t)( ((uint32_t)F_CPU / 8U) / Baudrate ); } //(F_CPU / 8U) / Baudrate + 1 - 1 + *this->USARTN.UBRRN = UBRR_2X; + this->BAUDRATE = Baudrate; + if ( this->InitState == 1 ) { this->InitState = 2; } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +void IdiBusSerial::Start(void) +{ + *this->USARTN.UCSRNB = (1U<RS485_DIR_GPIO.PORT |= this->RS485_DIR_GPIO.PIN_MASK; // Dir to Tx + sei(); + this->TransferComplete = 1; // +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::Stop(void) +{ + *this->TIMN.TCCRNB = 0; // Timer Stop + cli(); + *this->RS485_DIR_GPIO.PORT &= ~this->RS485_DIR_GPIO.PIN_MASK; // Dir to RX + sei(); + *this->USARTN.UCSRNB = 0; // USART TX/RX Periph disable + this->TransferComplete = 1; // +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::SendRequestAsync(uint8_t *_TxBuf_, uint16_t _TxBufLength_) +{ + if ( (this->TransferComplete == 0) || (this->InitState != 2) ) { return 0; } + + this->ERROR_STATUS.SumVar = 0; + if ( _TxBufLength_ == 0 ) { this->ERROR_STATUS.BF.TxZerolength = 1; return 0; } + else if ( _TxBufLength_ > IDIBUS_SERIAL_TX_BUF_SIZE ) { this->ERROR_STATUS.BF.TxOverflow = 1; return 0; } + + memcpy(this->TxBuf, _TxBuf_, _TxBufLength_); + this->TransferComplete = 0; + this->RequestType = _IDIBUS_SERIAL_TX_RX_; + + *this->TIMN.OCRNA = this->TimerInterFrameCompValue; + if ( this->TimerTimeoutCompValue > (0xFFFFU - this->TimerInterFrameCompValue) ) + { + *this->TIMN.OCRNB = 0xFFFFU; + this->TimerTimeoutOverflow = (uint16_t)( this->TimerTimeoutCompValue - (0xFFFFU - this->TimerInterFrameCompValue) ); + } + else + { + *this->TIMN.OCRNB = (uint16_t)(this->TimerTimeoutCompValue + this->TimerInterFrameCompValue); + this->TimerTimeoutOverflow = 0; + } + *this->TIMN.TCNTN = 0; + *this->TIMN.TIFRN = (1U << USARTN_TIM_TIFR_OCFA_Pos) | (1U << USARTN_TIM_TIFR_OCFB_Pos); // Interframe and Response timeouts + *this->TIMN.TIMSKN = (1U << USRTN_TIM_TIMSK_OCIEA_Pos) | (1U << USRTN_TIM_TIMSK_OCIEB_Pos); + + this->TxBufCounter = 1; + this->TxBufLength = _TxBufLength_; + this->RxBufCounter = 0; + *this->USARTN.UDRN = this->TxBuf[0]; + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::SendRequestSync(uint8_t *_TxBuf_, uint16_t _TxBufLength_) +{ + if ( this->InitState != 2 ) { return 0; } + while ( this->TransferComplete == 0 ) { } + if ( this->SendRequestAsync(_TxBuf_, _TxBufLength_) == 0 ) { return 0; } + while ( this->TransferComplete == 0 ) { } + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::WriteAsync(uint8_t *_TxBuf_, uint16_t _TxBufLength_) +{ + if ( (this->TransferComplete == 0) || (this->InitState != 2) ) { return 0; } + + this->ERROR_STATUS.SumVar = 0; + if ( _TxBufLength_ == 0 ) { this->ERROR_STATUS.BF.TxZerolength = 1; return 0; } + else if ( _TxBufLength_ > IDIBUS_SERIAL_TX_BUF_SIZE ) { this->ERROR_STATUS.BF.TxOverflow = 1; return 0; } + + this->TransferComplete = 0; + memcpy(this->TxBuf, _TxBuf_, _TxBufLength_); + this->RequestType = _IDIBUS_SERIAL_TX_; + + *this->TIMN.OCRNA = this->TimerInterFrameCompValue; + *this->TIMN.TCNTN = 0; + *this->TIMN.TIFRN = (1U << USARTN_TIM_TIFR_OCFA_Pos) | (1U << USARTN_TIM_TIFR_OCFB_Pos); // Interframe Timeout + *this->TIMN.TIMSKN = (1U << USRTN_TIM_TIMSK_OCIEA_Pos); + + this->TxBufCounter = 1; + this->TxBufLength = _TxBufLength_; + *this->USARTN.UDRN = this->TxBuf[0]; + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::WriteSync(uint8_t *_TxBuf_, uint16_t _TxBufLength_) +{ + if ( this->InitState != 2 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + if ( this->WriteAsync(_TxBuf_, _TxBufLength_) == 0 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + return 1; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t *IdiBusSerial::getTxBufPointer(void) +{ + if ( this->TransferComplete ) { return this->TxBuf; } + else { return NULL; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t *IdiBusSerial::getRxBufPointer (void) +{ + return this->RxBuf; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::SendRequestAsync(uint16_t DataLength) +{ + if ( (this->TransferComplete == 0) || (this->InitState != 2) ) { return 0; } + this->ERROR_STATUS.SumVar = 0; + this->TransferComplete = 0; + this->RequestType = _IDIBUS_SERIAL_TX_RX_; + + *this->TIMN.OCRNA = this->TimerInterFrameCompValue; + if ( this->TimerTimeoutCompValue > (0xFFFFU - this->TimerInterFrameCompValue) ) + { + *this->TIMN.OCRNB = 0xFFFFU; + this->TimerTimeoutOverflow = (uint16_t)( this->TimerTimeoutCompValue - (0xFFFFU - this->TimerInterFrameCompValue) ); + } + else + { + *this->TIMN.OCRNB = (uint16_t)(this->TimerTimeoutCompValue + this->TimerInterFrameCompValue); + this->TimerTimeoutOverflow = 0; + } + *this->TIMN.TCNTN = 0; + *this->TIMN.TIFRN = (1U << USARTN_TIM_TIFR_OCFA_Pos) | (1U << USARTN_TIM_TIFR_OCFB_Pos); // Interframe and Response timeouts + *this->TIMN.TIMSKN = (1U << USRTN_TIM_TIMSK_OCIEA_Pos) | (1U << USRTN_TIM_TIMSK_OCIEB_Pos); + + this->TxBufCounter = 1; + this->TxBufLength = DataLength; + this->RxBufCounter = 0; + *this->USARTN.UDRN = this->TxBuf[0]; + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::SendRequestSync(uint16_t DataLength) +{ + if ( this->InitState != 2 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + if ( this->SendRequestAsync(DataLength) == 0 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::WriteAsync(uint16_t DataLength) +{ + if ( (this->TransferComplete == 0) || (this->InitState != 2) ) { return 0; } + this->ERROR_STATUS.SumVar = 0; + this->TransferComplete = 0; + this->RequestType = _IDIBUS_SERIAL_TX_; + + *this->TIMN.OCRNA = this->TimerInterFrameCompValue; + *this->TIMN.TCNTN = 0; + *this->TIMN.TIFRN = (1U << USARTN_TIM_TIFR_OCFA_Pos) | (1U << USARTN_TIM_TIFR_OCFB_Pos); // Interframe Timeout + *this->TIMN.TIMSKN = (1U << USRTN_TIM_TIMSK_OCIEA_Pos); + + this->TxBufCounter = 1; + this->TxBufLength = DataLength; + *this->USARTN.UDRN = this->TxBuf[0]; + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::WriteSync(uint16_t DataLength) +{ + if ( this->InitState != 2 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + if ( this->WriteAsync(DataLength) == 0 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::IsTransferComplete(void) { return this->TransferComplete; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint16_t IdiBusSerial::GetRxBufCounter(void) { return this->RxBufCounter; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IDIBUS_SERIAL_ERROR_STATUS_TYPE IdiBusSerial::GetErrorStatus(void) { return this->ERROR_STATUS; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint32_t IdiBusSerial::GetBaudrate(void) { return this->BAUDRATE; } +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +void IdiBusSerial::USART_RxInterruptFunc (void) +{ + *this->TIMN.TCNTN = 0; + if ( (*this->USARTN.UCSRNA & ( (1U<RxBufCounter < IDIBUS_SERIAL_RX_BUF_SIZE ) { this->RxBuf[this->RxBufCounter++] = *this->USARTN.UDRN; } + else { this->ERROR_STATUS.BF.RxOverflow = 1; (void)*this->USARTN.UDRN; } + } + else { this->ERROR_STATUS.BF.LLComERR = 1; (void)*this->USARTN.UDRN; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::USART_TxInterruptFunc (void) +{ + if ( this->TxBufCounter != this->TxBufLength ) { *this->USARTN.UDRN = this->TxBuf[this->TxBufCounter++]; } + else + { + switch (this->RequestType) + { + case (_IDIBUS_SERIAL_TX_RX_) : { + *this->RS485_DIR_GPIO.PORT &= ~this->RS485_DIR_GPIO.PIN_MASK; + *this->USARTN.UCSRNB |= (1U<TIMN.TCCRNB = IDIBUS_SERIAL_TIMER_PR_REG; //Timer Start + break; } + case (_IDIBUS_SERIAL_TX_) : { + *this->TIMN.TCCRNB = IDIBUS_SERIAL_TIMER_PR_REG; //Timer Start + break; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::TIM_COMPA_InterruptFunc (void) +{ + switch (this->RequestType) + { + case ( _IDIBUS_SERIAL_TX_RX_ ) : { + if ( this->RxBufCounter != 0 ) // Interframe Timeout < Response < Request Timeout + { + *this->TIMN.TCCRNB = 0; // Timer Stop + *this->USARTN.UCSRNB &= ~( (1U<RS485_DIR_GPIO.PORT |= this->RS485_DIR_GPIO.PIN_MASK; // Dir to TX + this->TransferComplete = 1; // Complete + } + break; } + case (_IDIBUS_SERIAL_TX_) : { + *this->TIMN.TCCRNB = 0; // Timer Stop + this->TransferComplete = 1; // Complete + break; } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::TIM_COMPB_InterruptFunc (void) +{ + if ( this->TimerTimeoutOverflow != 0 ) + { + *this->TIMN.OCRNB = this->TimerTimeoutOverflow; + *this->TIMN.TCNTN = 0; + *this->TIMN.TIFRN = (1U << USARTN_TIM_TIFR_OCFB_Pos); + this->TimerTimeoutOverflow = 0; + } + else + { + *this->TIMN.TCCRNB = 0; //Timer Stop + *this->USARTN.UCSRNB &= ~( (1U<RS485_DIR_GPIO.PORT |= this->RS485_DIR_GPIO.PIN_MASK; + this->ERROR_STATUS.BF.TimeoutERR = 1; + this->TransferComplete = 1; + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSerial::GetGpioParams(IDIBUS_SERIAL_GPIO_INIT *InitSTR, IDIBUS_SERIAL_GPIO *gpio) +{ + if ( InitSTR->PIN_NUM > 7 ) { return 0; } + + if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTA ) { gpio->PORT = &PORTA; gpio->DDR = &DDRA; gpio->PIN = &PINA; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTB ) { gpio->PORT = &PORTB; gpio->DDR = &DDRB; gpio->PIN = &PINB; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTC ) { gpio->PORT = &PORTC; gpio->DDR = &DDRC; gpio->PIN = &PINC; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTD ) { gpio->PORT = &PORTD; gpio->DDR = &DDRD; gpio->PIN = &PIND; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTE ) { gpio->PORT = &PORTE; gpio->DDR = &DDRE; gpio->PIN = &PINE; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTF ) { gpio->PORT = &PORTF; gpio->DDR = &DDRF; gpio->PIN = &PINF; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTG ) { gpio->PORT = &PORTG; gpio->DDR = &DDRG; gpio->PIN = &PING; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTH ) { gpio->PORT = &PORTH; gpio->DDR = &DDRH; gpio->PIN = &PINH; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTJ ) { gpio->PORT = &PORTJ; gpio->DDR = &DDRJ; gpio->PIN = &PINJ; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTK ) { gpio->PORT = &PORTK; gpio->DDR = &DDRK; gpio->PIN = &PINK; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTL ) { gpio->PORT = &PORTL; gpio->DDR = &DDRL; gpio->PIN = &PINL; } + else { return 0; } + gpio->PIN_MASK = (0x01U << InitSTR->PIN_NUM); + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::GetGpioParamsArduino(uint8_t PinNum, IDIBUS_SERIAL_GPIO *gpio) +{ + uint8_t PortCode; + if ( (PinNum >= NUM_DIGITAL_PINS) || ((PortCode = digitalPinToPort(PinNum)) == NOT_A_PIN) ) { return 0; } + gpio->PIN_MASK = digitalPinToBitMask(PinNum); + gpio->PORT = portOutputRegister(PortCode); + gpio->DDR = portModeRegister(PortCode); + gpio->PIN = portInputRegister(PortCode); + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerial.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerial.h new file mode 100644 index 0000000..d69c074 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerial.h @@ -0,0 +1,123 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_SERIAL_H_ +#define _IDIBUS_SERIAL_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +#include "IdiBusSerialDefs.h" +#include "IdiBusInterruptsList.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_SERIAL_USARTN_NUMBER { + IDIBUS_SERIAL_USART0, + IDIBUS_SERIAL_USART1, + IDIBUS_SERIAL_USART2, + IDIBUS_SERIAL_USART3 + }; +enum IDIBUS_SERIAL_TIMER_NUMBER { + IDIBUS_TIMER_1 = 1, + IDIBUS_TIMER_3 = 3, + IDIBUS_TIMER_4, + IDIBUS_TIMER_5 + }; +enum IDIBUS_SERIAL_USARTN_CONFIG { + IDIBUS_SERIAL_8N1, + IDIBUS_SERIAL_8N2, + IDIBUS_SERIAL_8E1, + IDIBUS_SERIAL_8E2, + IDIBUS_SERIAL_8O1, + IDIBUS_SERIAL_8O2 + }; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + enum IDIBUS_SERIAL_USARTN_NUMBER USART_NUMBER; + enum IDIBUS_SERIAL_TIMER_NUMBER TIMER_NUMBER; + enum IDIBUS_SERIAL_USARTN_CONFIG CONFIG; + uint8_t RS485_DIR_PIN; + uint8_t BAUDRATE_DIPSW_S0_PIN; + uint8_t BAUDRATE_DIPSW_S1_PIN; + uint8_t BAUDRATE_DIPSW_S2_PIN; + } IDIBUS_SERIAL_INIT_TYPEDEF; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + enum IDIBUS_SERIAL_USARTN_NUMBER USART_NUMBER; + enum IDIBUS_SERIAL_TIMER_NUMBER TIMER_NUMBER; + enum IDIBUS_SERIAL_USARTN_CONFIG CONFIG; + IDIBUS_SERIAL_GPIO_INIT RS485_DIR_GPIO; + struct { + IDIBUS_SERIAL_GPIO_INIT S0; + IDIBUS_SERIAL_GPIO_INIT S1; + IDIBUS_SERIAL_GPIO_INIT S2; + } BAUDRATE_DIPSW; + } IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusSerial : public IdiBusCallbackInterface { + + public : + IdiBusSerial(void); + + uint8_t Init(IDIBUS_SERIAL_INIT_TYPEDEF *InitT); + uint8_t Init(IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF *InitT); + void SetBaudrate(enum IDIBUS_SERIAL_BAUDRATE Baudrate); + void UpdateBaudrateFromDipSwitch(void); + + void Start (void); // Hold Line + void Stop (void); // TX/RX disable, Release Line + + uint8_t SendRequestAsync(uint8_t *_TxBuf_, uint16_t _TxBufLength_); + uint8_t SendRequestSync (uint8_t *_TxBuf_, uint16_t _TxBufLength_); + + uint8_t WriteSync (uint8_t *_TxBuf_, uint16_t _TxBufLength_); + uint8_t WriteAsync(uint8_t *_TxBuf_, uint16_t _TxBufLength_); + + uint8_t IsTransferComplete(void); + uint16_t GetRxBufCounter(void); + IDIBUS_SERIAL_ERROR_STATUS_TYPE GetErrorStatus(void); + uint32_t GetBaudrate(void); + + private : + IDIBUS_SERIAL_USART_HW_TYPE USARTN; + IDIBUS_SERIAL_USARTN_16BIT_TIMER TIMN; + + IDIBUS_SERIAL_GPIO RS485_DIR_GPIO; + IDIBUS_SERIAL_BAUDRATE_DIPSW_TYPE BAUDRATE_DIPSW; + uint32_t BAUDRATE; + + uint8_t TxBuf[IDIBUS_SERIAL_TX_BUF_SIZE]; + uint16_t TxBufLength; + uint16_t TxBufCounter; + + uint8_t RxBuf[IDIBUS_SERIAL_RX_BUF_SIZE]; + uint16_t RxBufCounter; + IDIBUS_SERIAL_ERROR_STATUS_TYPE ERROR_STATUS; + + uint16_t TimerInterFrameCompValue; + uint16_t TimerTimeoutCompValue; + uint16_t TimerTimeoutOverflow; + + enum IDIBUS_SERIAL_REQUEST_TYPE RequestType; + volatile uint8_t TransferComplete; + uint16_t InitProtectionVar; + uint8_t InitState; + + // Interrupt Vectors Pointers + virtual void USART_RxInterruptFunc(void) override; + virtual void USART_TxInterruptFunc(void) override; + virtual void TIM_COMPA_InterruptFunc(void) override; + virtual void TIM_COMPB_InterruptFunc(void) override; + + // Routine + uint8_t BaseInit(enum IDIBUS_SERIAL_USARTN_NUMBER USART_NUM, enum IDIBUS_SERIAL_TIMER_NUMBER TIMER_NUM, enum IDIBUS_SERIAL_USARTN_CONFIG CONF); + uint8_t GetGpioParams(IDIBUS_SERIAL_GPIO_INIT *InitSTR, IDIBUS_SERIAL_GPIO *gpio); + uint8_t GetGpioParamsArduino(uint8_t PinNum, IDIBUS_SERIAL_GPIO *gpio); + void SetBaudrateLL(uint32_t Baudrate); + + protected : + uint8_t *getTxBufPointer (void); + uint8_t *getRxBufPointer (void); + uint8_t SendRequestAsync(uint16_t DataLength); + uint8_t SendRequestSync(uint16_t DataLength); + uint8_t WriteAsync(uint16_t DataLength); + uint8_t WriteSync(uint16_t DataLength); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //_IDIBUS_SERIAL_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialDefs.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialDefs.h new file mode 100644 index 0000000..778d4d8 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialDefs.h @@ -0,0 +1,138 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_SERIAL_COMDEFS_H_ +#define _IDIBUS_SERIAL_COMDEFS_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#if defined (__AVR_ATmega2560__) +#define USARTN_UCSRNA_RXC_Pos 7U +#define USARTN_UCSRNA_TXC_Pos 6U +#define USARTN_UCSRNA_UDR_Pos 5U +#define USARTN_UCSRNA_FE_Pos 4U +#define USARTN_UCSRNA_DOR_Pos 3U +#define USARTN_UCSRNA_UPE_Pos 2U +#define USARTN_UCSRNA_U2X_Pos 1U +#define USARTN_UCSRNA_MPCM_Pos 0U + +#define USARTN_UCSRNB_RXCIE_Pos 7U +#define USARTN_UCSRNB_TXCIE_Pos 6U +#define USARTN_UCSRNB_UDRIE_Pos 5U +#define USARTN_UCSRNB_RXEN_Pos 4U +#define USARTN_UCSRNB_TXEN_Pos 3U +#define USARTN_UCSRNB_UCSZ2_Pos 2U +#define USARTN_UCSRNB_RXB8_Pos 1U +#define USARTN_UCSRNB_TXB8_Pos 0U + +#define USARTN_UCSRNC_UMSEL1 7U +#define USARTN_UCSRNC_UMSEL0 6U +#define USARTN_UCSRNC_UPM1 5U +#define USARTN_UCSRNC_UPM0 4U +#define USARTN_UCSRNC_USBS 3U +#define USARTN_UCSRNC_UCSZ1 2U +#define USARTN_UCSRNC_UCSZ0 1U +#define USARTN_UCSRNC_UCPOL 0U + +#define USARTN_TIM_TCCRA_WGMN1_Pos 1U + +#define USARTN_TIM_TCCRB_PR1 1U +#define USARTN_TIM_TCCRB_PR8 2U +#define USARTN_TIM_TCCRB_PR64 3U +#define USARTN_TIM_TCCRB_PR256 4U +#define USARTN_TIM_TCCRB_PR1024 5U + +#define USRTN_TIM_TIMSK_TOIE_Pos 0U +#define USRTN_TIM_TIMSK_OCIEA_Pos 1U +#define USRTN_TIM_TIMSK_OCIEB_Pos 2U +#define USRTN_TIM_TIMSK_OCIEC_Pos 3U + +#define USARTN_TIM_TIFR_TOV_Pos 0U +#define USARTN_TIM_TIFR_OCFA_Pos 1U +#define USARTN_TIM_TIFR_OCFB_Pos 2U +#define USARTN_TIM_TIFR_OCFC_Pos 3U + +#endif //#if defined (__AVR_ATmega2560__) +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_BAUDRATE_DSW_CODE_19200B 0x00 +#define IDIBUS_BAUDRATE_DSW_CODE_500K 0x01 +#define IDIBUS_BAUDRATE_DSW_CODE_2400B 0x02 +#define IDIBUS_BAUDRATE_DSW_CODE_9600B 0x03 +#define IDIBUS_BAUDRATE_DSW_CODE_115200B 0x04 +#define IDIBUS_BAUDRATE_DSW_CODE_250K 0x05 +#define IDIBUS_BAUDRATE_DSW_CODE_1M 0x06 +#define IDIBUS_BAUDRATE_DSW_CODE_10M 0x07 +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_SERIAL_TIMER_PR_REG USARTN_TIM_TCCRB_PR64 + +#if IDIBUS_SERIAL_TIMER_PR_REG == USARTN_TIM_TCCRB_PR1 +#define IDIBUS_SERIAL_TIMER_PR_VALUE 1U +#elif IDIBUS_SERIAL_TIMER_PR_REG == USARTN_TIM_TCCRB_PR8 +#define IDIBUS_SERIAL_TIMER_PR_VALUE 8U +#elif IDIBUS_SERIAL_TIMER_PR_REG == USARTN_TIM_TCCRB_PR64 +#define IDIBUS_SERIAL_TIMER_PR_VALUE 64U +#elif IDIBUS_SERIAL_TIMER_PR_REG == USARTN_TIM_TCCRB_PR256 +#define IDIBUS_SERIAL_TIMER_PR_VALUE 256U +#elif IDIBUS_SERIAL_TIMER_PR_REG == USARTN_TIM_TCCRB_PR1024 +#define IDIBUS_SERIAL_TIMER_PR_VALUE 1024U +#else +#error "Idibus Serial: Incorrect Timer Prescaler value !" +#endif //#if IDIBUS_T_CPU==CPU_ATmega2560 +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_SERIAL_TX_BUF_SIZE IDIMMES_MAX_MES_SIZE +#define IDIBUS_SERIAL_RX_BUF_SIZE IDISMES_MAX_MES_SIZE +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_SERIAL_REQUEST_TYPE { + _IDIBUS_SERIAL_TX_RX_, + _IDIBUS_SERIAL_TX_, + //Alarm + }; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + volatile uint8_t *UCSRNA; + volatile uint8_t *UCSRNB; + volatile uint8_t *UCSRNC; + volatile uint16_t *UBRRN; + volatile uint8_t *UDRN; + } IDIBUS_SERIAL_USART_HW_TYPE; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + volatile uint8_t *TCCRNA; + volatile uint8_t *TCCRNB; + volatile uint8_t *TIMSKN; + volatile uint8_t *TIFRN; + volatile uint16_t *OCRNA; + volatile uint16_t *OCRNB; + volatile uint16_t *TCNTN; + } IDIBUS_SERIAL_USARTN_16BIT_TIMER; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef union { + uint8_t SumVar; + struct { + uint8_t TimeoutERR : 1; + uint8_t TxOverflow : 1; + uint8_t RxOverflow : 1; + uint8_t LLComERR : 1; + uint8_t TxZerolength : 1; + uint8_t Reserved : 3; + } BF; + } IDIBUS_SERIAL_ERROR_STATUS_TYPE; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + uint8_t PIN_MASK; + volatile uint8_t *PORT; + volatile uint8_t *DDR; + volatile uint8_t *PIN; + } IDIBUS_SERIAL_GPIO; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + uint8_t PIN_NUM; + volatile uint8_t *PORT; + } IDIBUS_SERIAL_GPIO_INIT; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + IDIBUS_SERIAL_GPIO S0_Gpio; + IDIBUS_SERIAL_GPIO S1_Gpio; + IDIBUS_SERIAL_GPIO S2_Gpio; + } IDIBUS_SERIAL_BAUDRATE_DIPSW_TYPE; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //_IDIBUS_SERIAL_COMDEFS_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialLine.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialLine.cpp new file mode 100644 index 0000000..f3646f2 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialLine.cpp @@ -0,0 +1,122 @@ +//############################################################################################################################################################################################################# +#include "IdiBusSerialLine.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSerialLine::IdiBusSerialLine(void) : IdiBusSerial() +{ +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerialLine::sendMMES (IdiBusMMES *MMES) +{ + if ( MMES->IsValid() == 0 ) { return IDIERMST_INVALID_TX_REQUEST_FORMAT; } + + uint8_t *TxMesBuf = this->getTxBufPointer(); + if ( TxMesBuf == NULL ) { return IDIERMST_TX_MES; } + + uint8_t *RxMesBuf = this->getRxBufPointer(); + uint8_t DataPos; + + // Fill Header + TxMesBuf[IDIMMES_ADDR_Pos] = MMES->SlAddr; + TxMesBuf[IDIMMES_MMPS_Pos] = (MMES->MMPS.LongMes << IDIMMES_MMPS_LONG_MES_Pos) | + (IDIMMES_MMPS_MES_TYPE_MMES << IDIMMES_MMPS_MES_TYPE_Pos) | + (0x00U << IDIMMES_MMPS_FAST_FUNC_Pos) | + (MMES->MMPS.AlarmMes << IDIMMES_MMPS_ALARM_FRAME_Pos) | + (MMES->MMPS.EncryptedAes << IDIMMES_MMPS_ENCRYPTED_AES_Pos); + TxMesBuf[IDIMMES_DEV_Pos] = (MMES->DEV.NUM << IDIMMES_DEV_NUM_Pos) | (MMES->DEV.ALLCH << IDIMMES_DEV_ALLCH_Pos); + TxMesBuf[IDIMMES_CHNL_Pos] = (MMES->CHNL.NUM << IDIMMES_CHNL_NUM_Pos) | (MMES->CHNL.ALLSAME << IDIMMES_CHNL_ALLSAME_Pos); + DataPos = IDIMMES_CHNL_Pos + 1; + + // If Not Fast Function add command/function + if ( MMES->ComFunc < 16 ) { TxMesBuf[IDIMMES_MMPS_Pos] |= (MMES->ComFunc << IDIMMES_MMPS_FAST_FUNC_Pos); } + else { TxMesBuf[DataPos++] = MMES->ComFunc; } + + // Fill Data + if ( MMES->TxDataLength != 0 ) { memcpy(&TxMesBuf[DataPos], &MMES->TxData[0], MMES->TxDataLength); } + + // Add CRC + uint16_t CRC = MODBUS_CRC16::CRC16_TF(&TxMesBuf[0], (uint16_t)(DataPos + MMES->TxDataLength)); + TxMesBuf[DataPos + MMES->TxDataLength] = (uint8_t)(CRC >> 8); + TxMesBuf[DataPos + MMES->TxDataLength + 1] = (uint8_t) CRC; + + if ( this->SendRequestSync(DataPos + MMES->TxDataLength + MODBUS_CRC16_SIZE) == 0 ) { return IDIERMST_TX_MES; } + + IDIBUS_SERIAL_ERROR_STATUS_TYPE SerialError = this->GetErrorStatus(); + uint16_t RxMessageLength; + + if ( SerialError.BF.TimeoutERR != 0 ) { return IDIERMST_RCV_TIMEOUT; } + else if ( (SerialError.SumVar != 0) || ((RxMessageLength = this->GetRxBufCounter()) < IDISMES_MIN_MES_SIZE) ) { return IDIERMST_MES_RX_INTEGRITY; } + else + { + uint16_t CRC = MODBUS_CRC16::CRC16_TF( &RxMesBuf[0], (uint16_t)(RxMessageLength-MODBUS_CRC16_SIZE) ); + uint16_t ReceivedCRC = ((uint16_t)RxMesBuf[RxMessageLength-2] << 8) | RxMesBuf[RxMessageLength-1]; + if ( CRC != ReceivedCRC ) { return IDIERMST_CRC; } + else if ( RxMesBuf[IDISMES_ADDR_Pos] != MMES->SlAddr ) { return IDIERMST_INVALID_ADDR_NUM; } + else + { + MMES->RxDataLength = RxMessageLength - (IDISMES_ERROR_Pos + MODBUS_CRC16_SIZE); + MMES->RxData = &RxMesBuf[IDISMES_ERROR_Pos]; + return IDIER_NOPE; + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerialLine::sendMMESG (IdiBusMMESG *MMESG) +{ + if ( MMESG->IsValid() == 0 ) { return IDIERMST_INVALID_TX_REQUEST_FORMAT ; } + + uint8_t *TxMesBuf = this->getTxBufPointer(); + if ( TxMesBuf == NULL ) { return IDIERMST_TX_MES; } + + uint8_t *RxMesBuf = this->getRxBufPointer(); + uint8_t DataPos; + + // Fill Header + TxMesBuf[IDIMMES_ADDR_Pos] = MMESG->SlAddr; + TxMesBuf[IDIMMES_MMPS_Pos] = (MMESG->MMPS.LongMes << IDIMMES_MMPS_LONG_MES_Pos) | + (IDIMMES_MMPS_MES_TYPE_MMESG << IDIMMES_MMPS_MES_TYPE_Pos) | + (0x00 << IDIMMES_MMPS_FAST_FUNC_Pos) | + (MMESG->MMPS.AlarmMes << IDIMMES_MMPS_ALARM_FRAME_Pos) | + (MMESG->MMPS.EncryptedAes << IDIMMES_MMPS_ENCRYPTED_AES_Pos); + DataPos = IDIMMES_MMPS_Pos + 1; + // If Not Fast Function add command/function + if ( MMESG->ComFunc < 16 ) { TxMesBuf[IDIMMES_MMPS_Pos] |= (MMESG->ComFunc << IDIMMES_MMPS_FAST_FUNC_Pos); } + else { TxMesBuf[DataPos++] = MMESG->ComFunc; } + + // Fill Data + if ( MMESG->TxDataLength != 0 ) { memcpy(&TxMesBuf[DataPos], &MMESG->TxData[0], MMESG->TxDataLength); } + + // Add CRC + uint16_t CRC = MODBUS_CRC16::CRC16_TF(&TxMesBuf[0], (uint16_t)(DataPos + MMESG->TxDataLength)); + TxMesBuf[DataPos + MMESG->TxDataLength] = (uint8_t)(CRC >> 8); + TxMesBuf[DataPos + MMESG->TxDataLength + 1] = (uint8_t) CRC; + + if ( MMESG->IsGroupAddr() != 0 ) + { + if ( this->WriteSync(DataPos + MMESG->TxDataLength + MODBUS_CRC16_SIZE) == 0 ) { return IDIERMST_TX_MES; } + return IDIER_NOPE; + } + else //Module commands + { + if ( this->SendRequestSync(DataPos + MMESG->TxDataLength + MODBUS_CRC16_SIZE) == 0 ) { return IDIERMST_TX_MES; } + + uint16_t RxMessageLength; + IDIBUS_SERIAL_ERROR_STATUS_TYPE SerialError = this->GetErrorStatus(); + + if ( SerialError.BF.TimeoutERR != 0 ) { return IDIERMST_RCV_TIMEOUT; } + else if ( (SerialError.SumVar != 0) || ((RxMessageLength = this->GetRxBufCounter()) < IDISMES_MIN_MES_SIZE) ) { return IDIERMST_TX_MES; } + else + { + uint16_t CRC = MODBUS_CRC16::CRC16_TF( &RxMesBuf[0], (uint16_t)(RxMessageLength-MODBUS_CRC16_SIZE) ); + uint16_t ReceivedCRC = ((uint16_t)RxMesBuf[RxMessageLength-2] << 8) | RxMesBuf[RxMessageLength-1]; + if ( CRC != ReceivedCRC ) { return IDIERMST_CRC; } + else if ( RxMesBuf[IDISMES_ADDR_Pos] != MMESG->SlAddr ) { return IDIERMST_INVALID_ADDR_NUM; } + { + MMESG->RxDataLength = RxMessageLength - (IDISMES_ERROR_Pos + MODBUS_CRC16_SIZE); + MMESG->RxData = &RxMesBuf[IDISMES_ERROR_Pos]; + return IDIER_NOPE; + } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialLine.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialLine.h new file mode 100644 index 0000000..528f335 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSerialLine.h @@ -0,0 +1,17 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_STD_LINE_H_ +#define _IDIBUS_STD_LINE_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +#include "IdiBusSerial.h" +#include "IdiBusMes.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusSerialLine : public IdiBusSerial { + public : + IdiBusSerialLine(); + uint8_t sendMMES (IdiBusMMES *MMES); // return ErrorCode but not look into [data] + uint8_t sendMMESG (IdiBusMMESG *MMESG); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_STD_LINE_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSlave.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSlave.cpp new file mode 100644 index 0000000..7753b0f --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSlave.cpp @@ -0,0 +1,349 @@ +//############################################################################################################################################################################################################# +#include "IdiBusSlave.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSlave::IdiBusSlave( IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress ) +{ + this->Line = SlaveLine; + this->Address = SlaveAddress; + this->CRC_AVR.CRC_ErrAvrBufCounter = 0; + this->CRC_AVR.CRC_ErrAvrBufPos = 0; + this->CRC_AVR.CRC_ErrAvrBufSum = 0; + this->CRC_MultipleError = 0; + this->ModuleError = IDIER_NOPE; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSlave::IdiBusSlave(void) +{ + this->Line = NULL; + this->Address = 1; + this->CRC_AVR.CRC_ErrAvrBufCounter = 0; + this->CRC_AVR.CRC_ErrAvrBufPos = 0; + this->CRC_AVR.CRC_ErrAvrBufSum = 0; + this->CRC_MultipleError = 0; + this->ModuleError = IDIER_NOPE; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSlave::Init(IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) +{ + this->Line = SlaveLine; + this->Address = SlaveAddress; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::SendRequestMMES(IdiBusMMES *MMES) +{ + if ( this->Line == NULL ) { return IDIERMST_TX_MES; } + uint8_t RequestError = this->Line->sendMMES(MMES); + this->CrcAvrErrorCalc(RequestError); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if ( MMES->IsModuleError(MMES->RxData[0]) ) + { + if ( MMES->RxDataLength != 1 ) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { this->ModuleError = MMES->RxData[0]; return MMES->RxData[0]; } + } + this->ModuleError = IDIER_NOPE; + return IDIER_NOPE; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::SendRequestMMESG(IdiBusMMESG *MMESG) +{ + if ( this->Line == NULL ) { return IDIERMST_TX_MES; } + uint8_t RequestError = this->Line->sendMMESG(MMESG); + this->CrcAvrErrorCalc(RequestError); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if ( MMESG->IsGroupAddr() == 0 ) + { + if ( MMESG->IsModuleError(MMESG->RxData[0]) ) + { + if ( MMESG->RxDataLength != 1 ) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { this->ModuleError = MMESG->RxData[0]; return MMESG->RxData[0]; } + } + } + this->ModuleError = IDIER_NOPE; + return IDIER_NOPE; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::SendModuleSimpleSetCommand(uint8_t Command) +{ + IdiBusMMESG MMESG(this->Address); + MMESG.ComFunc = Command; + uint8_t RequestError = this->SendRequestMMESG(&MMESG); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if (MMESG.RxDataLength != 1) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { return MMESG.RxData[0]; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::SendModuleSimpleSetCommand(uint8_t Command, uint8_t *TxData, uint16_t TxDataLength) +{ + IdiBusMMESG MMESG(this->Address, TxData, TxDataLength); + MMESG.ComFunc = Command; + uint8_t RequestError = this->SendRequestMMESG(&MMESG); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if (MMESG.RxDataLength != 1) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { return MMESG.RxData[0]; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSlave::CrcAvrErrorCalc(uint8_t ErrorCode) +{ + uint8_t ErrorBufCode; + if ( ErrorCode == IDIERMST_CRC ) { ErrorBufCode = 1; } + else { ErrorBufCode = 0; } + + this->CRC_AVR.CRC_ErrAvrBufSum = this->CRC_AVR.CRC_ErrAvrBufSum + ErrorBufCode - this->CRC_AVR.CRC_ErrAvrBuf[this->CRC_AVR.CRC_ErrAvrBufPos]; + this->CRC_AVR.CRC_ErrAvrBuf[this->CRC_AVR.CRC_ErrAvrBufPos] = ErrorBufCode; + if ( this->CRC_AVR.CRC_ErrAvrBufPos == (IDIER_MULTIPLE_CRC_AVRBUF_SIZE - 1) ) { this->CRC_AVR.CRC_ErrAvrBufPos = 0; } + else { this->CRC_AVR.CRC_ErrAvrBufPos++; } + + if ( this->CRC_AVR.CRC_ErrAvrBufCounter < IDIER_MULTIPLE_CRC_AVRBUF_SIZE ) { this->CRC_AVR.CRC_ErrAvrBufCounter++; } + else + { + if ( this->CRC_AVR.CRC_ErrAvrBufSum >= IDIER_MULTIPLE_CRC_AVRBUF_THR ) { this->CRC_MultipleError = 1; } + else { this->CRC_MultipleError = 0; } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::c_Init(void) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_Init); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_Init(uint8_t Group) { return (Group > IDIBUS_GROUP_LAST_NUMBER) ? IDIERMST_INVALID_TX_PARAM : this->SendModuleSimpleSetCommand(IDIMMES_COM_C_Init, &Group, 1); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_ShtDown(void) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_ShtDown); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_Freeze(void) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_Freeze); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_Resume(void) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_Resume); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_DummyModule(void) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_DummyModule); } +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::c_SendTimeDate(IdiTimeFormat Time, IdiDateFormat Date) +{ + if ( (Time.isValid() == 0) || (Date.isValid() == 0) ) { return IDIERMST_INVALID_TX_PARAM; } + uint8_t TxData[IDIMMES_C_DATETIME_LENGTH]; + Time.getBufForMMES(&TxData[IDIMMES_C_DATETIME_TIME_Pos]); + Date.getBufForMMES(&TxData[IDIMMES_C_DATETIME_DATE_Pos]); + return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_SendTimeDate, TxData, IDIMMES_C_DATETIME_LENGTH ); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_ReadDevFullSN_MS(void) +{ + IdiBusMMESG MMESG (this->Address); + MMESG.ComFunc = IDIMMES_COM_C_ReadDevFullSN_MS; + uint8_t RequestError = this->SendRequestMMESG(&MMESG); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if ( MMESG.RxDataLength != (IDISN_FULL_LENGTH - IDISN_VARP_AES256_Length + 2 + 1) ) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else if ( MMESG.RxData[0] != IDIER_NOPE ) { return MMESG.RxData[0]; } + else + { + this->ModuleST.parseSmesDataNoAes(&MMESG.RxData[1]); + return IDIER_NOPE; + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_WriteSnIPv4IPv6(uint32_t IPv4, uint32_t IPv6_B3, uint32_t IPv6_B2, uint32_t IPv6_B1, uint32_t IPv6_B0) +{ + uint8_t TxData[IDISN_VARP_IPv4_Length + IDISN_VARP_IPv6_Length]; + TxData[0] = (uint8_t)(IPv4 >> 24); + TxData[1] = (uint8_t)(IPv4 >> 16); + TxData[2] = (uint8_t)(IPv4 >> 8); + TxData[3] = (uint8_t)(IPv4); + TxData[4] = (uint8_t)(IPv6_B3 >> 24); + TxData[5] = (uint8_t)(IPv6_B3 >> 16); + TxData[6] = (uint8_t)(IPv6_B3 >> 8); + TxData[7] = (uint8_t)(IPv6_B3); + TxData[8] = (uint8_t)(IPv6_B2 >> 24); + TxData[9] = (uint8_t)(IPv6_B2 >> 16); + TxData[10] = (uint8_t)(IPv6_B2 >> 8); + TxData[11] = (uint8_t)(IPv6_B2); + TxData[12] = (uint8_t)(IPv6_B1 >> 24); + TxData[13] = (uint8_t)(IPv6_B1 >> 16); + TxData[14] = (uint8_t)(IPv6_B1 >> 8); + TxData[15] = (uint8_t)(IPv6_B1); + TxData[16] = (uint8_t)(IPv6_B0 >> 24); + TxData[17] = (uint8_t)(IPv6_B0 >> 16); + TxData[18] = (uint8_t)(IPv6_B0 >> 8); + TxData[19] = (uint8_t)(IPv6_B0); + uint8_t RequestError = this->SendModuleSimpleSetCommand(IDIMMES_COM_C_WriteSnIPv4IPv6, TxData, IDISN_VARP_IPv4_Length + IDISN_VARP_IPv6_Length ); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else + { + memcpy(this->ModuleST.SN.VAR.IPv4, &TxData[0], IDISN_VARP_IPv4_Length); + memcpy(this->ModuleST.SN.VAR.IPv6, &TxData[4], IDISN_VARP_IPv6_Length); + return IDIER_NOPE; + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_WriteSnVerifyDates(IdiDateFormat VDate, IdiDateFormat VEXPDate) +{ + if ( (VDate.isValid() == 0) || (VEXPDate.isValid() == 0) ) { return IDIERMST_INVALID_TX_PARAM; } + uint8_t TxData[IDIDATE_FORMAT_LENGTH * 2]; + VDate.getBufForMMES(&TxData[0]); + VEXPDate.getBufForMMES(&TxData[IDIDATE_FORMAT_LENGTH]); + uint8_t RequestError = this->SendModuleSimpleSetCommand(IDIMMES_COM_C_WriteSnVerifyDates, TxData, IDIDATE_FORMAT_LENGTH * 2 ); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else + { + this->ModuleST.SN.VAR.VerifDate = VDate; + this->ModuleST.SN.VAR.VerifExpDate = VEXPDate; + return IDIER_NOPE; + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_WriteSnAES256(uint8_t *AES256_key) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_WriteSnAES256, AES256_key, IDISN_VARP_AES256_Length); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_CheckModuleLongOp(void) +{ + IdiBusMMESG MMESG (this->Address); + MMESG.ComFunc = IDIMMES_COM_C_CheckModuleLongOp; + uint8_t RequestError = this->SendRequestMMESG(&MMESG); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if ( MMESG.RxDataLength != (IDILONGOP_MES_DATA_LENGTH + 1) ) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else if ( MMESG.RxData[0] != IDIER_NOPE ) { return MMESG.RxData[0]; } + else + { + uint8_t DataPos = 1; + this->ModuleLongOpData.State = MMESG.RxData[DataPos + IDILONGOP_STATE_Pos]; + this->ModuleLongOpData.Timeout = ((uint32_t)MMESG.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 0] << 24) | + ((uint32_t)MMESG.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 1] << 16) | + ((uint32_t)MMESG.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 2] << 8 ) | + ((uint32_t)MMESG.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 3] ); + return IDIER_NOPE; + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::c_Dummy(uint8_t Device, uint8_t Channel) +{ + IdiBusDevice *DEV; + IdiBusChannel *CHNL; + if ( (DEV = this->getDevice(Device)) == NULL ) { return IDIERMST_INVALID_DEV_NUM; } + if ( (CHNL = DEV->getChannel(Channel)) == NULL ) { return IDIERMST_INVALID_CHN_NUM; } + + IdiBusMMES MMES(this->Address); + MMES.ComFunc = IDIMMES_COM_C_Dummy; + MMES.DEV.NUM = Device; + MMES.CHNL.NUM = Channel; + + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { CHNL->MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { CHNL->MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { CHNL->MMES_Error = MMES.RxData[0]; } + return CHNL->MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_AssignGroup(uint8_t Device, uint8_t Channel, uint8_t Group) +{ + IdiBusDevice *DEV; + IdiBusChannel *CHNL; + if ( (DEV = this->getDevice(Device)) == NULL ) { return IDIERMST_INVALID_DEV_NUM; } + if ( (CHNL = DEV->getChannel(Channel)) == NULL ) { return IDIERMST_INVALID_CHN_NUM; } + if ( Group > IDIBUS_GROUP_LAST_NUMBER ) { CHNL->MMES_Error = IDIERMST_INVALID_TX_PARAM; } + else + { + IdiBusMMES MMES(this->Address, &Group, 1); + MMES.ComFunc = IDIMMES_COM_C_AssignGroup; + MMES.DEV.NUM = Device; + MMES.CHNL.NUM = Channel; + + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { CHNL->MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { CHNL->MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { CHNL->MMES_Error = MMES.RxData[0]; } + } + return CHNL->MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_CheckChannelLongOp(uint8_t Device, uint8_t Channel) +{ + IdiBusDevice *DEV; + IdiBusChannel *CHNL; + if ( (DEV = this->getDevice(Device)) == NULL ) { return IDIERMST_INVALID_DEV_NUM; } + if ( (CHNL = DEV->getChannel(Channel)) == NULL ) { return IDIERMST_INVALID_CHN_NUM; } + + IdiBusMMES MMES(this->Address); + MMES.ComFunc = IDIMMES_COM_C_CheckChannelLongOp; + MMES.DEV.NUM = Device; + MMES.CHNL.NUM = Channel; + + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { CHNL->MMES_Error = RequestError; } + else if ( MMES.RxDataLength != (IDILONGOP_MES_DATA_LENGTH + 1) ) { CHNL->MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else if ( MMES.RxData[0] != IDIER_NOPE ) { CHNL->MMES_Error = MMES.RxData[0]; } + else + { + CHNL->MMES_Error = IDIER_NOPE; + uint8_t DataPos = 1; + CHNL->LONG_OP.State = MMES.RxData[DataPos + IDILONGOP_STATE_Pos]; + CHNL->LONG_OP.Timeout = ((uint32_t)MMES.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 0] << 24) | + ((uint32_t)MMES.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 1] << 16) | + ((uint32_t)MMES.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 2] << 8 ) | + ((uint32_t)MMES.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 3] ); + } + return CHNL->MMES_Error; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::getAddress(void) { return this->Address; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSlave::setAes256ToSn(uint8_t *AES256_key) { memcpy(this->ModuleST.SN.VAR.AES, AES256_key, IDISN_VARP_AES256_Length); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusLongOpData IdiBusSlave::getModuleLongOpData(void) { return this->ModuleLongOpData; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusLongOpData IdiBusSlave::getChLongOpData(uint8_t Device, uint8_t Channel) +{ + IdiBusDevice *DEV; + IdiBusChannel *CHNL; + if ( ((DEV = this->getDevice(Device)) != NULL) && ((CHNL = DEV->getChannel(Channel)) != NULL) ) + { + return CHNL->LONG_OP; + } + IdiBusLongOpData NewData; + return NewData; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +void IdiMsaterState::parseSmesDataNoAes(uint8_t *Data) +{ + this->STATE.B0S.StError = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_ST_ERROR_Pos) & 0x01; + this->STATE.B0S.StState = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_ST_STATE_Pos) & IDISTATUS_B0S_ST_STATE_Msk; + this->STATE.B0S.AesSupported = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_AES_SUPPORTED_Pos) & 0x01; + this->STATE.B0S.AesInstalled = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_AES_INSTALLED_Pos) & 0x01; + this->STATE.B0S.SendAlarmL0 = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_SEND_ALARM_L0_Pos) & 0x01; + this->STATE.B0S.SendAlarmL1 = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_SEND_ALARM_L1_Pos) & 0x01; + + this->STATE.B1S.ModuleType = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_MODULE_TYPE_Pos) & IDISTATUS_B1S_MODULE_TYPE_Msk; + this->STATE.B1S.BridgeConnected = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_BRIDGE_CONNECTED_Pos) & 0x01; + this->STATE.B1S.SelfInit = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_SELF_INIT_Pos) & 0x01; + this->STATE.B1S.TimeoutLed = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_TIMEOUT_LED_Pos) & 0x01; + this->STATE.B1S.NoMMESTimeout = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_NO_MMES_TIMEOUT_Pos) & 0x01; + this->STATE.B1S.CatchAlarmL0 = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_CATCH_ALARM_L0_Pos) & 0x01; + this->STATE.B1S.CatchAlarmL1 = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_CATCH_ALARM_L1_Pos) & 0x01; + + memcpy(this->SN.FIX.GS1_country, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_GS1_COUNTRY_Pos], IDISN_FIXP_GS1_COUNTRY_Length); + memcpy(this->SN.FIX.GS1_company, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_GS1_COMPANY_Pos], IDISN_FIXP_GS1_COMPANY_Length); + memcpy(this->SN.FIX.ModuleType, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_MODULE_TYPE_Pos], IDISN_FIXP_MODULE_TYPE_Length); + memcpy(this->SN.FIX.HW_rev, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_HW_REV_Pos], IDISN_FIXP_HW_REV_Length); + memcpy(this->SN.FIX.Serial, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_SERIAL_Pos], IDISN_FIXP_SERIAL_Length); + memcpy(this->SN.FIX.MAC, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_MAC_Pos], IDISN_FIXP_MAC_Length); + memcpy(this->SN.VAR.SW_rev, &Data[IDISTATUS_SN_Pos + IDISN_VARP_SW_REV_Pos], IDISN_VARP_SW_REV_Length); + memcpy(this->SN.VAR.IPv4, &Data[IDISTATUS_SN_Pos + IDISN_VARP_IPv4_Pos], IDISN_VARP_IPv4_Length); + memcpy(this->SN.VAR.IPv6, &Data[IDISTATUS_SN_Pos + IDISN_VARP_IPv6_Pos], IDISN_VARP_IPv6_Length); + + uint8_t *VerifDateP = &Data[IDISTATUS_SN_Pos + IDISN_VARP_VERIF_DATE_Pos]; + uint8_t *VerifExpDateP = &Data[IDISTATUS_SN_Pos + IDISN_VARP_EXPIR_DATE_Pos]; + IdiDateFormat verifDate(VerifDateP[0], VerifDateP[1], VerifDateP[2], VerifDateP[3]); + IdiDateFormat verifExpDate(VerifExpDateP[0], VerifExpDateP[1], VerifExpDateP[2], VerifExpDateP[3]); + this->SN.VAR.VerifDate = verifDate; + this->SN.VAR.VerifExpDate = verifExpDate; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSlave.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSlave.h new file mode 100644 index 0000000..a54b607 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSlave.h @@ -0,0 +1,121 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_SLAVE_H_ +#define _IDIBUS_SLAVE_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +#include "IdiBusDateTime.h" +#include "IdiBusMes.h" +#include "IdiBusSerialLine.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiMsaterState { + public : + IDISTATUS_STATE_TYPE STATE; + struct { + struct { + uint8_t GS1_country[3]; + uint8_t GS1_company[6]; + uint8_t ModuleType[3]; + uint8_t HW_rev[2]; + uint8_t Serial[7]; + uint8_t MAC[6]; + } FIX; + struct VAR { + VAR() : VerifDate(0,0,0,0), VerifExpDate(0,0,0,0) {} + uint8_t SW_rev[2]; + IdiDateFormat VerifDate; + IdiDateFormat VerifExpDate; + uint8_t IPv4[4]; + uint8_t IPv6[16]; + uint8_t AES[32]; + } VAR; + } SN; + void parseSmesDataNoAes(uint8_t *Data); +}; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +class IdiBusLongOpData { + public : + IdiBusLongOpData() { this->State = IDILONGOP_STATE_COMPLETE_NO_ERR; this->Timeout = 0; } + uint8_t State; + uint32_t Timeout; +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusChannel { + public : + IdiBusChannel() { this->MMES_Error = IDIER_NOPE; } + IdiBusLongOpData LONG_OP; + uint8_t MMES_Error; +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusDevice { + public : + IdiBusDevice (void *ParentModule) { this->Module = ParentModule; } + virtual IdiBusChannel *getChannel(uint8_t Num) { return NULL; } + protected : + void *Module; +}; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +class IdiBusSlave { + + public : + // Constructors and init + IdiBusSlave(IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); + IdiBusSlave(void); + void Init(IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); + + // Standard communication API + uint8_t SendRequestMMES(IdiBusMMES *MMES); + uint8_t SendRequestMMESG(IdiBusMMESG *MMESG); + + //Module commands (return ErrorCode) + uint8_t c_Init (void); + uint8_t c_Init (uint8_t Gpoup); + uint8_t c_ShtDown (void); + uint8_t c_Freeze (void); + uint8_t c_Resume (void); + uint8_t c_ReadDevFullSN_MS(void); + uint8_t c_WriteSnIPv4IPv6(uint32_t IPv4, uint32_t IPv6_B3, uint32_t IPv6_B2, uint32_t IPv6_B1, uint32_t IPv6_B0); + uint8_t c_WriteSnVerifyDates(IdiDateFormat VDate, IdiDateFormat VEXPDate); + uint8_t c_WriteSnAES256(uint8_t *AES256_key); + uint8_t c_SendTimeDate(IdiTimeFormat Time, IdiDateFormat Date); + uint8_t c_DummyModule(void); + uint8_t c_CheckModuleLongOp(void); + + // Channel Commands + uint8_t c_Dummy(uint8_t Device, uint8_t Channel); + uint8_t c_AssignGroup(uint8_t Device, uint8_t Channel, uint8_t Group); + uint8_t c_CheckChannelLongOp(uint8_t Device, uint8_t Channel); + + // Utils + uint8_t getAddress(void); + void setAes256ToSn(uint8_t *AES256_key); + IdiBusLongOpData getModuleLongOpData(void); + IdiBusLongOpData getChLongOpData(uint8_t Device, uint8_t Channel); + + // Interface - must be overridden in derived classes + virtual IdiBusDevice *getDevice(uint8_t Num) { return NULL; } + + protected : + IdiBusSerialLine *Line; + uint8_t Address; + IdiMsaterState ModuleST; + uint8_t ModuleError; + IdiBusLongOpData ModuleLongOpData; + uint8_t CRC_MultipleError; + struct { + uint8_t CRC_ErrAvrBuf[16]; + uint8_t CRC_ErrAvrBufCounter; + uint8_t CRC_ErrAvrBufPos; + uint8_t CRC_ErrAvrBufSum; + } CRC_AVR; + + uint8_t SendModuleSimpleSetCommand(uint8_t Command); + uint8_t SendModuleSimpleSetCommand(uint8_t Command, uint8_t *TxData, uint16_t TxDataLength); + void CrcAvrErrorCalc(uint8_t ErrorCode); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_SLAVE_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSystem.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSystem.h new file mode 100644 index 0000000..979d5ff --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdiBusSystem.h @@ -0,0 +1,25 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_SYSTEM_H_ +#define _IDIBUS_SYSTEM_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "Arduino.h" +#include "pins_arduino.h" + +#include +#include +#include +#include +#include "IdiBusDefs.h" +#include "MODBUS_CRC.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#ifndef F_CPU +#error "IdibusSerial: F_CPU not defined!" +#endif + +#if defined __AVR_ATmega2560__ +#else +#error "IdibusSerial: Unsupported ControllerType!" +#endif +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#ifndef _IDIBUS_SYSTEM_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdibusDefs.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdibusDefs.h new file mode 100644 index 0000000..eb625e5 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/IdibusDefs.h @@ -0,0 +1,446 @@ +//############################################################################################################################################################################################################# +#ifndef _INC_IDIBUS_DEFS_H_ +#define _INC_IDIBUS_DEFS_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +#include "MODBUS_CRC.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_BAUDRATE_DSW_CODE_19200B 0x00 +#define IDIBUS_BAUDRATE_DSW_CODE_500K 0x01 +#define IDIBUS_BAUDRATE_DSW_CODE_2400B 0x02 +#define IDIBUS_BAUDRATE_DSW_CODE_9600B 0x03 +#define IDIBUS_BAUDRATE_DSW_CODE_115200B 0x04 +#define IDIBUS_BAUDRATE_DSW_CODE_250K 0x05 +#define IDIBUS_BAUDRATE_DSW_CODE_1M 0x06 +#define IDIBUS_BAUDRATE_DSW_CODE_10M 0x07 + +// Full timeout will be (InterframeTimeout + ResponseTimeout) for request(Write + Read) or InterframeTimeout for write(Write only) +#define IDIBUS_2400B_INTERFRAME_TIMEOUT_US 16042ULL //11 * 3.5 / Baudrate +#define IDIBUS_9600B_INTERFRAME_TIMEOUT_US 4011ULL +#define IDIBUS_19200B_INTERFRAME_TIMEOUT_US 2006ULL +#define IDIBUS_115200B_INTERFRAME_TIMEOUT_US 1750ULL +#define IDIBUS_250K_INTERFRAME_TIMEOUT_US 1750ULL +#define IDIBUS_500K_INTERFRAME_TIMEOUT_US 1750ULL +#define IDIBUS_1M_INTERFRAME_TIMEOUT_US 1750ULL +#define IDIBUS_10M_INTERFRAME_TIMEOUT_US 1750ULL + +#define IDIBUS_2400B_ALARM_TIMEOUT_US 34375ULL //11 * 3.5 / Baudrate +#define IDIBUS_9600B_ALARM_TIMEOUT_US 8594ULL +#define IDIBUS_19200B_ALARM_TIMEOUT_US 4297ULL +#define IDIBUS_115200B_ALARM_TIMEOUT_US 1750ULL +#define IDIBUS_250K_ALARM_TIMEOUT_US 1750ULL +#define IDIBUS_500K_ALARM_TIMEOUT_US 1750ULL +#define IDIBUS_1M_ALARM_TIMEOUT_US 1750ULL +#define IDIBUS_10M_ALARM_TIMEOUT_US 1750ULL + +#define IDIBUS_2400B_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_2400B_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_9600B_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_9600B_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_19200B_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_19200B_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_115200B_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_115200B_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_250K_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_250K_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_500K_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_500K_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_1M_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_1M_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_10M_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_10M_INTERFRAME_TIMEOUT_US * 3 / 2 ) + +#define IDIBUS_2400B_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_2400B_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_9600B_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_9600B_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_19200B_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_19200B_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_115200B_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_115200B_INTERFRAME_TIMEOUT_US) +#define IDIBUS_250K_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_250K_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_500K_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_500K_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_1M_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_1M_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_10M_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_10M_INTERFRAME_TIMEOUT_US ) + + +enum IDIBUS_SERIAL_BAUDRATE { + IDIBUS_BAUDRATE_2400 = IDIBUS_BAUDRATE_DSW_CODE_2400B, + IDIBUS_BAUDRATE_9600 = IDIBUS_BAUDRATE_DSW_CODE_9600B, + IDIBUS_BAUDRATE_19200 = IDIBUS_BAUDRATE_DSW_CODE_19200B, + IDIBUS_BAUDRATE_115200 = IDIBUS_BAUDRATE_DSW_CODE_115200B, + IDIBUS_BAUDRATE_250K = IDIBUS_BAUDRATE_DSW_CODE_250K, + IDIBUS_BAUDRATE_500K = IDIBUS_BAUDRATE_DSW_CODE_500K, + IDIBUS_BAUDRATE_1M = IDIBUS_BAUDRATE_DSW_CODE_1M, + IDIBUS_BAUDRATE_10M = IDIBUS_BAUDRATE_DSW_CODE_10M +}; + +#define IDIBUS_LINK_LED_NO_MMES_TIMEOUT_0_SEC 60U +#define IDIBUS_LINK_LED_NO_MMES_TIMEOUT_0_MS ( IDIBUS_LINK_LED_NO_MMES_TIMEOUT_0_SEC * 1000U ) +#define IDIBUS_LINK_LED_NO_MMES_TIMEOUT_1_SEC 15U +#define IDIBUS_LINK_LED_NO_MMES_TIMEOUT_1_MS ( IDIBUS_LINK_LED_NO_MMES_TIMEOUT_1_SEC * 1000U ) + +enum IDIBUS_RXTIMER_TIMEOUT_MODE { + IDIBUS_TIMER_MODE_RX_TIMEOUT = 0x00, + IDIBUS_TIMER_MODE_ALARM_TIMEOUT, + IDIBUS_TIMER_MODE_RESPONSE_TIMEOUT +}; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDISN_FIXP_Pos 0U +#define IDISN_FIXP_GS1_COUNTRY_Pos ( IDISN_FIXP_Pos + 0U) +#define IDISN_FIXP_GS1_COUNTRY_Length 3 +#define IDISN_FIXP_GS1_COMPANY_Pos ( IDISN_FIXP_GS1_COUNTRY_Pos + IDISN_FIXP_GS1_COUNTRY_Length ) +#define IDISN_FIXP_GS1_COMPANY_Length 6 +#define IDISN_FIXP_MODULE_TYPE_Pos ( IDISN_FIXP_GS1_COMPANY_Pos + IDISN_FIXP_GS1_COMPANY_Length ) +#define IDISN_FIXP_MODULE_TYPE_Length 3 +#define IDISN_FIXP_HW_REV_Pos ( IDISN_FIXP_MODULE_TYPE_Pos + IDISN_FIXP_MODULE_TYPE_Length ) +#define IDISN_FIXP_HW_REV_Length 2 +#define IDISN_FIXP_SERIAL_Pos ( IDISN_FIXP_HW_REV_Pos + IDISN_FIXP_HW_REV_Length ) +#define IDISN_FIXP_SERIAL_Length 7 +#define IDISN_FIXP_MAC_Pos ( IDISN_FIXP_SERIAL_Pos + IDISN_FIXP_SERIAL_Length ) +#define IDISN_FIXP_MAC_Length 6 +#define IDISN_FIXP_LENGTH ( IDISN_FIXP_GS1_COUNTRY_Length + IDISN_FIXP_GS1_COMPANY_Length + IDISN_FIXP_MODULE_TYPE_Length + \ +IDISN_FIXP_HW_REV_Length + IDISN_FIXP_SERIAL_Length + IDISN_FIXP_MAC_Length ) + +#define IDISN_VARP_Pos IDISN_FIXP_LENGTH +#define IDISN_VARP_SW_REV_Pos ( IDISN_VARP_Pos + 0U ) +#define IDISN_VARP_SW_REV_Length 2U +#define IDISN_VARP_VERIF_DATE_Pos ( IDISN_VARP_SW_REV_Pos + IDISN_VARP_SW_REV_Length ) +#define IDISN_VARP_VERIF_DATE_Length 4U +#define IDISN_VARP_EXPIR_DATE_Pos ( IDISN_VARP_VERIF_DATE_Pos + IDISN_VARP_VERIF_DATE_Length ) +#define IDISN_VARP_EXPIR_DATE_Length 4U +#define IDISN_VARP_IPv4_Pos ( IDISN_VARP_EXPIR_DATE_Pos + IDISN_VARP_EXPIR_DATE_Length ) +#define IDISN_VARP_IPv4_Length 4U +#define IDISN_VARP_IPv6_Pos ( IDISN_VARP_IPv4_Pos + IDISN_VARP_IPv4_Length ) +#define IDISN_VARP_IPv6_Length 16U +#define IDISN_VARP_AES256_Pos ( IDISN_VARP_IPv6_Pos + IDISN_VARP_IPv6_Length ) +#define IDISN_VARP_AES256_Length 32U +#define IDISN_VARP_LENGTH ( IDISN_VARP_SW_REV_Length + IDISN_VARP_VERIF_DATE_Length + IDISN_VARP_EXPIR_DATE_Length + \ +IDISN_VARP_IPv4_Length + IDISN_VARP_IPv6_Length + IDISN_VARP_AES256_Length ) + +#define IDISN_FULL_LENGTH ( IDISN_FIXP_LENGTH + IDISN_VARP_LENGTH ) +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define ISIBUS_MASTER_MAIN_ADDR 255U +#define ISIBUS_MASTER_SPARE_ADDR 254U +#define IDIBUS_SLAVE_ADDR_MIN 1U +#define IDIBUS_SLAVE_ADDR_MAX 229U +#define IDIBUS_DEVELOPER_ADDR_0 250U +#define IDIBUS_DEVELOPER_ADDR_1 251U +#define IDIBUS_DEVELOPER_ADDR_2 252U +#define IDIBUS_DEVELOPER_ADDR_3 253U +#define IDIBUS_GROUP_0_ADDR 230U +#define IDIBUS_GROUP_1_ADDR 231U +#define IDIBUS_GROUP_2_ADDR 232U +#define IDIBUS_GROUP_3_ADDR 233U +#define IDIBUS_GROUP_4_ADDR 234U +#define IDIBUS_GROUP_5_ADDR 235U +#define IDIBUS_GROUP_6_ADDR 236U +#define IDIBUS_GROUP_7_ADDR 237U +#define IDIBUS_GROUP_8_ADDR 238U +#define IDIBUS_GROUP_9_ADDR 239U +#define IDIBUS_GROUP_10_ADDR 240U +#define IDIBUS_GROUP_11_ADDR 241U +#define IDIBUS_GROUP_12_ADDR 242U +#define IDIBUS_GROUP_13_ADDR 243U +#define IDIBUS_GROUP_14_ADDR 244U +#define IDIBUS_GROUP_15_ADDR 245U + +#define IDIBUS_GROUPS_NUMBER 16U +#define IDIBUS_GROUP_FIRST_NUMBER 0U +#define IDIBUS_GROUP_LAST_NUMBER 15U +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDIMMES_ADDR_Pos 00U +#define IDIMMES_MMPS_Pos 01U +#define IDIMMES_MMPS_LONG_MES_Pos 0U +#define IDIMMES_MMPS_LONG_MES_Msk 0x01U +#define IDIMMES_MMPS_MES_TYPE_Pos 1U +#define IDIMMES_MMPS_MES_TYPE_Msk 0x02U +#define IDIMMES_MMPS_MES_TYPE_MMES 0x00U +#define IDIMMES_MMPS_MES_TYPE_MMESG 0x01U +#define IDIMMES_MMPS_FAST_FUNC_Pos 2U +#define IDIMMES_MMPS_FAST_FUNC_Msk 0x3CU +#define IDIMMES_MMPS_ALARM_FRAME_Pos 6U +#define IDIMMES_MMPS_ALARM_FRAME_Msk 0x40U +#define IDIMMES_MMPS_ENCRYPTED_AES_Pos 7U +#define IDIMMES_MMPS_ENCRYPTED_AES_Msk 0x80U +#define IDIMMES_DEV_Pos 02U +#define IDIMMES_DEV_NUM_Pos 0U +#define IDIMMES_DEV_NUM_Msk 0x1FU +#define IDIMMES_DEV_ALLCH_Pos 5U +#define IDIMMES_DEV_ALLCH_Msk 0x20U +#define IDIMMES_CHNL_Pos 03U +#define IDIMMES_CHNL_NUM_Pos 0U +#define IDIMMES_CHNL_NUM_Msk 0x7FU +#define IDIMMES_CHNL_ALLSAME_Pos 7U +#define IDIMMES_CHNL_ALLSAME_Msk 0x80U +#define IDIMMES_DATA_FUNC_COM_DATA_Pos 04U +#define IDIMMES_MAX_HEADER_LENGTH (IDIMMES_DATA_FUNC_COM_DATA_Pos + 1) +#define IDIMMES_MAX_DATA_SIZE 256U +#define IDIMMES_MAX_MES_SIZE (IDIMMES_MAX_DATA_SIZE + IDIMMES_MAX_HEADER_LENGTH + MODBUS_CRC16_SIZE) +#define IDIMMES_MIN_MES_SIZE (IDIMMES_DATA_FUNC_COM_DATA_Pos + MODBUS_CRC16_SIZE) + +#define IDIMMESG_DATA_COM_FUNC_Pos 02U +#define IDIMMESG_MAX_HEADER_LENGTH (IDIMMESG_DATA_COM_FUNC_Pos + 1) +#define IDIMMESG_MAX_DATA_SIZE IDIMMES_MAX_DATA_SIZE +#define IDIMMESG_MAX_MES_SIZE (IDIMMESG_MAX_DATA_SIZE + IDIMMESG_MAX_HEADER_LENGTH + MODBUS_CRC16_SIZE) +#define IDIMMESG_MODULE_MIN_MES_SIZE (IDIMMESG_DATA_COM_FUNC_Pos + 1 + MODBUS_CRC16_SIZE) +#define IDIMMESG_GROUP_MIN_MES_SIZE (IDIMMESG_DATA_COM_FUNC_Pos + MODBUS_CRC16_SIZE) + +#define IDIMMES_LMES_MSIZE_Pos 0U +#define IDIMMES_LMES_BSIZE_Pos (IDIMMES_LMES_MSIZE_Pos + 4U) +#define IDIMMES_LMES_IDENTIFIER_LENGTH (IDIMMES_LMES_BSIZE_Pos + 1U) +#define IDIMMES_LMES_BSIZE_256B 0U +#define IDIMMES_LMES_BSIZE_1K 1U +#define IDIMMES_LMES_BSIZE_4K 2U +#define IDIMMES_LMES_BSIZE_8K 3U +#define IDIMMES_LMES_BSIZE_16K 4U +#define IDIMMES_LMES_BSIZE_32K 5U +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDISMES_ADDR_Pos 00U +#define IDISMES_SMPS_Pos 01U +#define IDISMES_SMPS_ERROR_BIT_Pos 0U +#define IDISMES_SMPS_LONG_MES_Pos 1U +#define IDISMES_SMPS_LONG_OP_Pos 2U +#define IDISMES_ERROR_Pos 02U +#define IDISMES_DATA_Pos 03U +#define IDISMES_MAX_DATA_SIZE 256U +#define IDISMES_MIN_MES_SIZE (IDISMES_DATA_Pos + MODBUS_CRC16_SIZE) +#define IDISMES_MAX_MES_SIZE (IDISMES_DATA_Pos + IDISMES_MAX_DATA_SIZE + MODBUS_CRC16_SIZE) +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDILONGOP_STATE_COMPLETE_NO_ERR 0x00U +#define IDILONGOP_STATE_IN_PROC 0x01U +#define IDILONGOP_STATE_COMPLETE_WITH_ERR 0x02U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDILONGOP_MES_DATA_LENGTH 5U +#define IDILONGOP_STATE_Pos 0U +#define IDILONGOP_REMAIN_TIME_Pos 1U +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDISTATUS_B0S_Pos 00U +#define IDISTATUS_B0S_ST_ERROR_Pos 0U +#define IDISTATUS_B0S_ST_STATE_Pos 1U +#define IDISTATUS_B0S_ST_STATE_Msk 0x07U +#define IDISTATUS_B0S_ST_STATE_StNoInit 0x00U +#define IDISTATUS_B0S_ST_STATE_StOperate 0x01U +#define IDISTATUS_B0S_ST_STATE_StFreeze 0x02U +#define IDISTATUS_B0S_ST_STATE_StVirtual 0x03U +#define IDISTATUS_B0S_ST_STATE_StFirmwareUpd 0x04U +#define IDISTATUS_B0S_ST_STATE_StReservedMaster 0x05U +#define IDISTATUS_B0S_ST_STATE_StBroken 0x06U +#define IDISTATUS_B0S_ST_STATE_StReserved0 0x07U +#define IDISTATUS_B0S_AES_SUPPORTED_Pos 4U +#define IDISTATUS_B0S_AES_INSTALLED_Pos 5U +#define IDISTATUS_B0S_SEND_ALARM_L0_Pos 6U +#define IDISTATUS_B0S_SEND_ALARM_L1_Pos 7U + +#define IDISTATUS_B1S_Pos 01U +#define IDISTATUS_B1S_MODULE_TYPE_Pos 0U +#define IDISTATUS_B1S_MODULE_TYPE_Msk 0x03U +#define IDISTATUS_B1S_MODULE_TYPE_Master 0x00U +#define IDISTATUS_B1S_MODULE_TYPE_SpareMaster 0x01U +#define IDISTATUS_B1S_MODULE_TYPE_Slave 0x02U +#define IDISTATUS_B1S_MODULE_TYPE_Bridge 0x03U +#define IDISTATUS_B1S_BRIDGE_CONNECTED_Pos 2U +#define IDISTATUS_B1S_SELF_INIT_Pos 3U +#define IDISTATUS_B1S_TIMEOUT_LED_Pos 4U +#define IDISTATUS_B1S_NO_MMES_TIMEOUT_Pos 5U +#define IDISTATUS_B1S_CATCH_ALARM_L0_Pos 6U +#define IDISTATUS_B1S_CATCH_ALARM_L1_Pos 7U + +#define IDISTATUS_SN_Pos 02U +#define IDISTATUS_LENGTH ( IDISTATUS_SN_Pos + IDISN_FULL_LENGTH ) +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDIMMES_NOT_FAST_FUNC 0U +#define IDIMMES_MAX_FAST_FUNC_NUM 15U +#define IDIMMES_COM_START_NUM 220U +#define IDIMMES_COM_C_Init 220U +#define IDIMMES_COM_C_ShtDown 221U +#define IDIMMES_COM_C_Freeze 222U +#define IDIMMES_COM_C_Resume 223U +#define IDIMMES_COM_C_Dummy 224U +#define IDIMMES_COM_C_AssignGroup 225U +#define IDIMMES_COM_C_SetAlarmL12 226U +#define IDIMMES_COM_C_SetAlarmL 227U +#define IDIMMES_COM_C_Virtual 228U +#define IDIMMES_COM_C_SyncReadChnl 229U +#define IDIMMES_COM_C_SyncRead 230U +#define IDIMMES_COM_C_SyncDoChnl 231U +#define IDIMMES_COM_C_SyncDo 232U +#define IDIMMES_COM_C_SyncClear 233U +#define IDIMMES_COM_C_BurstReadCnt 234U +#define IDIMMES_COM_C_BurstReadTime 235U +#define IDIMMES_COM_C_SendTimeDate 236U +#define IDIMMES_COM_C_MkTimedMaster 237U +#define IDIMMES_COM_C_FmwUpd 238U +#define IDIMMES_COM_C_EndFmwUpd 239U +#define IDIMMES_COM_C_FmwWrite 240U +#define IDIMMES_COM_C_ReadDevFullSN_MS 241U +#define IDIMMES_COM_C_WriteSnIPv4IPv6 242U +#define IDIMMES_COM_C_WriteSnVerifyDates 243U +#define IDIMMES_COM_C_WriteSnAES256 244U +#define IDIMMES_COM_C_SendLongMessage 245U +#define IDIMMES_COM_C_GetLondMessage 246U +#define IDIMMES_COM_C_DummyModule 247U +#define IDIMMES_COM_C_CheckModuleLongOp 248U +#define IDIMMES_COM_C_CheckChannelLongOp 249U +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDIER_MODBUS_NUM_START 1U +#define IDIER_MODBUS_NUM_END 9U +#define IDIER_MODULE_MASTER_NUM_START 10U +#define IDIER_MODULE_MASTER_NUM_END 32U +#define IDIER_MODULE_SLAVE_NUM_START 33U +#define IDIER_MODULE_SLAVE_NUM_END 71U +#define IDIER_MODULE_NUM_START IDIER_MODULE_MASTER_NUM_START +#define IDIER_MODULE_NUM_END IDIER_MODULE_SLAVE_NUM_END +#define IDIER_DEVICE_NUM_START 72U +#define IDIER_DEVICE_NUM_END 89U + +#define IDIER_NOPE 0U +#define MODBUSER_WRONGFUNC 1U +#define MODBUSER_WRONGADDR 2U +#define MODBUSER_WRONGDATA 3U +#define MODBUSER_BROKE 4U +#define MODBUSER_LONGCOMMAND 5U +#define MODBUSER_BUSY 6U +#define MODBUSER_CANTDOFUNC 7U +#define MODBUSER_EXTMEMORYERROR 8U +#define MODBUSER_RESERVED 9U +#define IDIERMST_INVALID_ADDR_NUM 10U +#define IDIERMST_INVALID_DEV_NUM 11U +#define IDIERMST_INVALID_CHN_NUM 12U +#define IDIERMST_INVALID_FUNC_NUM 13U +#define IDIERMST_INVALID_TX_REQUEST_FORMAT 14U +#define IDIERMST_INVALID_TX_PARAM 15U +#define IDIERMST_TX_MES 16U +#define IDIERMST_RCV_TIMEOUT 17U +#define IDIERMST_MES_RX_INTEGRITY 18U +#define IDIERMST_CRC 19U +#define IDIERMST_MULTIPLE_CRC 20U +#define IDIERMST_INVALID_RX_REQUEST_FORMAT 21U +#define IDIERMST_INVALID_RX_PARAM 22U +#define IDIERMST_RESEVED_23 23U +#define IDIERMST_RESEVED_24 24U +#define IDIERMST_RESEVED_25 25U +#define IDIERMST_RESEVED_26 26U +#define IDIERMST_RESEVED_27 27U +#define IDIERMST_EXTRA_28 28U +#define IDIERMST_EXTRA_29 29U +#define IDIERMST_EXTRA_30 30U +#define IDIERMST_EXTRA_31 31U +#define IDIERMST_EXTRA_32 32U +#define IDIERSLV_RESEVED_33 33U +#define IDIERSLV_ENCRYPTION_NOT_SUPPORTED 34U +#define IDIERSLV_ENCRYPTION_NOT_INSTALLED 35U +#define IDIERSLV_JUMBO_NOT_SUPPORTED 36U +#define IDIERSLV_UNSUPPORTED_FUNC_NUM 37U +#define IDIERSLV_INVALID_RX_REQUEST_FORMAT 38U +#define IDIERSLV_INVALID_RX_PARAM 39U +#define IDIERSLV_IN_FREEZE 40U +#define IDIERSLV_RESERVED_41 41U +#define IDIERSLV_RESERVED_42 42U +#define IDIERSLV_RESERVED_43 43U +#define IDIERSLV_RESERVED_44 44U +#define IDIERSLV_RESERVED_45 45U +#define IDIERSLV_EXTRA_46 46U +#define IDIERSLV_EXTRA_47 47U +#define IDIERSLV_EXTRA_48 48U +#define IDIERSLV_EXTRA_49 49U +#define IDIERSLV_EXTRA_50 50U +#define IDIERSLV_BROKE 51U +#define IDIERSLV_NO_FIRMWARE 52U +#define IDIERSLV_NO_INIT 53U +#define IDIERSLV_OVERHEAT 54U +#define IDIERSLV_INP_VOLTAGE 55U +#define IDIERSLV_BRIDGE_OVERFLOW 56U +#define IDIERSLV_BRIDGE_NOT_CONF 57U +#define IDIERSLV_VERIF_DATE 58U +#define IDIERSLV_RTC 59U +#define IDIERSLV_LONG_OP_IN_PROC 60U +#define IDIERSLV_RESERVED_61 61U +#define IDIERSLV_RESERVED_62 62U +#define IDIERSLV_RESERVED_63 63U +#define IDIERSLV_RESERVED_64 64U +#define IDIERSLV_RESERVED_65 65U +#define IDIERSLV_RESERVED_66 66U +#define IDIERSLV_EXTRA_67 67U +#define IDIERSLV_EXTRA_68 68U +#define IDIERSLV_EXTRA_69 69U +#define IDIERSLV_EXTRA_70 70U +#define IDIERSLV_EXTRA_71 71U +#define IDIERDEV_INVALID_DEV_NUM 72U +#define IDIERDEV_INVALID_CHN_NUM 73U +#define IDIERDEV_INVALID_FUNC_NUM 74U +#define IDIERDEV_LONG_OP_IN_PROC 75U +#define IDIERDEV_RESERVED_76 76U +#define IDIERDEV_PARAM_LOW_ST_TIMEOUT 77U +#define IDIERDEV_PARAM_HIGH_ST_TIMEOUT 78U +#define IDIERDEV_PARAM_NOT_CHANGE_TIMEOUT 79U +#define IDIERDEV_RESERVED_80 80U +#define IDIERDEV_RESERVED_81 81U +#define IDIERDEV_RESERVED_82 82U +#define IDIERDEV_RESERVED_83 83U +#define IDIERDEV_RESERVED_84 84U +#define IDIERDEV_RESERVED_85 85U +#define IDIERDEV_RESERVED_86 86U +#define IDIERDEV_RESERVED_87 87U +#define IDIERDEV_RESERVED_88 88U +#define IDIERDEV_RESERVED_89 89U + +#define IDIER_MULTIPLE_CRC_AVRBUF_SIZE 16U +#define IDIER_MULTIPLE_CRC_AVRBUF_THR 5U +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDIDATE_FORMAT_DAY_Pos 0U +#define IDIDATE_FORMAT_MONTH_Pos 1U +#define IDIDATE_FORMAT_CENTURY_Pos 2U +#define IDIDATE_FORMAT_YEAR99_Pos 3U +#define IDIDATE_FORMAT_LENGTH 4U + +#define IDITIME_FORMAT_SECONDS_Pos 0U +#define IDITIME_FORMAT_MINUTES_Pos 1U +#define IDITIME_FORMAT_HOURS_Pos 2U +#define IDITIME_FORMAT_TIMEZONE_Pos 3U +#define IDITIME_FORMAT_LENGTH 4U + +#define IDITIME_FORMAT_TIMEZONE_MIN (-12) +#define IDITIME_FORMAT_TIMEZONE_MAX 14 + +#define IDIMMES_C_DATETIME_TIME_Pos 0 +#define IDIMMES_C_DATETIME_DATE_Pos (IDIMMES_C_DATETIME_TIME_Pos + IDIDATE_FORMAT_LENGTH) +#define IDIMMES_C_DATETIME_LENGTH (IDIDATE_FORMAT_LENGTH + IDITIME_FORMAT_LENGTH) +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +typedef struct { + struct { + uint8_t StError : 1; + uint8_t StState : 3; + uint8_t AesSupported : 1; + uint8_t AesInstalled : 1; + uint8_t SendAlarmL0 : 1; + uint8_t SendAlarmL1 : 1; + } B0S; + struct { + uint8_t ModuleType : 2; + uint8_t BridgeConnected : 1; + uint8_t SelfInit : 1; + uint8_t TimeoutLed : 1; + uint8_t NoMMESTimeout : 1; + uint8_t CatchAlarmL0 : 1; + uint8_t CatchAlarmL1 : 1; + } B1S; +} IDISTATUS_STATE_TYPE; +//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------s +typedef struct { + IDISTATUS_STATE_TYPE STATE; + uint8_t SN[IDISN_FULL_LENGTH]; +} IDISTATUS_SLAVE_TYPE; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //_INC_IDIBUS_DEFS_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/MODBUS_CRC.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/MODBUS_CRC.cpp new file mode 100644 index 0000000..ef339dd --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/MODBUS_CRC.cpp @@ -0,0 +1,134 @@ +//################################################################################################################################################### +#include "MODBUS_CRC.h" +//--------------------------------------------------------------------------------------------------------------------------------------------------- +// Table of CRC values for highorder byte FLASH Variant +const uint8_t MODBUS_auchCRCHi_PR[] PROGMEM = { +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, +0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, +0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40 +}; +// Table of CRC values for loworder byte +const uint8_t MODBUS_auchCRCLo_PR[] PROGMEM = { +0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, +0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, +0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, +0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, +0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, +0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, +0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, +0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, +0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, +0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, +0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, +0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, +0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, +0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, +0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, +0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, +0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, +0x40 +}; +//--------------------------------------------------------------------------------------------------------------------------------------------------- +// Table of CRC values for highorder byte RAM Variant +uint8_t MODBUS_auchCRCHi_R[] = { +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, +0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, +0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40 +}; +// Table of CRC values for loworder byte +uint8_t MODBUS_auchCRCLo_R[] = { +0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, +0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, +0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, +0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, +0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, +0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, +0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, +0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, +0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, +0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, +0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, +0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, +0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, +0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, +0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, +0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, +0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, +0x40 +}; +//--------------------------------------------------------------------------------------------------------------------------------------------------- +uint16_t MODBUS_CRC16::CRC16_TF(uint8_t *MODBUS_puchMsg, uint16_t MODBUS_usDataLen) +{ + uint8_t MODBUS_uchCRCHi = 0xFF; // high byte of CRC initialized + uint8_t MODBUS_uchCRCLo = 0xFF; // low byte of CRC initialized + uint8_t MODBUS_uIndex; + while (MODBUS_usDataLen--) + { + MODBUS_uIndex = MODBUS_uchCRCLo ^ (*MODBUS_puchMsg++); // calculate the CRC + MODBUS_uchCRCLo = MODBUS_uchCRCHi ^ pgm_read_byte(&MODBUS_auchCRCHi_PR[MODBUS_uIndex]); + MODBUS_uchCRCHi = pgm_read_byte(&MODBUS_auchCRCLo_PR[MODBUS_uIndex]); + } + return ( ((uint16_t)MODBUS_uchCRCHi << 8 ) | MODBUS_uchCRCLo ); +} +//--------------------------------------------------------------------------------------------------------------------------------------------------- +uint16_t MODBUS_CRC16::CRC16_TR(uint8_t *MODBUS_puchMsg, uint16_t MODBUS_usDataLen) +{ + uint8_t MODBUS_uchCRCHi = 0xFF; // high byte of CRC initialized + uint8_t MODBUS_uchCRCLo = 0xFF; // low byte of CRC initialized + uint8_t MODBUS_uIndex; + while (MODBUS_usDataLen--) + { + MODBUS_uIndex = MODBUS_uchCRCLo ^ (*MODBUS_puchMsg++); // calculate the CRC + MODBUS_uchCRCLo = MODBUS_uchCRCHi ^ MODBUS_auchCRCHi_R[MODBUS_uIndex]; + MODBUS_uchCRCHi = MODBUS_auchCRCLo_R[MODBUS_uIndex]; + } + return (((uint16_t)MODBUS_uchCRCHi << 8) | MODBUS_uchCRCLo); +} +//--------------------------------------------------------------------------------------------------------------------------------------------------- +uint16_t MODBUS_CRC16::CRC16_S(uint8_t *MODBUS_buf, uint16_t MODBUS_len) +{ + uint16_t MODBUS_crc = 0xFFFF; + for (uint16_t MODBUS_pos = 0; MODBUS_pos < MODBUS_len; MODBUS_pos++) + { + MODBUS_crc ^= MODBUS_buf[MODBUS_pos]; // XOR byte into least sig. byte of crc + for (uint8_t MODBUS_i = 8; MODBUS_i != 0; MODBUS_i--) // Loop over each bit + { + if ((MODBUS_crc & 0x0001) != 0) { MODBUS_crc >>= 1; MODBUS_crc ^= 0xA001; } // If the LSB is set // Shift right and XOR 0xA001 + else { MODBUS_crc >>= 1; } // Else LSB is not set // Just shift right + } + } + + return MODBUS_crc; +} +//--------------------------------------------------------------------------------------------------------------------------------------------------- +//################################################################################################################################################### diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/MODBUS_CRC.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/MODBUS_CRC.h new file mode 100644 index 0000000..703e77d --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusLib/MODBUS_CRC.h @@ -0,0 +1,20 @@ +//################################################################################################################################################### +#ifndef _MODBUS_CRC_H_ +#define _MODBUS_CRC_H_ +//--------------------------------------------------------------------------------------------------------------------------------------------------- +#include "avr/io.h" +#include +#include +//--------------------------------------------------------------------------------------------------------------------------------------------------- +#define MODBUS_CRC16_SIZE 2 +//--------------------------------------------------------------------------------------------------------------------------------------------------- +class MODBUS_CRC16 { + public : + static uint16_t CRC16_TF(uint8_t *MODBUS_puchMsg, uint16_t MODBUS_usDataLen); + static uint16_t CRC16_TR(uint8_t *MODBUS_puchMsg, uint16_t MODBUS_usDataLen); + static uint16_t CRC16_S(uint8_t *MODBUS_buf, uint16_t MODBUS_len); + private : + }; +//--------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _CRC_MODBUS_ +//################################################################################################################################################### \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusSlaves/IDIBUS_4DC.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusSlaves/IDIBUS_4DC.cpp new file mode 100644 index 0000000..83518fd --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusSlaves/IDIBUS_4DC.cpp @@ -0,0 +1,663 @@ +//############################################################################################################################################################################################################# +#include "IDIBUS_4DC.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusDevice *IdiBus_4DC::getDevice(uint8_t Num) +{ + switch (Num) + { + case ( IDIBUS_PSU_CNTRL_DEV ) : { return &this->PSUC_DEV; } + case ( IDIBUS_INPV_CNTRL_DEV ) : { return &this->INPV_DEV; } + default : { return NULL; } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +IdiBus_4DC_PSUChannel::IdiBus_4DC_PSUChannel(void) : IdiBusChannel() +{ + this->TargetVoltage = 0; + this->CurrentLimit = 0; + this->Voltage = 0; + this->Current = 0; + this->STATUS.Enable = 0; + this->STATUS.PowerGood = 0; + this->STATUS.ERRORS.Sum = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusChannel *IdiBus_4DC_PSUCDevice::getChannel(uint8_t Num) +{ + if ( Num < IDIBUS_4DC_CH_COUNT ) { return &this->CH[Num]; } + else { return NULL; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBus_4DC_PSUChannel IdiBus_4DC_PSUCDevice::getChData(uint8_t ChNum) +{ + if ( ChNum < IDIBUS_4DC_CH_COUNT ) { return this->CH[ChNum]; } + else { IdiBus_4DC_PSUChannel NewData; return NewData; } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +IdiBus_4DC_INPVChannel::IdiBus_4DC_INPVChannel(void) : IdiBusChannel() +{ + this->InpVoltage = 0; + this->STATUS.Sum = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusChannel *IdiBus_4DC_INPVCDevice::getChannel(uint8_t Num) +{ + if ( Num == 0 ) { return &this->INPV; } + else { return NULL; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBus_4DC_INPVChannel IdiBus_4DC_INPVCDevice::getChData(void) +{ + return this->INPV; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_INPVCDevice::getInputVoltage(void) +{ + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_INPV_CNTRL_DEV; + MMES.CHNL.NUM = 0; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_GET_INP_VOLTAGE; + uint8_t ChDataSize = IDIBUS_CUSTDEF_PSUINPV_MES_LENGTH; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->INPV.MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->INPV.MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->INPV.MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } +else { + this->INPV.MMES_Error = MMES.RxData[0]; + if ( this->INPV.MMES_Error == IDIER_NOPE ) + { + uint8_t *Data = &MMES.RxData[1]; + if ( (Data[IDIBUS_CUSTDEF_PSUINPV_STATE_Pos] & (1U << IDIBUS_CUSTDEF_PSUINPV_STATE_UV_Pos)) != 0 ) { this->INPV.STATUS.BF.Undervoltage = 1; } + else { this->INPV.STATUS.BF.Undervoltage = 0; } + if ( (Data[IDIBUS_CUSTDEF_PSUINPV_STATE_Pos] & (1U << IDIBUS_CUSTDEF_PSUINPV_STATE_OV_Pos)) != 0 ) { this->INPV.STATUS.BF.Overvoltage = 1; } + else { this->INPV.STATUS.BF.Overvoltage = 0; } + this->INPV.InpVoltage = (uint16_t)( (uint16_t)Data[IDIBUS_CUSTDEF_PSUINPV_VOLTAGE_Pos] << 8 ) | MMES.RxData[IDIBUS_CUSTDEF_PSUINPV_VOLTAGE_Pos + 1]; + } + } + return this->INPV.MMES_Error; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::getChOutputVoltage(uint8_t ChNum) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_VOLTAGE; + uint8_t ChDataSize = 4; //int32_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Voltage = (int32_t) ( + (uint32_t)((uint32_t)MMES.RxData[1] << 24) | + (uint32_t)((uint32_t)MMES.RxData[2] << 16) | + (uint32_t)((uint32_t)MMES.RxData[3] << 8) | + (uint32_t)((uint32_t)MMES.RxData[4]) ); + } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::getAllChOutputVoltage(void) +{ + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_VOLTAGE; + uint8_t ChDataSize = 4; //int32_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4DC_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4DC_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->CH[I].Voltage = (int32_t) ( + (uint32_t)((uint32_t)MMES.RxData[DataPos] << 24) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+1] << 16) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+2] << 8) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+3]) ); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::getChOutputCurrent(uint8_t ChNum) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_CURRENT; + uint8_t ChDataSize = 4; //int32_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Current = (int32_t) ( + (uint32_t)((uint32_t)MMES.RxData[1] << 24) | + (uint32_t)((uint32_t)MMES.RxData[2] << 16) | + (uint32_t)((uint32_t)MMES.RxData[3] << 8) | + (uint32_t)((uint32_t)MMES.RxData[4]) ); + } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::getAllChOutputCurrent(void) +{ + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_CURRENT; + uint8_t ChDataSize = 4; //int32_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4DC_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4DC_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->CH[I].Current = (int32_t) ( + (uint32_t)((uint32_t)MMES.RxData[DataPos] << 24) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+1] << 16) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+2] << 8) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+3]) ); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::getChStatus(uint8_t ChNum) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_STATUS; + uint8_t ChDataSize = IDIBUS_CUSTDEF_PSUCH_STBUF_SIZE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->parsePsuChState(&MMES.RxData[1], ChNum); } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::getAllChStatus(void) +{ + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_STATUS; + uint8_t ChDataSize = IDIBUS_CUSTDEF_PSUCH_STBUF_SIZE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4DC_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4DC_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->parsePsuChState(&MMES.RxData[DataPos], I); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::getChAllData(uint8_t ChNum) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_ALLDATA; + uint8_t ChDataSize = IDIBUS_CUSTDEF_PSUCH_STALLBUF_SIZE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->parsePsuChAllState(&MMES.RxData[1], ChNum); } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::getAllChAllData(void) +{ + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_ALLDATA; + uint8_t ChDataSize = IDIBUS_CUSTDEF_PSUCH_STALLBUF_SIZE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4DC_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4DC_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->parsePsuChAllState(&MMES.RxData[DataPos], I); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::setChState(uint8_t ChNum, uint8_t State) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + if ( State != 0 ) { State = IDIBUS_CUSTDEF_PSU_CH_STATE_ENABLE; } + else { State = IDIBUS_CUSTDEF_PSU_CH_STATE_DISABLE; } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &State, 1); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->CH[ChNum].STATUS.Enable = State; } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChState(uint8_t State) +{ + if ( State != 0 ) { State = IDIBUS_CUSTDEF_PSU_CH_STATE_ENABLE; } + else { State = IDIBUS_CUSTDEF_PSU_CH_STATE_DISABLE; } + + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &State, 1); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.CHNL.ALLSAME = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].STATUS.Enable = State; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChState(uint8_t Ch1State, uint8_t Ch2State, uint8_t Ch3State, uint8_t Ch4State) +{ + uint8_t State[IDIBUS_4DC_CH_COUNT] = { Ch1State, Ch2State, Ch3State, Ch4State }; + for (uint8_t I=0; I(this->Module)->getAddress() , &State[0], IDIBUS_4DC_CH_COUNT); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].STATUS.Enable = State[I]; } + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::setChVoltage(uint8_t ChNum, uint16_t TargetVoltage) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + if ( (TargetVoltage < IDIBUS_PSU_CH_TARG_V_MIN_mV) || (TargetVoltage > IDIBUS_PSU_CH_TARG_V_MAX_mV) ) + { + this->CH[ChNum].MMES_Error = IDIERMST_INVALID_TX_PARAM; + return IDIERMST_INVALID_TX_PARAM; + } + uint8_t TxData[2]; + TxData[0] = (uint8_t)(TargetVoltage >> 8); + TxData[1] = (uint8_t)(TargetVoltage); + + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_TARGET_VOLTAGE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->CH[ChNum].TargetVoltage = TargetVoltage; } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChVoltage(uint16_t TargetVoltage) +{ + if ( (TargetVoltage < IDIBUS_PSU_CH_TARG_V_MIN_mV) || (TargetVoltage > IDIBUS_PSU_CH_TARG_V_MAX_mV) ) { this->setAllPsuChErr(IDIERMST_INVALID_TX_PARAM); return; } + uint8_t TxData[2]; + TxData[0] = (uint8_t)(TargetVoltage >> 8); + TxData[1] = (uint8_t)(TargetVoltage); + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.CHNL.ALLSAME = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_TARGET_VOLTAGE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].TargetVoltage = TargetVoltage; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChVoltage(uint16_t TV_CH1, uint16_t TV_CH2, uint16_t TV_CH3, uint16_t TV_CH4) +{ + uint16_t TargetV[IDIBUS_4DC_CH_COUNT] = { TV_CH1, TV_CH2, TV_CH3, TV_CH4 }; + uint8_t TxData[IDIBUS_4DC_CH_COUNT * 2]; + for (uint8_t I=0, J=0; I> 8); + TxData[J+1] = (uint8_t)(TargetV[I]); + } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], IDIBUS_4DC_CH_COUNT * 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_TARGET_VOLTAGE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].TargetVoltage = TargetV[I]; } + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::setChCurrentLimit(uint8_t ChNum, uint16_t CurrentLimit) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + if ( (CurrentLimit < IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MIN) || (CurrentLimit > IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MAX) ) + { + this->CH[ChNum].MMES_Error = IDIERMST_INVALID_TX_PARAM; + return IDIERMST_INVALID_TX_PARAM; + } + uint8_t TxData[2]; + TxData[0] = (uint8_t)(CurrentLimit >> 8); + TxData[1] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_CURRENT_LIMIT; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->CH[ChNum].CurrentLimit = CurrentLimit; } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChCurrentLimit(uint16_t CurrentLimit) +{ + if ( (CurrentLimit < IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MIN) || (CurrentLimit > IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MAX) ) { this->setAllPsuChErr(IDIERMST_INVALID_TX_PARAM); return; } + uint8_t TxData[2]; + TxData[0] = (uint8_t)(CurrentLimit >> 8); + TxData[1] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.CHNL.ALLSAME = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_CURRENT_LIMIT; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].CurrentLimit = CurrentLimit; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChCurrentLimit(uint16_t CL_CH1, uint16_t CL_CH2, uint16_t CL_CH3, uint16_t CL_CH4) +{ + uint16_t CurrentL[IDIBUS_4DC_CH_COUNT] = { CL_CH1, CL_CH2, CL_CH3, CL_CH4 }; + uint8_t TxData[IDIBUS_4DC_CH_COUNT * 2]; + for (uint8_t I=0, J=0; I> 8); + TxData[J+1] = (uint8_t)(CurrentL[I]); + } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], IDIBUS_4DC_CH_COUNT * 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_CURRENT_LIMIT; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].CurrentLimit = CurrentL[I]; } + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::setChVoltageAndCurrentLimit(uint8_t ChNum, uint16_t TargetVoltage, uint16_t CurrentLimit) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + if ( (CurrentLimit < IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MIN) || (CurrentLimit > IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MAX) || + (TargetVoltage < IDIBUS_PSU_CH_TARG_V_MIN_mV) || (TargetVoltage > IDIBUS_PSU_CH_TARG_V_MAX_mV) ) + { + this->CH[ChNum].MMES_Error = IDIERMST_INVALID_TX_PARAM; + return IDIERMST_INVALID_TX_PARAM; + } + uint8_t TxData[4]; + TxData[0] = (uint8_t)(TargetVoltage >> 8); + TxData[1] = (uint8_t)(TargetVoltage); + TxData[2] = (uint8_t)(CurrentLimit >> 8); + TxData[3] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 4); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_ALL; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->CH[ChNum].TargetVoltage = TargetVoltage; this->CH[ChNum].CurrentLimit = CurrentLimit; } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChVoltageAndCurrentLimit(uint16_t TargetVoltage, uint16_t CurrentLimit) +{ + if ( (CurrentLimit < IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MIN) || (CurrentLimit > IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MAX) || + (TargetVoltage < IDIBUS_PSU_CH_TARG_V_MIN_mV) || (TargetVoltage > IDIBUS_PSU_CH_TARG_V_MAX_mV) ) { this->setAllPsuChErr(IDIERMST_INVALID_TX_PARAM); return; } + uint8_t TxData[4]; + TxData[0] = (uint8_t)(TargetVoltage >> 8); + TxData[1] = (uint8_t)(TargetVoltage); + TxData[2] = (uint8_t)(CurrentLimit >> 8); + TxData[3] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 4); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.CHNL.ALLSAME = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_ALL; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].TargetVoltage = TargetVoltage; this->CH[I].CurrentLimit = CurrentLimit; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChVoltageAndCurrentLimit(uint16_t VCH1, uint16_t CCH1, uint16_t VCH2, uint16_t CCH2, uint16_t VCH3, uint16_t CCH3, uint16_t VCH4, uint16_t CCH4) +{ + uint16_t CurrentL[IDIBUS_4DC_CH_COUNT] = { CCH1, CCH2, CCH3, CCH4 }; + uint16_t TargetV[IDIBUS_4DC_CH_COUNT] = { VCH1, VCH2, VCH3, VCH4 }; + uint8_t TxData[IDIBUS_4DC_CH_COUNT * 4]; + for (uint8_t I=0, J=0; I> 8); + TxData[J+1] = (uint8_t)(TargetV[I]); + TxData[J+2] = (uint8_t)(CurrentL[I] >> 8); + TxData[J+3] = (uint8_t)(CurrentL[I]); + } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], IDIBUS_4DC_CH_COUNT * 4); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_ALL; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].TargetVoltage = TargetV[I]; this->CH[I].CurrentLimit = CurrentL[I]; } + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +void IdiBus_4DC_PSUCDevice::parsePsuChState(uint8_t *State, uint8_t ChNum) +{ + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_EN_Pos)) != 0 ) { this->CH[ChNum].STATUS.Enable = 1; } + else { this->CH[ChNum].STATUS.Enable = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_PG_Pos)) != 0 ) { this->CH[ChNum].STATUS.PowerGood = 1; } + else { this->CH[ChNum].STATUS.PowerGood = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_PERIPH_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.PeripheryError = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.PeripheryError = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OVERCURRENT_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.OvercurrentError = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.OvercurrentError = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OVERVOLTAGE_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.OvervoltageError = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.OvervoltageError = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OFFSTATELEAKAGE_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.OffStateCurrentLeakage = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.OffStateCurrentLeakage = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_MEMORY_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.MemoryError = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.MemoryError = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_INPV_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.InpVoltageError = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.InpVoltageError = 0; } + this->CH[ChNum].TargetVoltage = (uint16_t)( (uint16_t)((uint16_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_TARGET_VOLATGE_Pos] << 8) | State[IDIBUS_CUSTDEF_PSUCH_STBUF_TARGET_VOLATGE_Pos + 1] ); + this->CH[ChNum].CurrentLimit = (uint16_t)( (uint16_t)((uint16_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_CURRENT_LIMIT_Pos] << 8) | State[IDIBUS_CUSTDEF_PSUCH_STBUF_CURRENT_LIMIT_Pos + 1] ); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::parsePsuChAllState(uint8_t *State, uint8_t ChNum) +{ + this->parsePsuChState(&State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos], ChNum); + this->CH[ChNum].Voltage = (int32_t) ( + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos] << 24) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos + 1] << 16) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos + 2] << 8) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos + 3]) ); + this->CH[ChNum].Current = (int32_t) ( + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos] << 24) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos + 1] << 16) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos + 2] << 8) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos + 3]) ); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllPsuChErr(uint8_t ErrCode) +{ + for (uint8_t I=0; ICH[I].MMES_Error = ErrCode; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusSlaves/IDIBUS_4DC.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusSlaves/IDIBUS_4DC.h new file mode 100644 index 0000000..5806b2a --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Arduino/_lib/IdiBusSlaves/IDIBUS_4DC.h @@ -0,0 +1,178 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_4DC_H_ +#define _IDIBUS_4DC_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSlave.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_PSU_CH_STATE_DISABLE 0x00 +#define IDIBUS_CUSTDEF_PSU_CH_STATE_ENABLE 0x01 + +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE 0x01 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_VOLTAGE 0x02 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_CURRENT 0x03 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_STATUS 0x04 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_ALLDATA 0x05 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_TARGET_VOLTAGE 0x06 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_CURRENT_LIMIT 0x07 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_ALL 0x08 +#define IDIBUS_CUSTDEF_FUNC_CODE_GET_INP_VOLTAGE 0x09 +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_ERCODE_INVALID_DATA 100U +#define IDIBUS_CUSTDEF_ERCODE_NO_ACCESS 101U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_PSUCH_GET_CV_MES_LENGTH 4U + +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos 00U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_EN_Pos 0U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_PG_Pos 1U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_PERIPH_ERR_Pos 2U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OVERCURRENT_ERR_Pos 3U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OVERVOLTAGE_ERR_Pos 4U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OFFSTATELEAKAGE_ERR_Pos 5U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_MEMORY_ERR_Pos 6U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_INPV_ERR_Pos 7U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_TARGET_VOLATGE_Pos 01U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_CURRENT_LIMIT_Pos 03U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_SIZE 05U + +#define IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos IDIBUS_CUSTDEF_PSUCH_STBUF_SIZE +#define IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos (IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos + 4) +#define IDIBUS_CUSTDEF_PSUCH_STALLBUF_SIZE (IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos + 4) +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_PSUINPV_STATE_Pos 00U +#define IDIBUS_CUSTDEF_PSUINPV_STATE_UV_Pos 0U +#define IDIBUS_CUSTDEF_PSUINPV_STATE_OV_Pos 1U +#define IDIBUS_CUSTDEF_PSUINPV_VOLTAGE_Pos 01U +#define IDIBUS_CUSTDEF_PSUINPV_MES_LENGTH (IDIBUS_CUSTDEF_PSUINPV_VOLTAGE_Pos + 2) +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_PSU_CH_TARG_V_MIN_mV 1500UL +#define IDIBUS_PSU_CH_TARG_V_MAX_mV 48000UL +#define IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MAX 10200UL +#define IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MIN 100UL +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define PSU_INV_UNDERVOLTAGE_ERR_THR 10000U +#define PSU_INV_OVERVOLTAGE_ERR_THR 50000U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_MODULE_DEVICES_LIST { + IDIBUS_PSU_CNTRL_DEV = 0x00, + IDIBUS_INPV_CNTRL_DEV, + IDIBUS_DEVICES_NUMBER +}; +enum { + IDIBUS_4DC_CH1_NUM = 0, + IDIBUS_4DC_CH2_NUM, + IDIBUS_4DC_CH3_NUM, + IDIBUS_4DC_CH4_NUM, + IDIBUS_4DC_CH_COUNT + }; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +class IdiBus_4DC_PSUChannel : public IdiBusChannel { + public: + IdiBus_4DC_PSUChannel(void); + int32_t Voltage; + int32_t Current; + uint16_t TargetVoltage; + uint16_t CurrentLimit; + struct { + uint8_t Enable; + uint8_t PowerGood; + union { + uint8_t Sum; + struct { + uint8_t PeripheryError : 1; + uint8_t OvercurrentError : 1; + uint8_t OvervoltageError : 1; + uint8_t OffStateCurrentLeakage : 1; + uint8_t MemoryError : 1; + uint8_t InpVoltageError : 1; + uint8_t Reserved : 2; + } BF; + } ERRORS; + } STATUS; +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBus_4DC_PSUCDevice : public IdiBusDevice { + public : + IdiBus_4DC_PSUCDevice(void *ParentModule) : IdiBusDevice (ParentModule) {} + + uint8_t getChStatus(uint8_t ChNum); + void getAllChStatus(void); + + uint8_t getChOutputVoltage(uint8_t ChNum); + void getAllChOutputVoltage(void); + + uint8_t getChOutputCurrent(uint8_t ChNum); + void getAllChOutputCurrent(void); + + uint8_t getChAllData(uint8_t ChNum); + void getAllChAllData(void); + + uint8_t setChState(uint8_t ChNum, uint8_t State); + void setAllChState(uint8_t State); + void setAllChState(uint8_t Ch1State, uint8_t Ch2State, uint8_t Ch3State, uint8_t Ch4State); + + uint8_t setChVoltage(uint8_t ChNum, uint16_t TargetVoltage); + void setAllChVoltage(uint16_t TargetVoltage); + void setAllChVoltage(uint16_t TV_CH1, uint16_t TV_CH2, uint16_t TV_CH3, uint16_t TV_CH4); + + uint8_t setChCurrentLimit(uint8_t ChNum, uint16_t CurrentLimit); + void setAllChCurrentLimit(uint16_t CurrentLimit); + void setAllChCurrentLimit(uint16_t CL_CH1, uint16_t CL_CH2, uint16_t CL_CH3, uint16_t CL_CH4); + + uint8_t setChVoltageAndCurrentLimit(uint8_t ChNum, uint16_t TargetVoltage, uint16_t CurrentLimit); + void setAllChVoltageAndCurrentLimit(uint16_t TargetVoltage, uint16_t CurrentLimit); + void setAllChVoltageAndCurrentLimit(uint16_t VCH1, uint16_t CCH1, uint16_t VCH2, uint16_t CCH2, uint16_t VCH3, uint16_t CCH3, uint16_t VCH4, uint16_t CCH4); + + IdiBus_4DC_PSUChannel getChData(uint8_t ChNum); + protected : + IdiBus_4DC_PSUChannel CH[IDIBUS_4DC_CH_COUNT]; + virtual IdiBusChannel *getChannel(uint8_t Num); + void parsePsuChState(uint8_t *State, uint8_t ChNum); + void parsePsuChAllState(uint8_t *State, uint8_t ChNum); + void setAllPsuChErr(uint8_t ErrCode); + +}; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +class IdiBus_4DC_INPVChannel : public IdiBusChannel { + public: + IdiBus_4DC_INPVChannel(void); + uint16_t InpVoltage; + union { + uint8_t Sum; + struct { + uint8_t Undervoltage : 1; + uint8_t Overvoltage : 1; + uint8_t Reserved : 6; + } BF; + } STATUS; +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBus_4DC_INPVCDevice : public IdiBusDevice { + public : + IdiBus_4DC_INPVCDevice (void *ParentModule) : IdiBusDevice (ParentModule) {} + uint8_t getInputVoltage(void); + IdiBus_4DC_INPVChannel getChData(void); + protected : + IdiBus_4DC_INPVChannel INPV; + virtual IdiBusChannel *getChannel(uint8_t Num); +}; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +class IdiBus_4DC : public IdiBusSlave { + public: + IdiBus_4DC (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress), PSUC_DEV(this), INPV_DEV(this) {} + IdiBus_4DC() : IdiBusSlave(), PSUC_DEV(this), INPV_DEV(this) {} + + virtual IdiBusDevice *getDevice(uint8_t Num); + + IdiBus_4DC_PSUCDevice PSUC_DEV; + IdiBus_4DC_INPVCDevice INPV_DEV; +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_4DC_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/1xGenTest.componentinfo.xml b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/1xGenTest.componentinfo.xml new file mode 100644 index 0000000..169ded6 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/1xGenTest.componentinfo.xml @@ -0,0 +1,86 @@ + + + + + + + Device + Startup + + + Atmel + 2.0.0 + C:/Program Files (x86)\Atmel\Studio\7.0\Packs + + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\Atmel\ATmega_DFP\2.0.401\include\ + + include + C + + + include/ + + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\Atmel\ATmega_DFP\2.0.401\include\avr\iom328pb.h + + header + C + ciLFjy803ysEAt1ml/dotQ== + + include/avr/iom328pb.h + + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\Atmel\ATmega_DFP\2.0.401\templates\main.c + template + source + C Exe + KjvOcFWd++tbnsEMfVPd/w== + + templates/main.c + Main file (.c) + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\Atmel\ATmega_DFP\2.0.401\templates\main.cpp + template + source + C Exe + jUpFIcLr99QCZJmYGdbF/A== + + templates/main.cpp + Main file (.cpp) + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\Atmel\ATmega_DFP\2.0.401\gcc\dev\atmega328pb + + libraryPrefix + GCC + + + gcc/dev/atmega328pb + + + + + ATmega_DFP + C:/Program Files (x86)/Atmel/Studio/7.0/Packs/Atmel/ATmega_DFP/2.0.401/Atmel.ATmega_DFP.pdsc + 2.0.401 + true + ATmega328PB + + + + Resolved + Fixed + true + + + \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/1xGenTest.cppproj b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/1xGenTest.cppproj new file mode 100644 index 0000000..df15cb6 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/1xGenTest.cppproj @@ -0,0 +1,161 @@ + + + + 2.0 + 7.0 + com.Atmel.AVRGCC8.CPP + {6a6fbffd-b460-4b8d-ac37-72193bed073f} + ATmega328PB + none + Executable + CPP + $(MSBuildProjectName) + .elf + $(MSBuildProjectDirectory)\$(Configuration) + 1xGenTest + 1xGenTest + 1xGenTest + Native + true + false + true + true + 0x20000000 + + true + exception_table + 2 + 0 + 0 + + + + + + + + + + + + + + + + + + -mmcu=atmega328pb -B "%24(PackRepoDir)\Atmel\ATmega_DFP\2.0.401\gcc\dev\atmega328pb" + True + True + True + True + False + True + True + + + NDEBUG + + + + + %24(PackRepoDir)\Atmel\ATmega_DFP\2.0.401\include\ + + + Optimize for size (-Os) + True + True + True + True + True + + + NDEBUG + + + + + %24(PackRepoDir)\Atmel\ATmega_DFP\2.0.401\include\ + + + Optimize for size (-Os) + True + True + True + + + libm + + + + + %24(PackRepoDir)\Atmel\ATmega_DFP\2.0.401\include\ + + + + + + + + + -mmcu=atmega328pb -B "%24(PackRepoDir)\Atmel\ATmega_DFP\2.0.401\gcc\dev\atmega328pb" + True + True + True + True + False + True + True + + + DEBUG + + + + + %24(PackRepoDir)\Atmel\ATmega_DFP\2.0.401\include\ + + + Optimize (-O1) + True + True + Default (-g2) + True + True + True + + + DEBUG + + + + + %24(PackRepoDir)\Atmel\ATmega_DFP\2.0.401\include\ + + + Optimize (-O1) + True + True + Default (-g2) + True + + + libm + + + + + %24(PackRepoDir)\Atmel\ATmega_DFP\2.0.401\include\ + + + Default (-Wa,-g) + + + + + + compile + + + + \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/main.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/main.cpp new file mode 100644 index 0000000..305e843 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/1xGenTest/main.cpp @@ -0,0 +1,150 @@ +#ifdef F_CPU +#undef F_CPU +#endif +#define F_CPU 16000000UL + +#include +#include "IdiBusSerialLine.h" +#include "IDIBUS_1xGen.h" +#include "MBOARD_POWER.h" +#include + +IdiBusSerialLine Serial_Line0; +IdiBusSerialLine Serial_Line1; + +void setup() +{ + MBOARD_POWER_OFF_ON(); + delay(50); + + IDIBUS_SERIAL_INIT_TYPEDEF L0Init; + L0Init.USART_NUMBER = IDIBUS_SERIAL_USART2; // select USART + L0Init.TIMER_NUMBER = IDIBUS_TIMER_1; // select timer + L0Init.CONFIG = IDIBUS_SERIAL_8N2; // 8 bit, 2 stop + L0Init.RS485_DIR_PIN = 6; // direction pin in-out + L0Init.BAUDRATE_DIPSW_S0_PIN = 9; // speed selector pins + L0Init.BAUDRATE_DIPSW_S1_PIN = 8; + L0Init.BAUDRATE_DIPSW_S2_PIN = 7; + Serial_Line0.Init(&L0Init); // Init line with with config above + Serial_Line0.UpdateBaudrateFromDipSwitch(); // speed setup + Serial_Line0.Start(); // run! + + IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF L1Init; + L1Init.USART_NUMBER = IDIBUS_SERIAL_USART1; + L1Init.TIMER_NUMBER = IDIBUS_TIMER_3; + L1Init.CONFIG = IDIBUS_SERIAL_8N2; + L1Init.RS485_DIR_GPIO.PORT = &PORTL; + L1Init.RS485_DIR_GPIO.PIN_NUM = 6; + L1Init.BAUDRATE_DIPSW.S0.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S0.PIN_NUM = 1; + L1Init.BAUDRATE_DIPSW.S1.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S1.PIN_NUM = 0; + L1Init.BAUDRATE_DIPSW.S2.PORT = &PORTL; + L1Init.BAUDRATE_DIPSW.S2.PIN_NUM = 7; + Serial_Line1.Init(&L1Init); + Serial_Line1.UpdateBaudrateFromDipSwitch(); + Serial_Line1.Start(); + + Serial.begin(115200,SERIAL_8N2); // usart0 for debug + + #define BAUD 16000000UL/16/250000UL-1 // BAUD speed = 250000 bod + UBRR3 = (uint16_t)(BAUD); // USART BAUD RATE INIT + UCSR3B = (1<> 8) & 0xFF), (uint8_t)(Settings.first_mode_pwm_value & 0xFF), + Settings.first_mode_f, Settings.first_mode_invert, Settings.first_mode_R1, + Settings.second_mode_time, + (uint8_t)((Settings.second_mode_pwm_value >> 8) & 0xFF), (uint8_t)(Settings.second_mode_pwm_value & 0xFF), + Settings.second_mode_f, Settings.second_mode_invert, Settings.second_mode_R1}; + TEMP.start_SPI(TxData); + + //TEMP.reset_STM(); + + Serial_Line1.UpdateBaudrateFromDipSwitch(); +} + +uint8_t MBOARD_POWER_SET(uint8_t juction, uint8_t set) // power channel ON/OFF +{ + Serial3.begin(115200,SERIAL_8N1); // usart3 for 328pb on MBoard + uint8_t string[2]; + if((juction==MBOARD_POWER_J89_05V)&&(set==MBOARD_POWER_ON)) + { + Serial3.print("5+"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J89_05V)&&(set==MBOARD_POWER_OFF)) + { + Serial3.print("5-"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J89_24V)&&(set==MBOARD_POWER_ON)) + { + Serial3.print("J+"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J89_24V)&&(set==MBOARD_POWER_OFF)) + { + Serial3.print("J-"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J67_24V)&&(set==MBOARD_POWER_ON)) + { + Serial3.print("R+"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J67_24V)&&(set==MBOARD_POWER_OFF)) + { + Serial3.print("R-"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + while(Serial3.available()>0) string[0]=Serial3.read(); + return MBOARD_POWER_ERR; +} + +void MBOARD_POWER_OFF_ON(void) // , +{ + MBOARD_POWER_SET(MBOARD_POWER_J89_05V, MBOARD_POWER_OFF); + MBOARD_POWER_SET(MBOARD_POWER_J89_24V, MBOARD_POWER_OFF); + MBOARD_POWER_SET(MBOARD_POWER_J67_24V, MBOARD_POWER_OFF); + delay(1000);wdt_reset(); + MBOARD_POWER_SET(MBOARD_POWER_J89_05V, MBOARD_POWER_ON); + delay(500);wdt_reset(); + MBOARD_POWER_SET(MBOARD_POWER_J89_24V, MBOARD_POWER_ON); + delay(500);wdt_reset(); + MBOARD_POWER_SET(MBOARD_POWER_J67_24V, MBOARD_POWER_ON); + delay(1000);wdt_reset(); + return; +} \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER.atsln b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER.atsln new file mode 100644 index 0000000..4e99123 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER.atsln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Atmel Studio Solution File, Format Version 11.00 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "IdiBus_Master", "IDIBUS_MASTER\idiBus_Master\IdiBus_Master.cppproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}" +EndProject +Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "ArduinoCore", "IDIBUS_MASTER\ArduinoCore\ArduinoCore.cppproj", "{D2221125-FC2C-43AE-A08A-D2054A122DA5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|AVR = Debug|AVR + Release|AVR = Release|AVR + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.ActiveCfg = Debug|AVR + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.Build.0 = Debug|AVR + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.ActiveCfg = Release|AVR + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.Build.0 = Release|AVR + {D2221125-FC2C-43AE-A08A-D2054A122DA5}.Debug|AVR.ActiveCfg = Debug|AVR + {D2221125-FC2C-43AE-A08A-D2054A122DA5}.Debug|AVR.Build.0 = Debug|AVR + {D2221125-FC2C-43AE-A08A-D2054A122DA5}.Release|AVR.ActiveCfg = Release|AVR + {D2221125-FC2C-43AE-A08A-D2054A122DA5}.Release|AVR.Build.0 = Release|AVR + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/ArduinoCore.componentinfo.xml b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/ArduinoCore.componentinfo.xml new file mode 100644 index 0000000..c5e25cc --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/ArduinoCore.componentinfo.xml @@ -0,0 +1,86 @@ + + + + + + + Device + Startup + + + Atmel + 1.6.0 + C:/Program Files (x86)\Atmel\Studio\7.0\Packs + + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.6.364\include\ + + include + C + + + include/ + + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.6.364\include\avr\iom2560.h + + header + C + MkwPezikXVtYA90mpLpFfA== + + include/avr/iom2560.h + + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.6.364\templates\library.c + template + source + C Lib + VjSGq44t/3IHSL1ATPOBng== + + templates/library.c + Main file (.c) + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.6.364\templates\library.cpp + template + source + C Lib + G0XtXwMIamMgYWpjMWDloQ== + + templates/library.cpp + Main file (.cpp) + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.6.364\gcc\dev\atmega2560 + + libraryPrefix + GCC + + + gcc/dev/atmega2560 + + + + + ATmega_DFP + C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.6.364/Atmel.ATmega_DFP.pdsc + 1.6.364 + true + ATmega2560 + + + + Resolved + Fixed + true + + + \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/ArduinoCore.cppproj b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/ArduinoCore.cppproj new file mode 100644 index 0000000..0af4c4e --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/ArduinoCore.cppproj @@ -0,0 +1,395 @@ + + + + 2.0 + 7.0 + com.Atmel.AVRGCC8.CPP + d2221125-fc2c-43ae-a08a-d2054a122da5 + atmega2560 + none + StaticLibrary + CPP + lib$(MSBuildProjectName) + .a + $(MSBuildProjectDirectory)\$(Configuration) + ArduinoCore + C:\Program Files (x86)\Arduino + Core + Native + ArduinoCore + ArduinoCore + true + false + true + true + 0x20000000 + + true + exception_table + 2 + 0 + 0 + + + + + + + + + + + + + + com.atmel.avrdbg.tool.atmelice + J41800097429 + 0x1E9801 + JTAG + 1000000 + + + + 0 + + ISP + + com.atmel.avrdbg.tool.ispmk2 + 193775278415 + AVRISP mkII + + + + + + + + + com.atmel.avrdbg.tool.simulator + + + Simulator + + + + + 125000 + 1000000 + + JTAG + + com.atmel.avrdbg.tool.atmelice + J41800097429 + Atmel-ICE + + + + + + -mmcu=atmega2560 -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\gcc\dev\atmega2560" + True + True + True + True + True + False + True + True + + + NDEBUG + IDIBUS_F_CPU=16000000L + ARDUINO=108013 + ARDUINO_AVR_MEGA2560 + ARDUINO_ARCH_AVR + USB_VID=0x2341 + USB_PID=0x0010 + USB_MANUFACTURER="\"Arduino LLC\"" + + + + + ..\include\core + ..\include\variants\mega + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Optimize for size (-Os) + -fno-threadsafe-statics + True + True + Default (-g2) + True + -std=gnu99 -std=gnu11 + True + True + + + NDEBUG + IDIBUS_F_CPU=16000000L + ARDUINO=108013 + ARDUINO_AVR_MEGA2560 + ARDUINO_ARCH_AVR + USB_VID=0x2341 + USB_PID=0x0010 + USB_MANUFACTURER="\"Arduino LLC\"" + + + + + ..\include\core + ..\include\variants\mega + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Optimize for size (-Os) + -fno-threadsafe-statics + True + True + Default (-g2) + True + -std=gnu++11 + + + libm + + + -Os + + + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Default (-Wa,-g) + + + + + + + -mmcu=atmega2560 -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\gcc\dev\atmega2560" + True + True + True + True + True + False + True + True + + + DEBUG + IDIBUS_F_CPU=16000000L + ARDUINO=108013 + ARDUINO_AVR_MEGA2560 + ARDUINO_ARCH_AVR + USB_VID=0x2341 + USB_PID=0x0010 + USB_MANUFACTURER="\"Arduino LLC\"" + + + + + ..\include\core + ..\include\variants\mega + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Optimize for size (-Os) + -fno-threadsafe-statics + True + True + Default (-g2) + True + -std=gnu99 -std=gnu11 + True + True + + + DEBUG + IDIBUS_F_CPU=16000000L + ARDUINO=108013 + ARDUINO_AVR_MEGA2560 + ARDUINO_ARCH_AVR + USB_VID=0x2341 + USB_PID=0x0010 + USB_MANUFACTURER="\"Arduino LLC\"" + + + + + ..\include\core + ..\include\variants\mega + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Optimize for size (-Os) + -fno-threadsafe-statics + True + True + Default (-g2) + True + -std=gnu++11 + + + libm + + + -Os + + + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Default (-Wa,-g) + + + + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + + + + + + + + + + + \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Arduino.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Arduino.h new file mode 100644 index 0000000..5d62e2f --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Arduino.h @@ -0,0 +1,260 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Arduino_h +#define Arduino_h + +#include +#include +#include +#include + +#include +#include +#include + +#include "binary.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +void yield(void); + +#define HIGH 0x1 +#define LOW 0x0 + +#define INPUT 0x0 +#define OUTPUT 0x1 +#define INPUT_PULLUP 0x2 + +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 +#define EULER 2.718281828459045235360287471352 + +#define SERIAL 0x0 +#define DISPLAY 0x1 + +#define LSBFIRST 0 +#define MSBFIRST 1 + +#define CHANGE 1 +#define FALLING 2 +#define RISING 3 + +#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) + #define DEFAULT 0 + #define EXTERNAL 1 + #define INTERNAL1V1 2 + #define INTERNAL INTERNAL1V1 +#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + #define DEFAULT 0 + #define EXTERNAL 4 + #define INTERNAL1V1 8 + #define INTERNAL INTERNAL1V1 + #define INTERNAL2V56 9 + #define INTERNAL2V56_EXTCAP 13 +#else +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) +#define INTERNAL1V1 2 +#define INTERNAL2V56 3 +#else +#define INTERNAL 3 +#endif +#define DEFAULT 1 +#define EXTERNAL 0 +#endif + +// undefine stdlib's abs if encountered +#ifdef abs +#undef abs +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) +#define abs(x) ((x)>0?(x):-(x)) +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define sq(x) ((x)*(x)) + +#define interrupts() sei() +#define noInterrupts() cli() + +#define clockCyclesPerMicrosecond() ( IDIBUS_F_CPU / 1000000L ) +#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) +#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitToggle(value, bit) ((value) ^= (1UL << (bit))) +#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit)) + +// avr-libc defines _NOP() since 1.6.2 +#ifndef _NOP +#define _NOP() do { __asm__ volatile ("nop"); } while (0) +#endif + +typedef unsigned int word; + +#define bit(b) (1UL << (b)) + +typedef bool boolean; +typedef uint8_t byte; + +void init(void); +void initVariant(void); + +int atexit(void (*func)()) __attribute__((weak)); + +void pinMode(uint8_t pin, uint8_t mode); +void digitalWrite(uint8_t pin, uint8_t val); +int digitalRead(uint8_t pin); +int analogRead(uint8_t pin); +void analogReference(uint8_t mode); +void analogWrite(uint8_t pin, int val); + +unsigned long millis(void); +unsigned long micros(void); +void delay(unsigned long ms); +void delayMicroseconds(unsigned int us); +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout); + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); + +void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode); +void detachInterrupt(uint8_t interruptNum); + +void setup(void); +void loop(void); + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. + +#define analogInPinToBit(P) (P) + +// On the ATmega1280, the addresses of some of the port registers are +// greater than 255, so we can't store them in uint8_t's. +extern const uint16_t PROGMEM port_to_mode_PGM[]; +extern const uint16_t PROGMEM port_to_input_PGM[]; +extern const uint16_t PROGMEM port_to_output_PGM[]; + +extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; +// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. +// +// These perform slightly better as macros compared to inline functions +// +#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) +#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) +#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) +#define analogInPinToBit(P) (P) +#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) +#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) +#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) + +#define NOT_A_PIN 0 +#define NOT_A_PORT 0 + +#define NOT_AN_INTERRUPT -1 + +#ifdef ARDUINO_MAIN +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 +#endif + +#define NOT_ON_TIMER 0 +#define TIMER0A 1 +#define TIMER0B 2 +#define TIMER1A 3 +#define TIMER1B 4 +#define TIMER1C 5 +#define TIMER2 6 +#define TIMER2A 7 +#define TIMER2B 8 + +#define TIMER3A 9 +#define TIMER3B 10 +#define TIMER3C 11 +#define TIMER4A 12 +#define TIMER4B 13 +#define TIMER4C 14 +#define TIMER4D 15 +#define TIMER5A 16 +#define TIMER5B 17 +#define TIMER5C 18 + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus +#include "WCharacter.h" +#include "WString.h" +#include "HardwareSerial.h" +#include "USBAPI.h" +#if defined(HAVE_HWSERIAL0) && defined(HAVE_CDCSERIAL) +#error "Targets with both UART0 and CDC serial not supported" +#endif + +uint16_t makeWord(uint16_t w); +uint16_t makeWord(byte h, byte l); + +#define word(...) makeWord(__VA_ARGS__) + +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); +void noTone(uint8_t _pin); + +// WMath prototypes +long random(long); +long random(long, long); +void randomSeed(unsigned long); +long map(long, long, long, long, long); + +#endif + +#include "pins_arduino.h" + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Client.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Client.h new file mode 100644 index 0000000..b8e5d93 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Client.h @@ -0,0 +1,45 @@ +/* + Client.h - Base class that provides Client + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef client_h +#define client_h +#include "Print.h" +#include "Stream.h" +#include "IPAddress.h" + +class Client : public Stream { + +public: + virtual int connect(IPAddress ip, uint16_t port) =0; + virtual int connect(const char *host, uint16_t port) =0; + virtual size_t write(uint8_t) =0; + virtual size_t write(const uint8_t *buf, size_t size) =0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/HardwareSerial.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/HardwareSerial.h new file mode 100644 index 0000000..17000c2 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/HardwareSerial.h @@ -0,0 +1,161 @@ +/* + HardwareSerial.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#ifndef HardwareSerial_h +#define HardwareSerial_h + +#include + +#include "Stream.h" + +// Define constants and variables for buffering incoming serial data. We're +// using a ring buffer (I think), in which head is the index of the location +// to which to write the next incoming character and tail is the index of the +// location from which to read. +// NOTE: a "power of 2" buffer size is reccomended to dramatically +// optimize all the modulo operations for ring buffers. +// WARNING: When buffer sizes are increased to > 256, the buffer index +// variables are automatically increased in size, but the extra +// atomicity guards needed for that are not implemented. This will +// often work, but occasionally a race condition can occur that makes +// Serial behave erratically. See https://github.com/arduino/Arduino/issues/2405 +#if !defined(SERIAL_TX_BUFFER_SIZE) +#if ((RAMEND - RAMSTART) < 1023) +#define SERIAL_TX_BUFFER_SIZE 16 +#else +#define SERIAL_TX_BUFFER_SIZE 64 +#endif +#endif +#if !defined(SERIAL_RX_BUFFER_SIZE) +#if ((RAMEND - RAMSTART) < 1023) +#define SERIAL_RX_BUFFER_SIZE 16 +#else +#define SERIAL_RX_BUFFER_SIZE 64 +#endif +#endif +#if (SERIAL_TX_BUFFER_SIZE>256) +typedef uint16_t tx_buffer_index_t; +#else +typedef uint8_t tx_buffer_index_t; +#endif +#if (SERIAL_RX_BUFFER_SIZE>256) +typedef uint16_t rx_buffer_index_t; +#else +typedef uint8_t rx_buffer_index_t; +#endif + +// Define config for Serial.begin(baud, config); +#define SERIAL_5N1 0x00 +#define SERIAL_6N1 0x02 +#define SERIAL_7N1 0x04 +#define SERIAL_8N1 0x06 +#define SERIAL_5N2 0x08 +#define SERIAL_6N2 0x0A +#define SERIAL_7N2 0x0C +#define SERIAL_8N2 0x0E +#define SERIAL_5E1 0x20 +#define SERIAL_6E1 0x22 +#define SERIAL_7E1 0x24 +#define SERIAL_8E1 0x26 +#define SERIAL_5E2 0x28 +#define SERIAL_6E2 0x2A +#define SERIAL_7E2 0x2C +#define SERIAL_8E2 0x2E +#define SERIAL_5O1 0x30 +#define SERIAL_6O1 0x32 +#define SERIAL_7O1 0x34 +#define SERIAL_8O1 0x36 +#define SERIAL_5O2 0x38 +#define SERIAL_6O2 0x3A +#define SERIAL_7O2 0x3C +#define SERIAL_8O2 0x3E + +class HardwareSerial : public Stream +{ + protected: + volatile uint8_t * const _ubrrh; + volatile uint8_t * const _ubrrl; + volatile uint8_t * const _ucsra; + volatile uint8_t * const _ucsrb; + volatile uint8_t * const _ucsrc; + volatile uint8_t * const _udr; + // Has any byte been written to the UART since begin() + bool _written; + + volatile rx_buffer_index_t _rx_buffer_head; + volatile rx_buffer_index_t _rx_buffer_tail; + volatile tx_buffer_index_t _tx_buffer_head; + volatile tx_buffer_index_t _tx_buffer_tail; + + // Don't put any members after these buffers, since only the first + // 32 bytes of this struct can be accessed quickly using the ldd + // instruction. + unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE]; + unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE]; + + public: + inline HardwareSerial( + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *ucsrc, volatile uint8_t *udr); + void begin(unsigned long baud) { begin(baud, SERIAL_8N1); } + void begin(unsigned long, uint8_t); + void end(); + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual int availableForWrite(void); + virtual void flush(void); + virtual size_t write(uint8_t); + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool() { return true; } + + // Interrupt handlers - Not intended to be called externally + inline void _rx_complete_irq(void); + void _tx_udr_empty_irq(void); +}; + +#if defined(UBRRH) || defined(UBRR0H) + extern HardwareSerial Serial; + #define HAVE_HWSERIAL0 +#endif +#if defined(UBRR1H) + extern HardwareSerial Serial1; + #define HAVE_HWSERIAL1 +#endif +#if defined(UBRR2H) + extern HardwareSerial Serial2; + #define HAVE_HWSERIAL2 +#endif +#if defined(UBRR3H) + extern HardwareSerial Serial3; + #define HAVE_HWSERIAL3 +#endif + +extern void serialEventRun(void) __attribute__((weak)); + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/HardwareSerial_private.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/HardwareSerial_private.h new file mode 100644 index 0000000..761a5e5 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/HardwareSerial_private.h @@ -0,0 +1,123 @@ +/* + HardwareSerial_private.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus +*/ + +#include "wiring_private.h" + +// this next line disables the entire HardwareSerial.cpp, +// this is so I can support Attiny series and any other chip without a uart +#if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3) + +// Ensure that the various bit positions we use are available with a 0 +// postfix, so we can always use the values for UART0 for all UARTs. The +// alternative, passing the various values for each UART to the +// HardwareSerial constructor also works, but makes the code bigger and +// slower. +#if !defined(TXC0) +#if defined(TXC) +// Some chips like ATmega8 don't have UPE, only PE. The other bits are +// named as expected. +#if !defined(UPE) && defined(PE) +#define UPE PE +#endif +// On ATmega8, the uart and its bits are not numbered, so there is no TXC0 etc. +#define TXC0 TXC +#define RXEN0 RXEN +#define TXEN0 TXEN +#define RXCIE0 RXCIE +#define UDRIE0 UDRIE +#define U2X0 U2X +#define UPE0 UPE +#define UDRE0 UDRE +#elif defined(TXC1) +// Some devices have uart1 but no uart0 +#define TXC0 TXC1 +#define RXEN0 RXEN1 +#define TXEN0 TXEN1 +#define RXCIE0 RXCIE1 +#define UDRIE0 UDRIE1 +#define U2X0 U2X1 +#define UPE0 UPE1 +#define UDRE0 UDRE1 +#else +#error No UART found in HardwareSerial.cpp +#endif +#endif // !defined TXC0 + +// Check at compiletime that it is really ok to use the bit positions of +// UART0 for the other UARTs as well, in case these values ever get +// changed for future hardware. +#if defined(TXC1) && (TXC1 != TXC0 || RXEN1 != RXEN0 || RXCIE1 != RXCIE0 || \ + UDRIE1 != UDRIE0 || U2X1 != U2X0 || UPE1 != UPE0 || \ + UDRE1 != UDRE0) +#error "Not all bit positions for UART1 are the same as for UART0" +#endif +#if defined(TXC2) && (TXC2 != TXC0 || RXEN2 != RXEN0 || RXCIE2 != RXCIE0 || \ + UDRIE2 != UDRIE0 || U2X2 != U2X0 || UPE2 != UPE0 || \ + UDRE2 != UDRE0) +#error "Not all bit positions for UART2 are the same as for UART0" +#endif +#if defined(TXC3) && (TXC3 != TXC0 || RXEN3 != RXEN0 || RXCIE3 != RXCIE0 || \ + UDRIE3 != UDRIE0 || U3X3 != U3X0 || UPE3 != UPE0 || \ + UDRE3 != UDRE0) +#error "Not all bit positions for UART3 are the same as for UART0" +#endif + +// Constructors //////////////////////////////////////////////////////////////// + +HardwareSerial::HardwareSerial( + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *ucsrc, volatile uint8_t *udr) : + _ubrrh(ubrrh), _ubrrl(ubrrl), + _ucsra(ucsra), _ucsrb(ucsrb), _ucsrc(ucsrc), + _udr(udr), + _rx_buffer_head(0), _rx_buffer_tail(0), + _tx_buffer_head(0), _tx_buffer_tail(0) +{ +} + +// Actual interrupt handlers ////////////////////////////////////////////////////////////// + +void HardwareSerial::_rx_complete_irq(void) +{ + if (bit_is_clear(*_ucsra, UPE0)) { + // No Parity error, read byte and store it in the buffer if there is + // room + unsigned char c = *_udr; + rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != _rx_buffer_tail) { + _rx_buffer[_rx_buffer_head] = c; + _rx_buffer_head = i; + } + } else { + // Parity error, read byte but discard it + *_udr; + }; +} + +#endif // whole file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/IPAddress.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/IPAddress.h new file mode 100644 index 0000000..d762f2c --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/IPAddress.h @@ -0,0 +1,78 @@ +/* + IPAddress.h - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef IPAddress_h +#define IPAddress_h + +#include +#include "Printable.h" +#include "WString.h" + +// A class to make it easier to handle and pass around IP addresses + +class IPAddress : public Printable { +private: + union { + uint8_t bytes[4]; // IPv4 address + uint32_t dword; + } _address; + + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() { return _address.bytes; }; + +public: + // Constructors + IPAddress(); + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint32_t address); + IPAddress(const uint8_t *address); + + bool fromString(const char *address); + bool fromString(const String &address) { return fromString(address.c_str()); } + + // Overloaded cast operator to allow IPAddress objects to be used where a pointer + // to a four-byte uint8_t array is expected + operator uint32_t() const { return _address.dword; }; + bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; }; + bool operator==(const uint8_t* addr) const; + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const { return _address.bytes[index]; }; + uint8_t& operator[](int index) { return _address.bytes[index]; }; + + // Overloaded copy operators to allow initialisation of IPAddress objects from other types + IPAddress& operator=(const uint8_t *address); + IPAddress& operator=(uint32_t address); + + virtual size_t printTo(Print& p) const; + + friend class EthernetClass; + friend class UDP; + friend class Client; + friend class Server; + friend class DhcpClass; + friend class DNSClient; +}; + +const IPAddress INADDR_NONE(0,0,0,0); + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/PluggableUSB.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/PluggableUSB.h new file mode 100644 index 0000000..507f0df --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/PluggableUSB.h @@ -0,0 +1,74 @@ +/* + PluggableUSB.h + Copyright (c) 2015 Arduino LLC + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef PUSB_h +#define PUSB_h + +#include "USBAPI.h" +#include + +#if defined(USBCON) + +class PluggableUSBModule { +public: + PluggableUSBModule(uint8_t numEps, uint8_t numIfs, uint8_t *epType) : + numEndpoints(numEps), numInterfaces(numIfs), endpointType(epType) + { } + +protected: + virtual bool setup(USBSetup& setup) = 0; + virtual int getInterface(uint8_t* interfaceCount) = 0; + virtual int getDescriptor(USBSetup& setup) = 0; + virtual uint8_t getShortName(char *name) { name[0] = 'A'+pluggedInterface; return 1; } + + uint8_t pluggedInterface; + uint8_t pluggedEndpoint; + + const uint8_t numEndpoints; + const uint8_t numInterfaces; + const uint8_t *endpointType; + + PluggableUSBModule *next = NULL; + + friend class PluggableUSB_; +}; + +class PluggableUSB_ { +public: + PluggableUSB_(); + bool plug(PluggableUSBModule *node); + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); + void getShortName(char *iSerialNum); + +private: + uint8_t lastIf; + uint8_t lastEp; + PluggableUSBModule* rootNode; +}; + +// Replacement for global singleton. +// This function prevents static-initialization-order-fiasco +// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use +PluggableUSB_& PluggableUSB(); + +#endif + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Print.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Print.h new file mode 100644 index 0000000..058a2ab --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Print.h @@ -0,0 +1,93 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Print_h +#define Print_h + +#include +#include // for size_t + +#include "WString.h" +#include "Printable.h" + +#define DEC 10 +#define HEX 16 +#define OCT 8 +#ifdef BIN // Prevent warnings if BIN is previously defined in "iotnx4.h" or similar +#undef BIN +#endif +#define BIN 2 + +class Print +{ + private: + int write_error; + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + protected: + void setWriteError(int err = 1) { write_error = err; } + public: + Print() : write_error(0) {} + + int getWriteError() { return write_error; } + void clearWriteError() { setWriteError(0); } + + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) { + return write((const uint8_t *)buffer, size); + } + + // default to zero, meaning "a single write may block" + // should be overriden by subclasses with buffering + virtual int availableForWrite() { return 0; } + + size_t print(const __FlashStringHelper *); + size_t print(const String &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + size_t print(const Printable&); + + size_t println(const __FlashStringHelper *); + size_t println(const String &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(const Printable&); + size_t println(void); + + virtual void flush() { /* Empty implementation for backward compatibility */ } +}; + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Printable.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Printable.h new file mode 100644 index 0000000..2a1b2e9 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Printable.h @@ -0,0 +1,40 @@ +/* + Printable.h - Interface class that allows printing of complex types + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Printable_h +#define Printable_h + +#include + +class Print; + +/** The Printable class provides a way for new classes to allow themselves to be printed. + By deriving from Printable and implementing the printTo method, it will then be possible + for users to print out instances of this class by passing them into the usual + Print::print and Print::println methods. +*/ + +class Printable +{ + public: + virtual size_t printTo(Print& p) const = 0; +}; + +#endif + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Server.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Server.h new file mode 100644 index 0000000..69e3e39 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Server.h @@ -0,0 +1,30 @@ +/* + Server.h - Base class that provides Server + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef server_h +#define server_h + +#include "Print.h" + +class Server : public Print { +public: + virtual void begin() =0; +}; + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Stream.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Stream.h new file mode 100644 index 0000000..8e950c7 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Stream.h @@ -0,0 +1,129 @@ +/* + Stream.h - base class for character-based streams. + Copyright (c) 2010 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + parsing functions based on TextFinder library by Michael Margolis +*/ + +#ifndef Stream_h +#define Stream_h + +#include +#include "Print.h" + +// compatability macros for testing +/* +#define getInt() parseInt() +#define getInt(ignore) parseInt(ignore) +#define getFloat() parseFloat() +#define getFloat(ignore) parseFloat(ignore) +#define getString( pre_string, post_string, buffer, length) +readBytesBetween( pre_string, terminator, buffer, length) +*/ + +// This enumeration provides the lookahead options for parseInt(), parseFloat() +// The rules set out here are used until either the first valid character is found +// or a time out occurs due to lack of input. +enum LookaheadMode{ + SKIP_ALL, // All invalid characters are ignored. + SKIP_NONE, // Nothing is skipped, and the stream is not touched unless the first waiting character is valid. + SKIP_WHITESPACE // Only tabs, spaces, line feeds & carriage returns are skipped. +}; + +#define NO_IGNORE_CHAR '\x01' // a char not found in a valid ASCII numeric field + +class Stream : public Print +{ + protected: + unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read + unsigned long _startMillis; // used for timeout measurement + int timedRead(); // read stream with timeout + int timedPeek(); // peek stream with timeout + int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout + + public: + virtual int available() = 0; + virtual int read() = 0; + virtual int peek() = 0; + + Stream() {_timeout=1000;} + +// parsing methods + + void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second + unsigned long getTimeout(void) { return _timeout; } + + bool find(char *target); // reads data from the stream until the target string is found + bool find(uint8_t *target) { return find ((char *)target); } + // returns true if target string is found, false if timed out (see setTimeout) + + bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found + bool find(uint8_t *target, size_t length) { return find ((char *)target, length); } + // returns true if target string is found, false if timed out + + bool find(char target) { return find (&target, 1); } + + bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found + bool findUntil(uint8_t *target, char *terminator) { return findUntil((char *)target, terminator); } + + bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found + bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); } + + long parseInt(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR); + // returns the first valid (long) integer value from the current position. + // lookahead determines how parseInt looks ahead in the stream. + // See LookaheadMode enumeration at the top of the file. + // Lookahead is terminated by the first character that is not a valid part of an integer. + // Once parsing commences, 'ignore' will be skipped in the stream. + + float parseFloat(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR); + // float version of parseInt + + size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer + size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } + // terminates if length characters have been read or timeout (see setTimeout) + // returns the number of characters placed in the buffer (0 means no valid data found) + + size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character + size_t readBytesUntil( char terminator, uint8_t *buffer, size_t length) { return readBytesUntil(terminator, (char *)buffer, length); } + // terminates if length characters have been read, timeout, or if the terminator character detected + // returns the number of characters placed in the buffer (0 means no valid data found) + + // Arduino String functions to be added here + String readString(); + String readStringUntil(char terminator); + + protected: + long parseInt(char ignore) { return parseInt(SKIP_ALL, ignore); } + float parseFloat(char ignore) { return parseFloat(SKIP_ALL, ignore); } + // These overload exists for compatibility with any class that has derived + // Stream and used parseFloat/Int with a custom ignore character. To keep + // the public API simple, these overload remains protected. + + struct MultiTarget { + const char *str; // string you're searching for + size_t len; // length of string you're searching for + size_t index; // index used by the search routine. + }; + + // This allows you to search for an arbitrary number of strings. + // Returns index of the target that is found first or -1 if timeout occurs. + int findMulti(struct MultiTarget *targets, int tCount); +}; + +#undef NO_IGNORE_CHAR +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBAPI.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBAPI.h new file mode 100644 index 0000000..701a14f --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBAPI.h @@ -0,0 +1,209 @@ +/* + USBAPI.h + Copyright (c) 2005-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __USBAPI__ +#define __USBAPI__ + +#include +#include +#include +#include +#include + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +#include "Arduino.h" + +// This definitions is usefull if you want to reduce the EP_SIZE to 16 +// at the moment only 64 and 16 as EP_SIZE for all EPs are supported except the control endpoint +#ifndef USB_EP_SIZE +#define USB_EP_SIZE 64 +#endif + +#if defined(USBCON) + +#include "USBDesc.h" +#include "USBCore.h" + +//================================================================================ +//================================================================================ +// USB + +#define EP_TYPE_CONTROL (0x00) +#define EP_TYPE_BULK_IN ((1<256) +#error Please lower the CDC Buffer size +#endif + +class Serial_ : public Stream +{ +private: + int peek_buffer; +public: + Serial_() { peek_buffer = -1; }; + void begin(unsigned long); + void begin(unsigned long, uint8_t); + void end(void); + + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual int availableForWrite(void); + virtual void flush(void); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t*, size_t); + using Print::write; // pull in write(str) and write(buf, size) from Print + operator bool(); + + volatile uint8_t _rx_buffer_head; + volatile uint8_t _rx_buffer_tail; + unsigned char _rx_buffer[SERIAL_BUFFER_SIZE]; + + // This method allows processing "SEND_BREAK" requests sent by + // the USB host. Those requests indicate that the host wants to + // send a BREAK signal and are accompanied by a single uint16_t + // value, specifying the duration of the break. The value 0 + // means to end any current break, while the value 0xffff means + // to start an indefinite break. + // readBreak() will return the value of the most recent break + // request, but will return it at most once, returning -1 when + // readBreak() is called again (until another break request is + // received, which is again returned once). + // This also mean that if two break requests are received + // without readBreak() being called in between, the value of the + // first request is lost. + // Note that the value returned is a long, so it can return + // 0-0xffff as well as -1. + int32_t readBreak(); + + // These return the settings specified by the USB host for the + // serial port. These aren't really used, but are offered here + // in case a sketch wants to act on these settings. + uint32_t baud(); + uint8_t stopbits(); + uint8_t paritytype(); + uint8_t numbits(); + bool dtr(); + bool rts(); + enum { + ONE_STOP_BIT = 0, + ONE_AND_HALF_STOP_BIT = 1, + TWO_STOP_BITS = 2, + }; + enum { + NO_PARITY = 0, + ODD_PARITY = 1, + EVEN_PARITY = 2, + MARK_PARITY = 3, + SPACE_PARITY = 4, + }; + +}; +extern Serial_ Serial; + +#define HAVE_CDCSERIAL + +//================================================================================ +//================================================================================ +// Low level API + +typedef struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint8_t wValueL; + uint8_t wValueH; + uint16_t wIndex; + uint16_t wLength; +} USBSetup; + +//================================================================================ +//================================================================================ +// MSC 'Driver' + +int MSC_GetInterface(uint8_t* interfaceNum); +int MSC_GetDescriptor(int i); +bool MSC_Setup(USBSetup& setup); +bool MSC_Data(uint8_t rx,uint8_t tx); + +//================================================================================ +//================================================================================ +// CSC 'Driver' + +int CDC_GetInterface(uint8_t* interfaceNum); +int CDC_GetDescriptor(int i); +bool CDC_Setup(USBSetup& setup); + +//================================================================================ +//================================================================================ + +#define TRANSFER_PGM 0x80 +#define TRANSFER_RELEASE 0x40 +#define TRANSFER_ZERO 0x20 + +int USB_SendControl(uint8_t flags, const void* d, int len); +int USB_RecvControl(void* d, int len); +int USB_RecvControlLong(void* d, int len); + +uint8_t USB_Available(uint8_t ep); +uint8_t USB_SendSpace(uint8_t ep); +int USB_Send(uint8_t ep, const void* data, int len); // blocking +int USB_Recv(uint8_t ep, void* data, int len); // non-blocking +int USB_Recv(uint8_t ep); // non-blocking +void USB_Flush(uint8_t ep); + +#endif + +#endif /* if defined(USBCON) */ diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBCore.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBCore.h new file mode 100644 index 0000000..0c63c2b --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBCore.h @@ -0,0 +1,304 @@ + +// Copyright (c) 2010, Peter Barrett +/* +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#ifndef __USBCORE_H__ +#define __USBCORE_H__ + +#include "USBAPI.h" + +// Standard requests +#define GET_STATUS 0 +#define CLEAR_FEATURE 1 +#define SET_FEATURE 3 +#define SET_ADDRESS 5 +#define GET_DESCRIPTOR 6 +#define SET_DESCRIPTOR 7 +#define GET_CONFIGURATION 8 +#define SET_CONFIGURATION 9 +#define GET_INTERFACE 10 +#define SET_INTERFACE 11 + + +// bmRequestType +#define REQUEST_HOSTTODEVICE 0x00 +#define REQUEST_DEVICETOHOST 0x80 +#define REQUEST_DIRECTION 0x80 + +#define REQUEST_STANDARD 0x00 +#define REQUEST_CLASS 0x20 +#define REQUEST_VENDOR 0x40 +#define REQUEST_TYPE 0x60 + +#define REQUEST_DEVICE 0x00 +#define REQUEST_INTERFACE 0x01 +#define REQUEST_ENDPOINT 0x02 +#define REQUEST_OTHER 0x03 +#define REQUEST_RECIPIENT 0x03 + +#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_CLASS | REQUEST_INTERFACE) +#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE) +#define REQUEST_DEVICETOHOST_STANDARD_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE) + +// Class requests + +#define CDC_SET_LINE_CODING 0x20 +#define CDC_GET_LINE_CODING 0x21 +#define CDC_SET_CONTROL_LINE_STATE 0x22 +#define CDC_SEND_BREAK 0x23 + +#define MSC_RESET 0xFF +#define MSC_GET_MAX_LUN 0xFE + +// Descriptors + +#define USB_DEVICE_DESC_SIZE 18 +#define USB_CONFIGUARTION_DESC_SIZE 9 +#define USB_INTERFACE_DESC_SIZE 9 +#define USB_ENDPOINT_DESC_SIZE 7 + +#define USB_DEVICE_DESCRIPTOR_TYPE 1 +#define USB_CONFIGURATION_DESCRIPTOR_TYPE 2 +#define USB_STRING_DESCRIPTOR_TYPE 3 +#define USB_INTERFACE_DESCRIPTOR_TYPE 4 +#define USB_ENDPOINT_DESCRIPTOR_TYPE 5 + +// usb_20.pdf Table 9.6 Standard Feature Selectors +#define DEVICE_REMOTE_WAKEUP 1 +#define ENDPOINT_HALT 2 +#define TEST_MODE 3 + +// usb_20.pdf Figure 9-4. Information Returned by a GetStatus() Request to a Device +#define FEATURE_SELFPOWERED_ENABLED (1 << 0) +#define FEATURE_REMOTE_WAKEUP_ENABLED (1 << 1) + +#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02 +#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03 +#define USB_DEVICE_CLASS_STORAGE 0x08 +#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF + +#define USB_CONFIG_POWERED_MASK 0x40 +#define USB_CONFIG_BUS_POWERED 0x80 +#define USB_CONFIG_SELF_POWERED 0xC0 +#define USB_CONFIG_REMOTE_WAKEUP 0x20 + +// bMaxPower in Configuration Descriptor +#define USB_CONFIG_POWER_MA(mA) ((mA)/2) +#ifndef USB_CONFIG_POWER + #define USB_CONFIG_POWER (500) +#endif + +// bEndpointAddress in Endpoint Descriptor +#define USB_ENDPOINT_DIRECTION_MASK 0x80 +#define USB_ENDPOINT_OUT(addr) (lowByte((addr) | 0x00)) +#define USB_ENDPOINT_IN(addr) (lowByte((addr) | 0x80)) + +#define USB_ENDPOINT_TYPE_MASK 0x03 +#define USB_ENDPOINT_TYPE_CONTROL 0x00 +#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01 +#define USB_ENDPOINT_TYPE_BULK 0x02 +#define USB_ENDPOINT_TYPE_INTERRUPT 0x03 + +#define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF) + +#define CDC_V1_10 0x0110 +#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02 + +#define CDC_CALL_MANAGEMENT 0x01 +#define CDC_ABSTRACT_CONTROL_MODEL 0x02 +#define CDC_HEADER 0x00 +#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02 +#define CDC_UNION 0x06 +#define CDC_CS_INTERFACE 0x24 +#define CDC_CS_ENDPOINT 0x25 +#define CDC_DATA_INTERFACE_CLASS 0x0A + +#define MSC_SUBCLASS_SCSI 0x06 +#define MSC_PROTOCOL_BULK_ONLY 0x50 + +#ifndef USB_VERSION +#define USB_VERSION 0x200 +#endif + +// Device +typedef struct { + u8 len; // 18 + u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE + u16 usbVersion; // 0x200 or 0x210 + u8 deviceClass; + u8 deviceSubClass; + u8 deviceProtocol; + u8 packetSize0; // Packet 0 + u16 idVendor; + u16 idProduct; + u16 deviceVersion; // 0x100 + u8 iManufacturer; + u8 iProduct; + u8 iSerialNumber; + u8 bNumConfigurations; +} DeviceDescriptor; + +// Config +typedef struct { + u8 len; // 9 + u8 dtype; // 2 + u16 clen; // total length + u8 numInterfaces; + u8 config; + u8 iconfig; + u8 attributes; + u8 maxPower; +} ConfigDescriptor; + +// String + +// Interface +typedef struct +{ + u8 len; // 9 + u8 dtype; // 4 + u8 number; + u8 alternate; + u8 numEndpoints; + u8 interfaceClass; + u8 interfaceSubClass; + u8 protocol; + u8 iInterface; +} InterfaceDescriptor; + +// Endpoint +typedef struct +{ + u8 len; // 7 + u8 dtype; // 5 + u8 addr; + u8 attr; + u16 packetSize; + u8 interval; +} EndpointDescriptor; + +// Interface Association Descriptor +// Used to bind 2 interfaces together in CDC compostite device +typedef struct +{ + u8 len; // 8 + u8 dtype; // 11 + u8 firstInterface; + u8 interfaceCount; + u8 functionClass; + u8 funtionSubClass; + u8 functionProtocol; + u8 iInterface; +} IADDescriptor; + +// CDC CS interface descriptor +typedef struct +{ + u8 len; // 5 + u8 dtype; // 0x24 + u8 subtype; + u8 d0; + u8 d1; +} CDCCSInterfaceDescriptor; + +typedef struct +{ + u8 len; // 4 + u8 dtype; // 0x24 + u8 subtype; + u8 d0; +} CDCCSInterfaceDescriptor4; + +typedef struct +{ + u8 len; + u8 dtype; // 0x24 + u8 subtype; // 1 + u8 bmCapabilities; + u8 bDataInterface; +} CMFunctionalDescriptor; + +typedef struct +{ + u8 len; + u8 dtype; // 0x24 + u8 subtype; // 1 + u8 bmCapabilities; +} ACMFunctionalDescriptor; + +typedef struct +{ + // IAD + IADDescriptor iad; // Only needed on compound device + + // Control + InterfaceDescriptor cif; // + CDCCSInterfaceDescriptor header; + CMFunctionalDescriptor callManagement; // Call Management + ACMFunctionalDescriptor controlManagement; // ACM + CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION + EndpointDescriptor cifin; + + // Data + InterfaceDescriptor dif; + EndpointDescriptor in; + EndpointDescriptor out; +} CDCDescriptor; + +typedef struct +{ + InterfaceDescriptor msc; + EndpointDescriptor in; + EndpointDescriptor out; +} MSCDescriptor; + + +#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \ + { 18, 1, USB_VERSION, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs } + +#define D_CONFIG(_totalLength,_interfaces) \ + { 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, USB_CONFIG_POWER_MA(USB_CONFIG_POWER) } + +#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \ + { 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 } + +#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \ + { 7, 5, _addr,_attr,_packetSize, _interval } + +#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \ + { 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 } + +#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } +#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 } + +// Bootloader related fields +// Old Caterina bootloader places the MAGIC key into unsafe RAM locations (it can be rewritten +// by the running sketch before to actual reboot). +// Newer bootloaders, recognizable by the LUFA "signature" at the end of the flash, can handle both +// the usafe and the safe location. +#ifndef MAGIC_KEY +#define MAGIC_KEY 0x7777 +#endif + +#ifndef MAGIC_KEY_POS +#define MAGIC_KEY_POS 0x0800 +#endif + +#ifndef NEW_LUFA_SIGNATURE +#define NEW_LUFA_SIGNATURE 0xDCFB +#endif + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBDesc.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBDesc.h new file mode 100644 index 0000000..c0dce07 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/USBDesc.h @@ -0,0 +1,46 @@ +/* + Copyright (c) 2011, Peter Barrett + Copyright (c) 2015, Arduino LLC + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + */ + +#define PLUGGABLE_USB_ENABLED + +#if defined(EPRST6) +#define USB_ENDPOINTS 7 // AtMegaxxU4 +#else +#define USB_ENDPOINTS 5 // AtMegaxxU2 +#endif + +#define ISERIAL_MAX_LEN 20 + +#define CDC_INTERFACE_COUNT 2 +#define CDC_ENPOINT_COUNT 3 + +#define CDC_ACM_INTERFACE 0 // CDC ACM +#define CDC_DATA_INTERFACE 1 // CDC Data +#define CDC_FIRST_ENDPOINT 1 +#define CDC_ENDPOINT_ACM (CDC_FIRST_ENDPOINT) // CDC First +#define CDC_ENDPOINT_OUT (CDC_FIRST_ENDPOINT+1) +#define CDC_ENDPOINT_IN (CDC_FIRST_ENDPOINT+2) + +#define INTERFACE_COUNT (MSC_INTERFACE + MSC_INTERFACE_COUNT) + +#define CDC_RX CDC_ENDPOINT_OUT +#define CDC_TX CDC_ENDPOINT_IN + +#define IMANUFACTURER 1 +#define IPRODUCT 2 +#define ISERIAL 3 \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Udp.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Udp.h new file mode 100644 index 0000000..89f31c6 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/Udp.h @@ -0,0 +1,89 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef udp_h +#define udp_h + +#include +#include + +class UDP : public Stream { + +public: + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure + virtual void stop() =0; // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port) =0; + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port) =0; + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket() =0; + // Write a single byte into the packet + virtual size_t write(uint8_t) =0; + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size) =0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket() =0; + // Number of bytes remaining in the current packet + virtual int available() =0; + // Read a single byte from the current packet + virtual int read() =0; + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) =0; + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) =0; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek() =0; + virtual void flush() =0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() =0; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() =0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/WCharacter.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/WCharacter.h new file mode 100644 index 0000000..79733b5 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/WCharacter.h @@ -0,0 +1,168 @@ +/* + WCharacter.h - Character utility functions for Wiring & Arduino + Copyright (c) 2010 Hernando Barragan. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Character_h +#define Character_h + +#include + +// WCharacter.h prototypes +inline boolean isAlphaNumeric(int c) __attribute__((always_inline)); +inline boolean isAlpha(int c) __attribute__((always_inline)); +inline boolean isAscii(int c) __attribute__((always_inline)); +inline boolean isWhitespace(int c) __attribute__((always_inline)); +inline boolean isControl(int c) __attribute__((always_inline)); +inline boolean isDigit(int c) __attribute__((always_inline)); +inline boolean isGraph(int c) __attribute__((always_inline)); +inline boolean isLowerCase(int c) __attribute__((always_inline)); +inline boolean isPrintable(int c) __attribute__((always_inline)); +inline boolean isPunct(int c) __attribute__((always_inline)); +inline boolean isSpace(int c) __attribute__((always_inline)); +inline boolean isUpperCase(int c) __attribute__((always_inline)); +inline boolean isHexadecimalDigit(int c) __attribute__((always_inline)); +inline int toAscii(int c) __attribute__((always_inline)); +inline int toLowerCase(int c) __attribute__((always_inline)); +inline int toUpperCase(int c)__attribute__((always_inline)); + + +// Checks for an alphanumeric character. +// It is equivalent to (isalpha(c) || isdigit(c)). +inline boolean isAlphaNumeric(int c) +{ + return ( isalnum(c) == 0 ? false : true); +} + + +// Checks for an alphabetic character. +// It is equivalent to (isupper(c) || islower(c)). +inline boolean isAlpha(int c) +{ + return ( isalpha(c) == 0 ? false : true); +} + + +// Checks whether c is a 7-bit unsigned char value +// that fits into the ASCII character set. +inline boolean isAscii(int c) +{ + return ( isascii (c) == 0 ? false : true); +} + + +// Checks for a blank character, that is, a space or a tab. +inline boolean isWhitespace(int c) +{ + return ( isblank (c) == 0 ? false : true); +} + + +// Checks for a control character. +inline boolean isControl(int c) +{ + return ( iscntrl (c) == 0 ? false : true); +} + + +// Checks for a digit (0 through 9). +inline boolean isDigit(int c) +{ + return ( isdigit (c) == 0 ? false : true); +} + + +// Checks for any printable character except space. +inline boolean isGraph(int c) +{ + return ( isgraph (c) == 0 ? false : true); +} + + +// Checks for a lower-case character. +inline boolean isLowerCase(int c) +{ + return (islower (c) == 0 ? false : true); +} + + +// Checks for any printable character including space. +inline boolean isPrintable(int c) +{ + return ( isprint (c) == 0 ? false : true); +} + + +// Checks for any printable character which is not a space +// or an alphanumeric character. +inline boolean isPunct(int c) +{ + return ( ispunct (c) == 0 ? false : true); +} + + +// Checks for white-space characters. For the avr-libc library, +// these are: space, formfeed ('\f'), newline ('\n'), carriage +// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v'). +inline boolean isSpace(int c) +{ + return ( isspace (c) == 0 ? false : true); +} + + +// Checks for an uppercase letter. +inline boolean isUpperCase(int c) +{ + return ( isupper (c) == 0 ? false : true); +} + + +// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7 +// 8 9 a b c d e f A B C D E F. +inline boolean isHexadecimalDigit(int c) +{ + return ( isxdigit (c) == 0 ? false : true); +} + + +// Converts c to a 7-bit unsigned char value that fits into the +// ASCII character set, by clearing the high-order bits. +inline int toAscii(int c) +{ + return toascii (c); +} + + +// Warning: +// Many people will be unhappy if you use this function. +// This function will convert accented letters into random +// characters. + +// Converts the letter c to lower case, if possible. +inline int toLowerCase(int c) +{ + return tolower (c); +} + + +// Converts the letter c to upper case, if possible. +inline int toUpperCase(int c) +{ + return toupper (c); +} + +#endif \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/WString.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/WString.h new file mode 100644 index 0000000..77709c3 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/WString.h @@ -0,0 +1,229 @@ +/* + WString.h - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... + Copyright (c) 2009-10 Hernando Barragan. All right reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef String_class_h +#define String_class_h +#ifdef __cplusplus + +#include +#include +#include +#include + +// When compiling programs with this class, the following gcc parameters +// dramatically increase performance and memory (RAM) efficiency, typically +// with little or no increase in code size. +// -felide-constructors +// -std=c++0x + +class __FlashStringHelper; +#define F(string_literal) (reinterpret_cast(PSTR(string_literal))) + +// An inherited class for holding the result of a concatenation. These +// result objects are assumed to be writable by subsequent concatenations. +class StringSumHelper; + +// The string class +class String +{ + // use a function pointer to allow for "if (s)" without the + // complications of an operator bool(). for more information, see: + // http://www.artima.com/cppsource/safebool.html + typedef void (String::*StringIfHelperType)() const; + void StringIfHelper() const {} + +public: + // constructors + // creates a copy of the initial value. + // if the initial value is null or invalid, or if memory allocation + // fails, the string will be marked as invalid (i.e. "if (s)" will + // be false). + String(const char *cstr = ""); + String(const String &str); + String(const __FlashStringHelper *str); + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) + String(String &&rval); + String(StringSumHelper &&rval); + #endif + explicit String(char c); + explicit String(unsigned char, unsigned char base=10); + explicit String(int, unsigned char base=10); + explicit String(unsigned int, unsigned char base=10); + explicit String(long, unsigned char base=10); + explicit String(unsigned long, unsigned char base=10); + explicit String(float, unsigned char decimalPlaces=2); + explicit String(double, unsigned char decimalPlaces=2); + ~String(void); + + // memory management + // return true on success, false on failure (in which case, the string + // is left unchanged). reserve(0), if successful, will validate an + // invalid string (i.e., "if (s)" will be true afterwards) + unsigned char reserve(unsigned int size); + inline unsigned int length(void) const {return len;} + + // creates a copy of the assigned value. if the value is null or + // invalid, or if the memory allocation fails, the string will be + // marked as invalid ("if (s)" will be false). + String & operator = (const String &rhs); + String & operator = (const char *cstr); + String & operator = (const __FlashStringHelper *str); + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) + String & operator = (String &&rval); + String & operator = (StringSumHelper &&rval); + #endif + + // concatenate (works w/ built-in types) + + // returns true on success, false on failure (in which case, the string + // is left unchanged). if the argument is null or invalid, the + // concatenation is considered unsucessful. + unsigned char concat(const String &str); + unsigned char concat(const char *cstr); + unsigned char concat(char c); + unsigned char concat(unsigned char c); + unsigned char concat(int num); + unsigned char concat(unsigned int num); + unsigned char concat(long num); + unsigned char concat(unsigned long num); + unsigned char concat(float num); + unsigned char concat(double num); + unsigned char concat(const __FlashStringHelper * str); + + // if there's not enough memory for the concatenated value, the string + // will be left unchanged (but this isn't signalled in any way) + String & operator += (const String &rhs) {concat(rhs); return (*this);} + String & operator += (const char *cstr) {concat(cstr); return (*this);} + String & operator += (char c) {concat(c); return (*this);} + String & operator += (unsigned char num) {concat(num); return (*this);} + String & operator += (int num) {concat(num); return (*this);} + String & operator += (unsigned int num) {concat(num); return (*this);} + String & operator += (long num) {concat(num); return (*this);} + String & operator += (unsigned long num) {concat(num); return (*this);} + String & operator += (float num) {concat(num); return (*this);} + String & operator += (double num) {concat(num); return (*this);} + String & operator += (const __FlashStringHelper *str){concat(str); return (*this);} + + friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); + friend StringSumHelper & operator + (const StringSumHelper &lhs, char c); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, float num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, double num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs); + + // comparison (only works w/ Strings and "strings") + operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } + int compareTo(const String &s) const; + unsigned char equals(const String &s) const; + unsigned char equals(const char *cstr) const; + unsigned char operator == (const String &rhs) const {return equals(rhs);} + unsigned char operator == (const char *cstr) const {return equals(cstr);} + unsigned char operator != (const String &rhs) const {return !equals(rhs);} + unsigned char operator != (const char *cstr) const {return !equals(cstr);} + unsigned char operator < (const String &rhs) const; + unsigned char operator > (const String &rhs) const; + unsigned char operator <= (const String &rhs) const; + unsigned char operator >= (const String &rhs) const; + unsigned char equalsIgnoreCase(const String &s) const; + unsigned char startsWith( const String &prefix) const; + unsigned char startsWith(const String &prefix, unsigned int offset) const; + unsigned char endsWith(const String &suffix) const; + + // character acccess + char charAt(unsigned int index) const; + void setCharAt(unsigned int index, char c); + char operator [] (unsigned int index) const; + char& operator [] (unsigned int index); + void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; + void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const + { getBytes((unsigned char *)buf, bufsize, index); } + const char* c_str() const { return buffer; } + char* begin() { return buffer; } + char* end() { return buffer + length(); } + const char* begin() const { return c_str(); } + const char* end() const { return c_str() + length(); } + + // search + int indexOf( char ch ) const; + int indexOf( char ch, unsigned int fromIndex ) const; + int indexOf( const String &str ) const; + int indexOf( const String &str, unsigned int fromIndex ) const; + int lastIndexOf( char ch ) const; + int lastIndexOf( char ch, unsigned int fromIndex ) const; + int lastIndexOf( const String &str ) const; + int lastIndexOf( const String &str, unsigned int fromIndex ) const; + String substring( unsigned int beginIndex ) const { return substring(beginIndex, len); }; + String substring( unsigned int beginIndex, unsigned int endIndex ) const; + + // modification + void replace(char find, char replace); + void replace(const String& find, const String& replace); + void remove(unsigned int index); + void remove(unsigned int index, unsigned int count); + void toLowerCase(void); + void toUpperCase(void); + void trim(void); + + // parsing/conversion + long toInt(void) const; + float toFloat(void) const; + double toDouble(void) const; + +protected: + char *buffer; // the actual char array + unsigned int capacity; // the array length minus one (for the '\0') + unsigned int len; // the String length (not counting the '\0') +protected: + void init(void); + void invalidate(void); + unsigned char changeBuffer(unsigned int maxStrLen); + unsigned char concat(const char *cstr, unsigned int length); + + // copy and move + String & copy(const char *cstr, unsigned int length); + String & copy(const __FlashStringHelper *pstr, unsigned int length); + #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) + void move(String &rhs); + #endif +}; + +class StringSumHelper : public String +{ +public: + StringSumHelper(const String &s) : String(s) {} + StringSumHelper(const char *p) : String(p) {} + StringSumHelper(char c) : String(c) {} + StringSumHelper(unsigned char num) : String(num) {} + StringSumHelper(int num) : String(num) {} + StringSumHelper(unsigned int num) : String(num) {} + StringSumHelper(long num) : String(num) {} + StringSumHelper(unsigned long num) : String(num) {} + StringSumHelper(float num) : String(num) {} + StringSumHelper(double num) : String(num) {} +}; + +#endif // __cplusplus +#endif // String_class_h diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/binary.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/binary.h new file mode 100644 index 0000000..aec4c73 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/binary.h @@ -0,0 +1,534 @@ +/* + binary.h - Definitions for binary constants + Copyright (c) 2006 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Binary_h +#define Binary_h + +#define B0 0 +#define B00 0 +#define B000 0 +#define B0000 0 +#define B00000 0 +#define B000000 0 +#define B0000000 0 +#define B00000000 0 +#define B1 1 +#define B01 1 +#define B001 1 +#define B0001 1 +#define B00001 1 +#define B000001 1 +#define B0000001 1 +#define B00000001 1 +#define B10 2 +#define B010 2 +#define B0010 2 +#define B00010 2 +#define B000010 2 +#define B0000010 2 +#define B00000010 2 +#define B11 3 +#define B011 3 +#define B0011 3 +#define B00011 3 +#define B000011 3 +#define B0000011 3 +#define B00000011 3 +#define B100 4 +#define B0100 4 +#define B00100 4 +#define B000100 4 +#define B0000100 4 +#define B00000100 4 +#define B101 5 +#define B0101 5 +#define B00101 5 +#define B000101 5 +#define B0000101 5 +#define B00000101 5 +#define B110 6 +#define B0110 6 +#define B00110 6 +#define B000110 6 +#define B0000110 6 +#define B00000110 6 +#define B111 7 +#define B0111 7 +#define B00111 7 +#define B000111 7 +#define B0000111 7 +#define B00000111 7 +#define B1000 8 +#define B01000 8 +#define B001000 8 +#define B0001000 8 +#define B00001000 8 +#define B1001 9 +#define B01001 9 +#define B001001 9 +#define B0001001 9 +#define B00001001 9 +#define B1010 10 +#define B01010 10 +#define B001010 10 +#define B0001010 10 +#define B00001010 10 +#define B1011 11 +#define B01011 11 +#define B001011 11 +#define B0001011 11 +#define B00001011 11 +#define B1100 12 +#define B01100 12 +#define B001100 12 +#define B0001100 12 +#define B00001100 12 +#define B1101 13 +#define B01101 13 +#define B001101 13 +#define B0001101 13 +#define B00001101 13 +#define B1110 14 +#define B01110 14 +#define B001110 14 +#define B0001110 14 +#define B00001110 14 +#define B1111 15 +#define B01111 15 +#define B001111 15 +#define B0001111 15 +#define B00001111 15 +#define B10000 16 +#define B010000 16 +#define B0010000 16 +#define B00010000 16 +#define B10001 17 +#define B010001 17 +#define B0010001 17 +#define B00010001 17 +#define B10010 18 +#define B010010 18 +#define B0010010 18 +#define B00010010 18 +#define B10011 19 +#define B010011 19 +#define B0010011 19 +#define B00010011 19 +#define B10100 20 +#define B010100 20 +#define B0010100 20 +#define B00010100 20 +#define B10101 21 +#define B010101 21 +#define B0010101 21 +#define B00010101 21 +#define B10110 22 +#define B010110 22 +#define B0010110 22 +#define B00010110 22 +#define B10111 23 +#define B010111 23 +#define B0010111 23 +#define B00010111 23 +#define B11000 24 +#define B011000 24 +#define B0011000 24 +#define B00011000 24 +#define B11001 25 +#define B011001 25 +#define B0011001 25 +#define B00011001 25 +#define B11010 26 +#define B011010 26 +#define B0011010 26 +#define B00011010 26 +#define B11011 27 +#define B011011 27 +#define B0011011 27 +#define B00011011 27 +#define B11100 28 +#define B011100 28 +#define B0011100 28 +#define B00011100 28 +#define B11101 29 +#define B011101 29 +#define B0011101 29 +#define B00011101 29 +#define B11110 30 +#define B011110 30 +#define B0011110 30 +#define B00011110 30 +#define B11111 31 +#define B011111 31 +#define B0011111 31 +#define B00011111 31 +#define B100000 32 +#define B0100000 32 +#define B00100000 32 +#define B100001 33 +#define B0100001 33 +#define B00100001 33 +#define B100010 34 +#define B0100010 34 +#define B00100010 34 +#define B100011 35 +#define B0100011 35 +#define B00100011 35 +#define B100100 36 +#define B0100100 36 +#define B00100100 36 +#define B100101 37 +#define B0100101 37 +#define B00100101 37 +#define B100110 38 +#define B0100110 38 +#define B00100110 38 +#define B100111 39 +#define B0100111 39 +#define B00100111 39 +#define B101000 40 +#define B0101000 40 +#define B00101000 40 +#define B101001 41 +#define B0101001 41 +#define B00101001 41 +#define B101010 42 +#define B0101010 42 +#define B00101010 42 +#define B101011 43 +#define B0101011 43 +#define B00101011 43 +#define B101100 44 +#define B0101100 44 +#define B00101100 44 +#define B101101 45 +#define B0101101 45 +#define B00101101 45 +#define B101110 46 +#define B0101110 46 +#define B00101110 46 +#define B101111 47 +#define B0101111 47 +#define B00101111 47 +#define B110000 48 +#define B0110000 48 +#define B00110000 48 +#define B110001 49 +#define B0110001 49 +#define B00110001 49 +#define B110010 50 +#define B0110010 50 +#define B00110010 50 +#define B110011 51 +#define B0110011 51 +#define B00110011 51 +#define B110100 52 +#define B0110100 52 +#define B00110100 52 +#define B110101 53 +#define B0110101 53 +#define B00110101 53 +#define B110110 54 +#define B0110110 54 +#define B00110110 54 +#define B110111 55 +#define B0110111 55 +#define B00110111 55 +#define B111000 56 +#define B0111000 56 +#define B00111000 56 +#define B111001 57 +#define B0111001 57 +#define B00111001 57 +#define B111010 58 +#define B0111010 58 +#define B00111010 58 +#define B111011 59 +#define B0111011 59 +#define B00111011 59 +#define B111100 60 +#define B0111100 60 +#define B00111100 60 +#define B111101 61 +#define B0111101 61 +#define B00111101 61 +#define B111110 62 +#define B0111110 62 +#define B00111110 62 +#define B111111 63 +#define B0111111 63 +#define B00111111 63 +#define B1000000 64 +#define B01000000 64 +#define B1000001 65 +#define B01000001 65 +#define B1000010 66 +#define B01000010 66 +#define B1000011 67 +#define B01000011 67 +#define B1000100 68 +#define B01000100 68 +#define B1000101 69 +#define B01000101 69 +#define B1000110 70 +#define B01000110 70 +#define B1000111 71 +#define B01000111 71 +#define B1001000 72 +#define B01001000 72 +#define B1001001 73 +#define B01001001 73 +#define B1001010 74 +#define B01001010 74 +#define B1001011 75 +#define B01001011 75 +#define B1001100 76 +#define B01001100 76 +#define B1001101 77 +#define B01001101 77 +#define B1001110 78 +#define B01001110 78 +#define B1001111 79 +#define B01001111 79 +#define B1010000 80 +#define B01010000 80 +#define B1010001 81 +#define B01010001 81 +#define B1010010 82 +#define B01010010 82 +#define B1010011 83 +#define B01010011 83 +#define B1010100 84 +#define B01010100 84 +#define B1010101 85 +#define B01010101 85 +#define B1010110 86 +#define B01010110 86 +#define B1010111 87 +#define B01010111 87 +#define B1011000 88 +#define B01011000 88 +#define B1011001 89 +#define B01011001 89 +#define B1011010 90 +#define B01011010 90 +#define B1011011 91 +#define B01011011 91 +#define B1011100 92 +#define B01011100 92 +#define B1011101 93 +#define B01011101 93 +#define B1011110 94 +#define B01011110 94 +#define B1011111 95 +#define B01011111 95 +#define B1100000 96 +#define B01100000 96 +#define B1100001 97 +#define B01100001 97 +#define B1100010 98 +#define B01100010 98 +#define B1100011 99 +#define B01100011 99 +#define B1100100 100 +#define B01100100 100 +#define B1100101 101 +#define B01100101 101 +#define B1100110 102 +#define B01100110 102 +#define B1100111 103 +#define B01100111 103 +#define B1101000 104 +#define B01101000 104 +#define B1101001 105 +#define B01101001 105 +#define B1101010 106 +#define B01101010 106 +#define B1101011 107 +#define B01101011 107 +#define B1101100 108 +#define B01101100 108 +#define B1101101 109 +#define B01101101 109 +#define B1101110 110 +#define B01101110 110 +#define B1101111 111 +#define B01101111 111 +#define B1110000 112 +#define B01110000 112 +#define B1110001 113 +#define B01110001 113 +#define B1110010 114 +#define B01110010 114 +#define B1110011 115 +#define B01110011 115 +#define B1110100 116 +#define B01110100 116 +#define B1110101 117 +#define B01110101 117 +#define B1110110 118 +#define B01110110 118 +#define B1110111 119 +#define B01110111 119 +#define B1111000 120 +#define B01111000 120 +#define B1111001 121 +#define B01111001 121 +#define B1111010 122 +#define B01111010 122 +#define B1111011 123 +#define B01111011 123 +#define B1111100 124 +#define B01111100 124 +#define B1111101 125 +#define B01111101 125 +#define B1111110 126 +#define B01111110 126 +#define B1111111 127 +#define B01111111 127 +#define B10000000 128 +#define B10000001 129 +#define B10000010 130 +#define B10000011 131 +#define B10000100 132 +#define B10000101 133 +#define B10000110 134 +#define B10000111 135 +#define B10001000 136 +#define B10001001 137 +#define B10001010 138 +#define B10001011 139 +#define B10001100 140 +#define B10001101 141 +#define B10001110 142 +#define B10001111 143 +#define B10010000 144 +#define B10010001 145 +#define B10010010 146 +#define B10010011 147 +#define B10010100 148 +#define B10010101 149 +#define B10010110 150 +#define B10010111 151 +#define B10011000 152 +#define B10011001 153 +#define B10011010 154 +#define B10011011 155 +#define B10011100 156 +#define B10011101 157 +#define B10011110 158 +#define B10011111 159 +#define B10100000 160 +#define B10100001 161 +#define B10100010 162 +#define B10100011 163 +#define B10100100 164 +#define B10100101 165 +#define B10100110 166 +#define B10100111 167 +#define B10101000 168 +#define B10101001 169 +#define B10101010 170 +#define B10101011 171 +#define B10101100 172 +#define B10101101 173 +#define B10101110 174 +#define B10101111 175 +#define B10110000 176 +#define B10110001 177 +#define B10110010 178 +#define B10110011 179 +#define B10110100 180 +#define B10110101 181 +#define B10110110 182 +#define B10110111 183 +#define B10111000 184 +#define B10111001 185 +#define B10111010 186 +#define B10111011 187 +#define B10111100 188 +#define B10111101 189 +#define B10111110 190 +#define B10111111 191 +#define B11000000 192 +#define B11000001 193 +#define B11000010 194 +#define B11000011 195 +#define B11000100 196 +#define B11000101 197 +#define B11000110 198 +#define B11000111 199 +#define B11001000 200 +#define B11001001 201 +#define B11001010 202 +#define B11001011 203 +#define B11001100 204 +#define B11001101 205 +#define B11001110 206 +#define B11001111 207 +#define B11010000 208 +#define B11010001 209 +#define B11010010 210 +#define B11010011 211 +#define B11010100 212 +#define B11010101 213 +#define B11010110 214 +#define B11010111 215 +#define B11011000 216 +#define B11011001 217 +#define B11011010 218 +#define B11011011 219 +#define B11011100 220 +#define B11011101 221 +#define B11011110 222 +#define B11011111 223 +#define B11100000 224 +#define B11100001 225 +#define B11100010 226 +#define B11100011 227 +#define B11100100 228 +#define B11100101 229 +#define B11100110 230 +#define B11100111 231 +#define B11101000 232 +#define B11101001 233 +#define B11101010 234 +#define B11101011 235 +#define B11101100 236 +#define B11101101 237 +#define B11101110 238 +#define B11101111 239 +#define B11110000 240 +#define B11110001 241 +#define B11110010 242 +#define B11110011 243 +#define B11110100 244 +#define B11110101 245 +#define B11110110 246 +#define B11110111 247 +#define B11111000 248 +#define B11111001 249 +#define B11111010 250 +#define B11111011 251 +#define B11111100 252 +#define B11111101 253 +#define B11111110 254 +#define B11111111 255 + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/new.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/new.h new file mode 100644 index 0000000..763f5cc --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/new.h @@ -0,0 +1,31 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef NEW_H +#define NEW_H + +#include + +void * operator new(size_t size); +void * operator new[](size_t size); +void * operator new(size_t size, void * ptr) noexcept; +void operator delete(void * ptr); +void operator delete[](void * ptr); + +#endif + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/wiring_private.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/wiring_private.h new file mode 100644 index 0000000..a277b14 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/core/wiring_private.h @@ -0,0 +1,72 @@ +/* + wiring_private.h - Internal header file. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#ifndef WiringPrivate_h +#define WiringPrivate_h + +#include +#include +#include +#include + +#include "Arduino.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +uint32_t countPulseASM(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops); + +#define EXTERNAL_INT_0 0 +#define EXTERNAL_INT_1 1 +#define EXTERNAL_INT_2 2 +#define EXTERNAL_INT_3 3 +#define EXTERNAL_INT_4 4 +#define EXTERNAL_INT_5 5 +#define EXTERNAL_INT_6 6 +#define EXTERNAL_INT_7 7 + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega128RFA1__) || defined(__AVR_ATmega256RFR2__) || \ + defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__) +#define EXTERNAL_NUM_INTERRUPTS 8 +#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) +#define EXTERNAL_NUM_INTERRUPTS 3 +#elif defined(__AVR_ATmega32U4__) +#define EXTERNAL_NUM_INTERRUPTS 5 +#else +#define EXTERNAL_NUM_INTERRUPTS 2 +#endif + +typedef void (*voidFuncPtr)(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/variants/mega/pins_arduino.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/variants/mega/pins_arduino.h new file mode 100644 index 0000000..5115c04 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/include/variants/mega/pins_arduino.h @@ -0,0 +1,413 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define NUM_DIGITAL_PINS 70 +#define NUM_ANALOG_INPUTS 16 +#define analogInputToDigitalPin(p) ((p < 16) ? (p) + 54 : -1) +#define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 13) || ((p) >= 44 && (p)<= 46)) + +#define PIN_SPI_SS (53) +#define PIN_SPI_MOSI (51) +#define PIN_SPI_MISO (50) +#define PIN_SPI_SCK (52) + +static const uint8_t SS = PIN_SPI_SS; +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +#define PIN_WIRE_SDA (20) +#define PIN_WIRE_SCL (21) + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + +#define LED_BUILTIN 13 + +#define PIN_A0 (54) +#define PIN_A1 (55) +#define PIN_A2 (56) +#define PIN_A3 (57) +#define PIN_A4 (58) +#define PIN_A5 (59) +#define PIN_A6 (60) +#define PIN_A7 (61) +#define PIN_A8 (62) +#define PIN_A9 (63) +#define PIN_A10 (64) +#define PIN_A11 (65) +#define PIN_A12 (66) +#define PIN_A13 (67) +#define PIN_A14 (68) +#define PIN_A15 (69) + +static const uint8_t A0 = PIN_A0; +static const uint8_t A1 = PIN_A1; +static const uint8_t A2 = PIN_A2; +static const uint8_t A3 = PIN_A3; +static const uint8_t A4 = PIN_A4; +static const uint8_t A5 = PIN_A5; +static const uint8_t A6 = PIN_A6; +static const uint8_t A7 = PIN_A7; +static const uint8_t A8 = PIN_A8; +static const uint8_t A9 = PIN_A9; +static const uint8_t A10 = PIN_A10; +static const uint8_t A11 = PIN_A11; +static const uint8_t A12 = PIN_A12; +static const uint8_t A13 = PIN_A13; +static const uint8_t A14 = PIN_A14; +static const uint8_t A15 = PIN_A15; + +// A majority of the pins are NOT PCINTs, SO BE WARNED (i.e. you cannot use them as receive pins) +// Only pins available for RECEIVE (TRANSMIT can be on any pin): +// (I've deliberately left out pin mapping to the Hardware USARTs - seems senseless to me) +// Pins: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 + +#define digitalPinToPCICR(p) ( (((p) >= 10) && ((p) <= 13)) || \ + (((p) >= 50) && ((p) <= 53)) || \ + (((p) >= 62) && ((p) <= 69)) ? (&PCICR) : ((uint8_t *)0) ) + +#define digitalPinToPCICRbit(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? 0 : \ + ( (((p) >= 62) && ((p) <= 69)) ? 2 : \ + 0 ) ) + +#define digitalPinToPCMSK(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? (&PCMSK0) : \ + ( (((p) >= 62) && ((p) <= 69)) ? (&PCMSK2) : \ + ((uint8_t *)0) ) ) + +#define digitalPinToPCMSKbit(p) ( (((p) >= 10) && ((p) <= 13)) ? ((p) - 6) : \ + ( ((p) == 50) ? 3 : \ + ( ((p) == 51) ? 2 : \ + ( ((p) == 52) ? 1 : \ + ( ((p) == 53) ? 0 : \ + ( (((p) >= 62) && ((p) <= 69)) ? ((p) - 62) : \ + 0 ) ) ) ) ) ) + +#define digitalPinToInterrupt(p) ((p) == 2 ? 0 : ((p) == 3 ? 1 : ((p) >= 18 && (p) <= 21 ? 23 - (p) : NOT_AN_INTERRUPT))) + +#ifdef ARDUINO_MAIN + +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + (uint16_t) &DDRA, + (uint16_t) &DDRB, + (uint16_t) &DDRC, + (uint16_t) &DDRD, + (uint16_t) &DDRE, + (uint16_t) &DDRF, + (uint16_t) &DDRG, + (uint16_t) &DDRH, + NOT_A_PORT, + (uint16_t) &DDRJ, + (uint16_t) &DDRK, + (uint16_t) &DDRL, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + (uint16_t) &PORTA, + (uint16_t) &PORTB, + (uint16_t) &PORTC, + (uint16_t) &PORTD, + (uint16_t) &PORTE, + (uint16_t) &PORTF, + (uint16_t) &PORTG, + (uint16_t) &PORTH, + NOT_A_PORT, + (uint16_t) &PORTJ, + (uint16_t) &PORTK, + (uint16_t) &PORTL, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PIN, + (uint16_t) &PINA, + (uint16_t) &PINB, + (uint16_t) &PINC, + (uint16_t) &PIND, + (uint16_t) &PINE, + (uint16_t) &PINF, + (uint16_t) &PING, + (uint16_t) &PINH, + NOT_A_PIN, + (uint16_t) &PINJ, + (uint16_t) &PINK, + (uint16_t) &PINL, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + // PORTLIST + // ------------------------------------------- + PE , // PE 0 ** 0 ** USART0_RX + PE , // PE 1 ** 1 ** USART0_TX + PE , // PE 4 ** 2 ** PWM2 + PE , // PE 5 ** 3 ** PWM3 + PG , // PG 5 ** 4 ** PWM4 + PE , // PE 3 ** 5 ** PWM5 + PH , // PH 3 ** 6 ** PWM6 + PH , // PH 4 ** 7 ** PWM7 + PH , // PH 5 ** 8 ** PWM8 + PH , // PH 6 ** 9 ** PWM9 + PB , // PB 4 ** 10 ** PWM10 + PB , // PB 5 ** 11 ** PWM11 + PB , // PB 6 ** 12 ** PWM12 + PB , // PB 7 ** 13 ** PWM13 + PJ , // PJ 1 ** 14 ** USART3_TX + PJ , // PJ 0 ** 15 ** USART3_RX + PH , // PH 1 ** 16 ** USART2_TX + PH , // PH 0 ** 17 ** USART2_RX + PD , // PD 3 ** 18 ** USART1_TX + PD , // PD 2 ** 19 ** USART1_RX + PD , // PD 1 ** 20 ** I2C_SDA + PD , // PD 0 ** 21 ** I2C_SCL + PA , // PA 0 ** 22 ** D22 + PA , // PA 1 ** 23 ** D23 + PA , // PA 2 ** 24 ** D24 + PA , // PA 3 ** 25 ** D25 + PA , // PA 4 ** 26 ** D26 + PA , // PA 5 ** 27 ** D27 + PA , // PA 6 ** 28 ** D28 + PA , // PA 7 ** 29 ** D29 + PC , // PC 7 ** 30 ** D30 + PC , // PC 6 ** 31 ** D31 + PC , // PC 5 ** 32 ** D32 + PC , // PC 4 ** 33 ** D33 + PC , // PC 3 ** 34 ** D34 + PC , // PC 2 ** 35 ** D35 + PC , // PC 1 ** 36 ** D36 + PC , // PC 0 ** 37 ** D37 + PD , // PD 7 ** 38 ** D38 + PG , // PG 2 ** 39 ** D39 + PG , // PG 1 ** 40 ** D40 + PG , // PG 0 ** 41 ** D41 + PL , // PL 7 ** 42 ** D42 + PL , // PL 6 ** 43 ** D43 + PL , // PL 5 ** 44 ** D44 + PL , // PL 4 ** 45 ** D45 + PL , // PL 3 ** 46 ** D46 + PL , // PL 2 ** 47 ** D47 + PL , // PL 1 ** 48 ** D48 + PL , // PL 0 ** 49 ** D49 + PB , // PB 3 ** 50 ** SPI_MISO + PB , // PB 2 ** 51 ** SPI_MOSI + PB , // PB 1 ** 52 ** SPI_SCK + PB , // PB 0 ** 53 ** SPI_SS + PF , // PF 0 ** 54 ** A0 + PF , // PF 1 ** 55 ** A1 + PF , // PF 2 ** 56 ** A2 + PF , // PF 3 ** 57 ** A3 + PF , // PF 4 ** 58 ** A4 + PF , // PF 5 ** 59 ** A5 + PF , // PF 6 ** 60 ** A6 + PF , // PF 7 ** 61 ** A7 + PK , // PK 0 ** 62 ** A8 + PK , // PK 1 ** 63 ** A9 + PK , // PK 2 ** 64 ** A10 + PK , // PK 3 ** 65 ** A11 + PK , // PK 4 ** 66 ** A12 + PK , // PK 5 ** 67 ** A13 + PK , // PK 6 ** 68 ** A14 + PK , // PK 7 ** 69 ** A15 +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + // PIN IN PORT + // ------------------------------------------- + _BV( 0 ) , // PE 0 ** 0 ** USART0_RX + _BV( 1 ) , // PE 1 ** 1 ** USART0_TX + _BV( 4 ) , // PE 4 ** 2 ** PWM2 + _BV( 5 ) , // PE 5 ** 3 ** PWM3 + _BV( 5 ) , // PG 5 ** 4 ** PWM4 + _BV( 3 ) , // PE 3 ** 5 ** PWM5 + _BV( 3 ) , // PH 3 ** 6 ** PWM6 + _BV( 4 ) , // PH 4 ** 7 ** PWM7 + _BV( 5 ) , // PH 5 ** 8 ** PWM8 + _BV( 6 ) , // PH 6 ** 9 ** PWM9 + _BV( 4 ) , // PB 4 ** 10 ** PWM10 + _BV( 5 ) , // PB 5 ** 11 ** PWM11 + _BV( 6 ) , // PB 6 ** 12 ** PWM12 + _BV( 7 ) , // PB 7 ** 13 ** PWM13 + _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX + _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX + _BV( 1 ) , // PH 1 ** 16 ** USART2_TX + _BV( 0 ) , // PH 0 ** 17 ** USART2_RX + _BV( 3 ) , // PD 3 ** 18 ** USART1_TX + _BV( 2 ) , // PD 2 ** 19 ** USART1_RX + _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA + _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL + _BV( 0 ) , // PA 0 ** 22 ** D22 + _BV( 1 ) , // PA 1 ** 23 ** D23 + _BV( 2 ) , // PA 2 ** 24 ** D24 + _BV( 3 ) , // PA 3 ** 25 ** D25 + _BV( 4 ) , // PA 4 ** 26 ** D26 + _BV( 5 ) , // PA 5 ** 27 ** D27 + _BV( 6 ) , // PA 6 ** 28 ** D28 + _BV( 7 ) , // PA 7 ** 29 ** D29 + _BV( 7 ) , // PC 7 ** 30 ** D30 + _BV( 6 ) , // PC 6 ** 31 ** D31 + _BV( 5 ) , // PC 5 ** 32 ** D32 + _BV( 4 ) , // PC 4 ** 33 ** D33 + _BV( 3 ) , // PC 3 ** 34 ** D34 + _BV( 2 ) , // PC 2 ** 35 ** D35 + _BV( 1 ) , // PC 1 ** 36 ** D36 + _BV( 0 ) , // PC 0 ** 37 ** D37 + _BV( 7 ) , // PD 7 ** 38 ** D38 + _BV( 2 ) , // PG 2 ** 39 ** D39 + _BV( 1 ) , // PG 1 ** 40 ** D40 + _BV( 0 ) , // PG 0 ** 41 ** D41 + _BV( 7 ) , // PL 7 ** 42 ** D42 + _BV( 6 ) , // PL 6 ** 43 ** D43 + _BV( 5 ) , // PL 5 ** 44 ** D44 + _BV( 4 ) , // PL 4 ** 45 ** D45 + _BV( 3 ) , // PL 3 ** 46 ** D46 + _BV( 2 ) , // PL 2 ** 47 ** D47 + _BV( 1 ) , // PL 1 ** 48 ** D48 + _BV( 0 ) , // PL 0 ** 49 ** D49 + _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO + _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI + _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK + _BV( 0 ) , // PB 0 ** 53 ** SPI_SS + _BV( 0 ) , // PF 0 ** 54 ** A0 + _BV( 1 ) , // PF 1 ** 55 ** A1 + _BV( 2 ) , // PF 2 ** 56 ** A2 + _BV( 3 ) , // PF 3 ** 57 ** A3 + _BV( 4 ) , // PF 4 ** 58 ** A4 + _BV( 5 ) , // PF 5 ** 59 ** A5 + _BV( 6 ) , // PF 6 ** 60 ** A6 + _BV( 7 ) , // PF 7 ** 61 ** A7 + _BV( 0 ) , // PK 0 ** 62 ** A8 + _BV( 1 ) , // PK 1 ** 63 ** A9 + _BV( 2 ) , // PK 2 ** 64 ** A10 + _BV( 3 ) , // PK 3 ** 65 ** A11 + _BV( 4 ) , // PK 4 ** 66 ** A12 + _BV( 5 ) , // PK 5 ** 67 ** A13 + _BV( 6 ) , // PK 6 ** 68 ** A14 + _BV( 7 ) , // PK 7 ** 69 ** A15 +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + // TIMERS + // ------------------------------------------- + NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX + NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX + TIMER3B , // PE 4 ** 2 ** PWM2 + TIMER3C , // PE 5 ** 3 ** PWM3 + TIMER0B , // PG 5 ** 4 ** PWM4 + TIMER3A , // PE 3 ** 5 ** PWM5 + TIMER4A , // PH 3 ** 6 ** PWM6 + TIMER4B , // PH 4 ** 7 ** PWM7 + TIMER4C , // PH 5 ** 8 ** PWM8 + TIMER2B , // PH 6 ** 9 ** PWM9 + TIMER2A , // PB 4 ** 10 ** PWM10 + TIMER1A , // PB 5 ** 11 ** PWM11 + TIMER1B , // PB 6 ** 12 ** PWM12 + TIMER0A , // PB 7 ** 13 ** PWM13 + NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX + NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX + NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX + NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX + NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX + NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX + NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA + NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL + NOT_ON_TIMER , // PA 0 ** 22 ** D22 + NOT_ON_TIMER , // PA 1 ** 23 ** D23 + NOT_ON_TIMER , // PA 2 ** 24 ** D24 + NOT_ON_TIMER , // PA 3 ** 25 ** D25 + NOT_ON_TIMER , // PA 4 ** 26 ** D26 + NOT_ON_TIMER , // PA 5 ** 27 ** D27 + NOT_ON_TIMER , // PA 6 ** 28 ** D28 + NOT_ON_TIMER , // PA 7 ** 29 ** D29 + NOT_ON_TIMER , // PC 7 ** 30 ** D30 + NOT_ON_TIMER , // PC 6 ** 31 ** D31 + NOT_ON_TIMER , // PC 5 ** 32 ** D32 + NOT_ON_TIMER , // PC 4 ** 33 ** D33 + NOT_ON_TIMER , // PC 3 ** 34 ** D34 + NOT_ON_TIMER , // PC 2 ** 35 ** D35 + NOT_ON_TIMER , // PC 1 ** 36 ** D36 + NOT_ON_TIMER , // PC 0 ** 37 ** D37 + NOT_ON_TIMER , // PD 7 ** 38 ** D38 + NOT_ON_TIMER , // PG 2 ** 39 ** D39 + NOT_ON_TIMER , // PG 1 ** 40 ** D40 + NOT_ON_TIMER , // PG 0 ** 41 ** D41 + NOT_ON_TIMER , // PL 7 ** 42 ** D42 + NOT_ON_TIMER , // PL 6 ** 43 ** D43 + TIMER5C , // PL 5 ** 44 ** D44 + TIMER5B , // PL 4 ** 45 ** D45 + TIMER5A , // PL 3 ** 46 ** D46 + NOT_ON_TIMER , // PL 2 ** 47 ** D47 + NOT_ON_TIMER , // PL 1 ** 48 ** D48 + NOT_ON_TIMER , // PL 0 ** 49 ** D49 + NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO + NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI + NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK + NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS + NOT_ON_TIMER , // PF 0 ** 54 ** A0 + NOT_ON_TIMER , // PF 1 ** 55 ** A1 + NOT_ON_TIMER , // PF 2 ** 56 ** A2 + NOT_ON_TIMER , // PF 3 ** 57 ** A3 + NOT_ON_TIMER , // PF 4 ** 58 ** A4 + NOT_ON_TIMER , // PF 5 ** 59 ** A5 + NOT_ON_TIMER , // PF 6 ** 60 ** A6 + NOT_ON_TIMER , // PF 7 ** 61 ** A7 + NOT_ON_TIMER , // PK 0 ** 62 ** A8 + NOT_ON_TIMER , // PK 1 ** 63 ** A9 + NOT_ON_TIMER , // PK 2 ** 64 ** A10 + NOT_ON_TIMER , // PK 3 ** 65 ** A11 + NOT_ON_TIMER , // PK 4 ** 66 ** A12 + NOT_ON_TIMER , // PK 5 ** 67 ** A13 + NOT_ON_TIMER , // PK 6 ** 68 ** A14 + NOT_ON_TIMER , // PK 7 ** 69 ** A15 +}; + +#endif + +// These serial port names are intended to allow libraries and architecture-neutral +// sketches to automatically default to the correct port name for a particular type +// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, +// the first hardware serial port whose RX/TX pins are not dedicated to another use. +// +// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor +// +// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial +// +// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library +// +// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. +// +// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX +// pins are NOT connected to anything by default. +#define SERIAL_PORT_MONITOR Serial +#define SERIAL_PORT_HARDWARE Serial +#define SERIAL_PORT_HARDWARE1 Serial1 +#define SERIAL_PORT_HARDWARE2 Serial2 +#define SERIAL_PORT_HARDWARE3 Serial3 +#define SERIAL_PORT_HARDWARE_OPEN Serial1 +#define SERIAL_PORT_HARDWARE_OPEN1 Serial2 +#define SERIAL_PORT_HARDWARE_OPEN2 Serial3 + +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/library.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/library.cpp new file mode 100644 index 0000000..8a5364b --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/library.cpp @@ -0,0 +1,16 @@ +/* + * ArduinoCore.cpp + * + * Created: 11.02.2021 15:39:41 + * Author : EG + */ + +#include + + +/* Replace with your library code */ +int myfunc(void) +{ + return 0; +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/CDC.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/CDC.cpp new file mode 100644 index 0000000..4ff6b9b --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/CDC.cpp @@ -0,0 +1,302 @@ + + +/* Copyright (c) 2011, Peter Barrett +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#include "USBAPI.h" +#include +#include + +#if defined(USBCON) + +typedef struct +{ + u32 dwDTERate; + u8 bCharFormat; + u8 bParityType; + u8 bDataBits; + u8 lineState; +} LineInfo; + +static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; +static volatile int32_t breakValue = -1; + +static u8 wdtcsr_save; + +#define WEAK __attribute__ ((weak)) + +extern const CDCDescriptor _cdcInterface PROGMEM; +const CDCDescriptor _cdcInterface = +{ + D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), + + // CDC communication interface + D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), + D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd) + D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not) + D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported + D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0 + D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40), + + // CDC data interface + D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0), + D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0), + D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0) +}; + +bool isLUFAbootloader() +{ + return pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE; +} + +int CDC_GetInterface(u8* interfaceNum) +{ + interfaceNum[0] += 2; // uses 2 + return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface)); +} + +bool CDC_Setup(USBSetup& setup) +{ + u8 r = setup.bRequest; + u8 requestType = setup.bmRequestType; + + if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) + { + if (CDC_GET_LINE_CODING == r) + { + USB_SendControl(0,(void*)&_usbLineInfo,7); + return true; + } + } + + if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) + { + if (CDC_SEND_BREAK == r) + { + breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; + } + + if (CDC_SET_LINE_CODING == r) + { + USB_RecvControl((void*)&_usbLineInfo,7); + } + + if (CDC_SET_CONTROL_LINE_STATE == r) + { + _usbLineInfo.lineState = setup.wValueL; + + // auto-reset into the bootloader is triggered when the port, already + // open at 1200 bps, is closed. this is the signal to start the watchdog + // with a relatively long period so it can finish housekeeping tasks + // like servicing endpoints before the sketch ends + + uint16_t magic_key_pos = MAGIC_KEY_POS; + +// If we don't use the new RAMEND directly, check manually if we have a newer bootloader. +// This is used to keep compatible with the old leonardo bootloaders. +// You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check. +#if MAGIC_KEY_POS != (RAMEND-1) + // For future boards save the key in the inproblematic RAMEND + // Which is reserved for the main() return value (which will never return) + if (isLUFAbootloader()) { + // horray, we got a new bootloader! + magic_key_pos = (RAMEND-1); + } +#endif + + // We check DTR state to determine if host port is open (bit 0 of lineState). + if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) + { +#if MAGIC_KEY_POS != (RAMEND-1) + // Backup ram value if its not a newer bootloader and it hasn't already been saved. + // This should avoid memory corruption at least a bit, not fully + if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) { + *(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos; + } +#endif + // Store boot key + *(uint16_t *)magic_key_pos = MAGIC_KEY; + // Save the watchdog state in case the reset is aborted. + wdtcsr_save = WDTCSR; + wdt_enable(WDTO_120MS); + } + else if (*(uint16_t *)magic_key_pos == MAGIC_KEY) + { + // Most OSs do some intermediate steps when configuring ports and DTR can + // twiggle more than once before stabilizing. + // To avoid spurious resets we set the watchdog to 120ms and eventually + // cancel if DTR goes back high. + // Cancellation is only done if an auto-reset was started, which is + // indicated by the magic key having been set. + + wdt_reset(); + // Restore the watchdog state in case the sketch was using it. + WDTCSR |= (1<= 0) { + return 1 + USB_Available(CDC_RX); + } + return USB_Available(CDC_RX); +} + +int Serial_::peek(void) +{ + if (peek_buffer < 0) + peek_buffer = USB_Recv(CDC_RX); + return peek_buffer; +} + +int Serial_::read(void) +{ + if (peek_buffer >= 0) { + int c = peek_buffer; + peek_buffer = -1; + return c; + } + return USB_Recv(CDC_RX); +} + +int Serial_::availableForWrite(void) +{ + return USB_SendSpace(CDC_TX); +} + +void Serial_::flush(void) +{ + USB_Flush(CDC_TX); +} + +size_t Serial_::write(uint8_t c) +{ + return write(&c, 1); +} + +size_t Serial_::write(const uint8_t *buffer, size_t size) +{ + /* only try to send bytes if the high-level CDC connection itself + is open (not just the pipe) - the OS should set lineState when the port + is opened and clear lineState when the port is closed. + bytes sent before the user opens the connection or after + the connection is closed are lost - just like with a UART. */ + + // TODO - ZE - check behavior on different OSes and test what happens if an + // open connection isn't broken cleanly (cable is yanked out, host dies + // or locks up, or host virtual serial port hangs) + if (_usbLineInfo.lineState > 0) { + int r = USB_Send(CDC_TX,buffer,size); + if (r > 0) { + return r; + } else { + setWriteError(); + return 0; + } + } + setWriteError(); + return 0; +} + +// This operator is a convenient way for a sketch to check whether the +// port has actually been configured and opened by the host (as opposed +// to just being connected to the host). It can be used, for example, in +// setup() before printing to ensure that an application on the host is +// actually ready to receive and display the data. +// We add a short delay before returning to fix a bug observed by Federico +// where the port is configured (lineState != 0) but not quite opened. +Serial_::operator bool() { + bool result = false; + if (_usbLineInfo.lineState > 0) + result = true; + delay(10); + return result; +} + +unsigned long Serial_::baud() { + // Disable interrupts while reading a multi-byte value + uint32_t baudrate; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + baudrate = _usbLineInfo.dwDTERate; + } + return baudrate; +} + +uint8_t Serial_::stopbits() { + return _usbLineInfo.bCharFormat; +} + +uint8_t Serial_::paritytype() { + return _usbLineInfo.bParityType; +} + +uint8_t Serial_::numbits() { + return _usbLineInfo.bDataBits; +} + +bool Serial_::dtr() { + return _usbLineInfo.lineState & 0x1; +} + +bool Serial_::rts() { + return _usbLineInfo.lineState & 0x2; +} + +int32_t Serial_::readBreak() { + int32_t ret; + // Disable IRQs while reading and clearing breakValue to make + // sure we don't overwrite a value just set by the ISR. + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + ret = breakValue; + breakValue = -1; + } + return ret; +} + +Serial_ Serial; + +#endif /* if defined(USBCON) */ diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial.cpp new file mode 100644 index 0000000..1ec8a6d --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial.cpp @@ -0,0 +1,281 @@ +/* + HardwareSerial.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#include +#include +#include +#include +#include +#include "Arduino.h" + +#include "HardwareSerial.h" +#include "HardwareSerial_private.h" + +// this next line disables the entire HardwareSerial.cpp, +// this is so I can support Attiny series and any other chip without a uart +#if defined(HAVE_HWSERIAL0) || defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3) + +// SerialEvent functions are weak, so when the user doesn't define them, +// the linker just sets their address to 0 (which is checked below). +// The Serialx_available is just a wrapper around Serialx.available(), +// but we can refer to it weakly so we don't pull in the entire +// HardwareSerial instance if the user doesn't also refer to it. +#if defined(HAVE_HWSERIAL0) + void serialEvent() __attribute__((weak)); + bool Serial0_available() __attribute__((weak)); +#endif + +#if defined(HAVE_HWSERIAL1) + void serialEvent1() __attribute__((weak)); + bool Serial1_available() __attribute__((weak)); +#endif + +#if defined(HAVE_HWSERIAL2) + void serialEvent2() __attribute__((weak)); + bool Serial2_available() __attribute__((weak)); +#endif + +#if defined(HAVE_HWSERIAL3) + void serialEvent3() __attribute__((weak)); + bool Serial3_available() __attribute__((weak)); +#endif + +void serialEventRun(void) +{ +#if defined(HAVE_HWSERIAL0) + if (Serial0_available && serialEvent && Serial0_available()) serialEvent(); +#endif +#if defined(HAVE_HWSERIAL1) + if (Serial1_available && serialEvent1 && Serial1_available()) serialEvent1(); +#endif +#if defined(HAVE_HWSERIAL2) + if (Serial2_available && serialEvent2 && Serial2_available()) serialEvent2(); +#endif +#if defined(HAVE_HWSERIAL3) + if (Serial3_available && serialEvent3 && Serial3_available()) serialEvent3(); +#endif +} + +// macro to guard critical sections when needed for large TX buffer sizes +#if (SERIAL_TX_BUFFER_SIZE>256) +#define TX_BUFFER_ATOMIC ATOMIC_BLOCK(ATOMIC_RESTORESTATE) +#else +#define TX_BUFFER_ATOMIC +#endif + +// Actual interrupt handlers ////////////////////////////////////////////////////////////// + +void HardwareSerial::_tx_udr_empty_irq(void) +{ + // If interrupts are enabled, there must be more data in the output + // buffer. Send the next byte + unsigned char c = _tx_buffer[_tx_buffer_tail]; + _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE; + + *_udr = c; + + // clear the TXC bit -- "can be cleared by writing a one to its bit + // location". This makes sure flush() won't return until the bytes + // actually got written. Other r/w bits are preserved, and zeroes + // written to the rest. + +#ifdef MPCM0 + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); +#else + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0))); +#endif + + if (_tx_buffer_head == _tx_buffer_tail) { + // Buffer empty, so disable interrupts + cbi(*_ucsrb, UDRIE0); + } +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void HardwareSerial::begin(unsigned long baud, byte config) +{ + // Try u2x mode first + uint16_t baud_setting = (IDIBUS_F_CPU / 4 / baud - 1) / 2; + *_ucsra = 1 << U2X0; + + // hardcoded exception for 57600 for compatibility with the bootloader + // shipped with the Duemilanove and previous boards and the firmware + // on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot + // be > 4095, so switch back to non-u2x mode if the baud rate is too + // low. + if (((IDIBUS_F_CPU == 16000000UL) && (baud == 57600)) || (baud_setting >4095)) + { + *_ucsra = 0; + baud_setting = (IDIBUS_F_CPU / 8 / baud - 1) / 2; + } + + // assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register) + *_ubrrh = baud_setting >> 8; + *_ubrrl = baud_setting; + + _written = false; + + //set the data bits, parity, and stop bits +#if defined(__AVR_ATmega8__) + config |= 0x80; // select UCSRC register (shared with UBRRH) +#endif + *_ucsrc = config; + + sbi(*_ucsrb, RXEN0); + sbi(*_ucsrb, TXEN0); + sbi(*_ucsrb, RXCIE0); + cbi(*_ucsrb, UDRIE0); +} + +void HardwareSerial::end() +{ + // wait for transmission of outgoing data + flush(); + + cbi(*_ucsrb, RXEN0); + cbi(*_ucsrb, TXEN0); + cbi(*_ucsrb, RXCIE0); + cbi(*_ucsrb, UDRIE0); + + // clear any received data + _rx_buffer_head = _rx_buffer_tail; +} + +int HardwareSerial::available(void) +{ + return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE; +} + +int HardwareSerial::peek(void) +{ + if (_rx_buffer_head == _rx_buffer_tail) { + return -1; + } else { + return _rx_buffer[_rx_buffer_tail]; + } +} + +int HardwareSerial::read(void) +{ + // if the head isn't ahead of the tail, we don't have any characters + if (_rx_buffer_head == _rx_buffer_tail) { + return -1; + } else { + unsigned char c = _rx_buffer[_rx_buffer_tail]; + _rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE; + return c; + } +} + +int HardwareSerial::availableForWrite(void) +{ + tx_buffer_index_t head; + tx_buffer_index_t tail; + + TX_BUFFER_ATOMIC { + head = _tx_buffer_head; + tail = _tx_buffer_tail; + } + if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail; + return tail - head - 1; +} + +void HardwareSerial::flush() +{ + // If we have never written a byte, no need to flush. This special + // case is needed since there is no way to force the TXC (transmit + // complete) bit to 1 during initialization + if (!_written) + return; + + while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) { + if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0)) + // Interrupts are globally disabled, but the DR empty + // interrupt should be enabled, so poll the DR empty flag to + // prevent deadlock + if (bit_is_set(*_ucsra, UDRE0)) + _tx_udr_empty_irq(); + } + // If we get here, nothing is queued anymore (DRIE is disabled) and + // the hardware finished tranmission (TXC is set). +} + +size_t HardwareSerial::write(uint8_t c) +{ + _written = true; + // If the buffer and the data register is empty, just write the byte + // to the data register and be done. This shortcut helps + // significantly improve the effective datarate at high (> + // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. + if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) { + // If TXC is cleared before writing UDR and the previous byte + // completes before writing to UDR, TXC will be set but a byte + // is still being transmitted causing flush() to return too soon. + // So writing UDR must happen first. + // Writing UDR and clearing TC must be done atomically, otherwise + // interrupts might delay the TXC clear so the byte written to UDR + // is transmitted (setting TXC) before clearing TXC. Then TXC will + // be cleared when no bytes are left, causing flush() to hang + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + *_udr = c; +#ifdef MPCM0 + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); +#else + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0))); +#endif + } + return 1; + } + tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; + + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + while (i == _tx_buffer_tail) { + if (bit_is_clear(SREG, SREG_I)) { + // Interrupts are disabled, so we'll have to poll the data + // register empty flag ourselves. If it is set, pretend an + // interrupt has happened and call the handler to free up + // space for us. + if(bit_is_set(*_ucsra, UDRE0)) + _tx_udr_empty_irq(); + } else { + // nop, the interrupt handler will free up space for us + } + } + + _tx_buffer[_tx_buffer_head] = c; + + // make atomic to prevent execution of ISR between setting the + // head pointer and setting the interrupt flag resulting in buffer + // retransmission + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + _tx_buffer_head = i; + sbi(*_ucsrb, UDRIE0); + } + + return 1; +} + +#endif // whole file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial0.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial0.cpp new file mode 100644 index 0000000..7d47ed2 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial0.cpp @@ -0,0 +1,79 @@ +/* + HardwareSerial0.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#include "Arduino.h" +#include "HardwareSerial.h" +#include "HardwareSerial_private.h" + +// Each HardwareSerial is defined in its own file, since the linker pulls +// in the entire file when any element inside is used. --gc-sections can +// additionally cause unused symbols to be dropped, but ISRs have the +// "used" attribute so are never dropped and they keep the +// HardwareSerial instance in as well. Putting each instance in its own +// file prevents the linker from pulling in any unused instances in the +// first place. + +#if defined(HAVE_HWSERIAL0) + +#if defined(USART_RX_vect) + ISR(USART_RX_vect) +#elif defined(USART0_RX_vect) + ISR(USART0_RX_vect) +#elif defined(USART_RXC_vect) + ISR(USART_RXC_vect) // ATmega8 +#else + #error "Don't know what the Data Received vector is called for Serial" +#endif + { + Serial._rx_complete_irq(); + } + +#if defined(UART0_UDRE_vect) +ISR(UART0_UDRE_vect) +#elif defined(UART_UDRE_vect) +ISR(UART_UDRE_vect) +#elif defined(USART0_UDRE_vect) +ISR(USART0_UDRE_vect) +#elif defined(USART_UDRE_vect) +ISR(USART_UDRE_vect) +#else + #error "Don't know what the Data Register Empty vector is called for Serial" +#endif +{ + Serial._tx_udr_empty_irq(); +} + +#if defined(UBRRH) && defined(UBRRL) + HardwareSerial Serial(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR); +#else + HardwareSerial Serial(&UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0); +#endif + +// Function that can be weakly referenced by serialEventRun to prevent +// pulling in this file if it's not otherwise used. +bool Serial0_available() { + return Serial.available(); +} + +#endif // HAVE_HWSERIAL0 diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial1.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial1.cpp new file mode 100644 index 0000000..a345cdb --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial1.cpp @@ -0,0 +1,69 @@ +/* + HardwareSerial1.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#include "Arduino.h" +#include "HardwareSerial.h" +#include "HardwareSerial_private.h" + +// Each HardwareSerial is defined in its own file, since the linker pulls +// in the entire file when any element inside is used. --gc-sections can +// additionally cause unused symbols to be dropped, but ISRs have the +// "used" attribute so are never dropped and they keep the +// HardwareSerial instance in as well. Putting each instance in its own +// file prevents the linker from pulling in any unused instances in the +// first place. + +#if defined(HAVE_HWSERIAL1) + +#if defined(UART1_RX_vect) +ISR(UART1_RX_vect) +#elif defined(USART1_RX_vect) +ISR(USART1_RX_vect) +#else +#error "Don't know what the Data Register Empty vector is called for Serial1" +#endif +{ + Serial1._rx_complete_irq(); +} + +#if defined(UART1_UDRE_vect) +ISR(UART1_UDRE_vect) +#elif defined(USART1_UDRE_vect) +ISR(USART1_UDRE_vect) +#else +#error "Don't know what the Data Register Empty vector is called for Serial1" +#endif +{ + Serial1._tx_udr_empty_irq(); +} + +HardwareSerial Serial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1); + +// Function that can be weakly referenced by serialEventRun to prevent +// pulling in this file if it's not otherwise used. +bool Serial1_available() { + return Serial1.available(); +} + +#endif // HAVE_HWSERIAL1 diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial2.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial2.cpp new file mode 100644 index 0000000..8e433b6 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial2.cpp @@ -0,0 +1,57 @@ +/* + HardwareSerial2.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#include "Arduino.h" +#include "HardwareSerial.h" +#include "HardwareSerial_private.h" + +// Each HardwareSerial is defined in its own file, since the linker pulls +// in the entire file when any element inside is used. --gc-sections can +// additionally cause unused symbols to be dropped, but ISRs have the +// "used" attribute so are never dropped and they keep the +// HardwareSerial instance in as well. Putting each instance in its own +// file prevents the linker from pulling in any unused instances in the +// first place. + +#if defined(HAVE_HWSERIAL2) + +ISR(USART2_RX_vect) +{ + Serial2._rx_complete_irq(); +} + +ISR(USART2_UDRE_vect) +{ + Serial2._tx_udr_empty_irq(); +} + +HardwareSerial Serial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2); + +// Function that can be weakly referenced by serialEventRun to prevent +// pulling in this file if it's not otherwise used. +bool Serial2_available() { + return Serial2.available(); +} + +#endif // HAVE_HWSERIAL2 diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial3.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial3.cpp new file mode 100644 index 0000000..26aaee8 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/HardwareSerial3.cpp @@ -0,0 +1,57 @@ +/* + HardwareSerial3.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman +*/ + +#include "Arduino.h" +#include "HardwareSerial.h" +#include "HardwareSerial_private.h" + +// Each HardwareSerial is defined in its own file, since the linker pulls +// in the entire file when any element inside is used. --gc-sections can +// additionally cause unused symbols to be dropped, but ISRs have the +// "used" attribute so are never dropped and they keep the +// HardwareSerial instance in as well. Putting each instance in its own +// file prevents the linker from pulling in any unused instances in the +// first place. + +#if defined(HAVE_HWSERIAL3) + +ISR(USART3_RX_vect) +{ + Serial3._rx_complete_irq(); +} + +ISR(USART3_UDRE_vect) +{ + Serial3._tx_udr_empty_irq(); +} + +HardwareSerial Serial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3); + +// Function that can be weakly referenced by serialEventRun to prevent +// pulling in this file if it's not otherwise used. +bool Serial3_available() { + return Serial3.available(); +} + +#endif // HAVE_HWSERIAL3 diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/IPAddress.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/IPAddress.cpp new file mode 100644 index 0000000..d9fe5be --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/IPAddress.cpp @@ -0,0 +1,114 @@ +/* + IPAddress.cpp - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +IPAddress::IPAddress() +{ + _address.dword = 0; +} + +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) +{ + _address.bytes[0] = first_octet; + _address.bytes[1] = second_octet; + _address.bytes[2] = third_octet; + _address.bytes[3] = fourth_octet; +} + +IPAddress::IPAddress(uint32_t address) +{ + _address.dword = address; +} + +IPAddress::IPAddress(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); +} + +bool IPAddress::fromString(const char *address) +{ + uint16_t acc = 0; // Accumulator + uint8_t dots = 0; + + while (*address) + { + char c = *address++; + if (c >= '0' && c <= '9') + { + acc = acc * 10 + (c - '0'); + if (acc > 255) { + // Value out of [0..255] range + return false; + } + } + else if (c == '.') + { + if (dots == 3) { + // Too much dots (there must be 3 dots) + return false; + } + _address.bytes[dots++] = acc; + acc = 0; + } + else + { + // Invalid char + return false; + } + } + + if (dots != 3) { + // Too few dots (there must be 3 dots) + return false; + } + _address.bytes[3] = acc; + return true; +} + +IPAddress& IPAddress::operator=(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) +{ + _address.dword = address; + return *this; +} + +bool IPAddress::operator==(const uint8_t* addr) const +{ + return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; +} + +size_t IPAddress::printTo(Print& p) const +{ + size_t n = 0; + for (int i =0; i < 3; i++) + { + n += p.print(_address.bytes[i], DEC); + n += p.print('.'); + } + n += p.print(_address.bytes[3], DEC); + return n; +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/PluggableUSB.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/PluggableUSB.cpp new file mode 100644 index 0000000..c489d9f --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/PluggableUSB.cpp @@ -0,0 +1,115 @@ +/* + PluggableUSB.cpp + Copyright (c) 2015 Arduino LLC + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "USBAPI.h" +#include "PluggableUSB.h" + +#if defined(USBCON) +#ifdef PLUGGABLE_USB_ENABLED + +extern uint8_t _initEndpoints[]; + +int PluggableUSB_::getInterface(uint8_t* interfaceCount) +{ + int sent = 0; + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + int res = node->getInterface(interfaceCount); + if (res < 0) + return -1; + sent += res; + } + return sent; +} + +int PluggableUSB_::getDescriptor(USBSetup& setup) +{ + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + int ret = node->getDescriptor(setup); + // ret!=0 -> request has been processed + if (ret) + return ret; + } + return 0; +} + +void PluggableUSB_::getShortName(char *iSerialNum) +{ + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + iSerialNum += node->getShortName(iSerialNum); + } + *iSerialNum = 0; +} + +bool PluggableUSB_::setup(USBSetup& setup) +{ + PluggableUSBModule* node; + for (node = rootNode; node; node = node->next) { + if (node->setup(setup)) { + return true; + } + } + return false; +} + +bool PluggableUSB_::plug(PluggableUSBModule *node) +{ + if ((lastEp + node->numEndpoints) > USB_ENDPOINTS) { + return false; + } + + if (!rootNode) { + rootNode = node; + } else { + PluggableUSBModule *current = rootNode; + while (current->next) { + current = current->next; + } + current->next = node; + } + + node->pluggedInterface = lastIf; + node->pluggedEndpoint = lastEp; + lastIf += node->numInterfaces; + for (uint8_t i = 0; i < node->numEndpoints; i++) { + _initEndpoints[lastEp] = node->endpointType[i]; + lastEp++; + } + return true; + // restart USB layer??? +} + +PluggableUSB_& PluggableUSB() +{ + static PluggableUSB_ obj; + return obj; +} + +PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT), + lastEp(CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT), + rootNode(NULL) +{ + // Empty +} + +#endif + +#endif /* if defined(USBCON) */ diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/PreprocessingAssembly/wiring_pulse.S b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/PreprocessingAssembly/wiring_pulse.S new file mode 100644 index 0000000..1dd22e6 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/PreprocessingAssembly/wiring_pulse.S @@ -0,0 +1,178 @@ +/* + wiring_pulse.s - pulseInASM() function in different flavours + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2014 Martino Facchin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +/* + * The following routine was generated by avr-gcc 4.8.3 with the following parameters + * -gstabs -Wa,-ahlmsd=output.lst -dp -fverbose-asm -O2 + * on the original C function + * + * unsigned long pulseInSimpl(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops) + * { + * unsigned long width = 0; + * // wait for any previous pulse to end + * while ((*port & bit) == stateMask) + * if (--maxloops == 0) + * return 0; + * + * // wait for the pulse to start + * while ((*port & bit) != stateMask) + * if (--maxloops == 0) + * return 0; + * + * // wait for the pulse to stop + * while ((*port & bit) == stateMask) { + * if (++width == maxloops) + * return 0; + * } + * return width; + * } + * + * some compiler outputs were removed but the rest of the code is untouched + */ + +#include + +.section .text + +.global countPulseASM + +countPulseASM: + +.LM0: +.LFBB1: + push r12 ; ; 130 pushqi1/1 [length = 1] + push r13 ; ; 131 pushqi1/1 [length = 1] + push r14 ; ; 132 pushqi1/1 [length = 1] + push r15 ; ; 133 pushqi1/1 [length = 1] + push r16 ; ; 134 pushqi1/1 [length = 1] + push r17 ; ; 135 pushqi1/1 [length = 1] +/* prologue: function */ +/* frame size = 0 */ +/* stack size = 6 */ +.L__stack_usage = 6 + mov r30,r24 ; port, port ; 2 *movhi/1 [length = 2] + mov r31,r25 ; port, port +/* unsigned long width = 0; +*** // wait for any previous pulse to end +*** while ((*port & bit) == stateMask) +*/ +.LM1: + rjmp .L2 ; ; 181 jump [length = 1] +.L4: +/* if (--maxloops == 0) */ +.LM2: + subi r16,1 ; maxloops, ; 17 addsi3/2 [length = 4] + sbc r17, r1 ; maxloops + sbc r18, r1 ; maxloops + sbc r19, r1 ; maxloops + breq .L13 ; , ; 19 branch [length = 1] +.L2: +/* if (--maxloops == 0) */ +.LM3: + ld r25,Z ; D.1554, *port_7(D) ; 22 movqi_insn/4 [length = 1] + and r25,r22 ; D.1554, bit ; 24 andqi3/1 [length = 1] + cp r25,r20 ; D.1554, stateMask ; 25 *cmpqi/2 [length = 1] + breq .L4 ; , ; 26 branch [length = 1] + rjmp .L6 ; ; 184 jump [length = 1] +.L7: +/* return 0; +*** +*** // wait for the pulse to start +*** while ((*port & bit) != stateMask) +*** if (--maxloops == 0) +*/ +.LM4: + subi r16,1 ; maxloops, ; 31 addsi3/2 [length = 4] + sbc r17, r1 ; maxloops + sbc r18, r1 ; maxloops + sbc r19, r1 ; maxloops + breq .L13 ; , ; 33 branch [length = 1] +.L6: +/* if (--maxloops == 0) */ +.LM5: + ld r25,Z ; D.1554, *port_7(D) ; 41 movqi_insn/4 [length = 1] + and r25,r22 ; D.1554, bit ; 43 andqi3/1 [length = 1] + cpse r25,r20 ; D.1554, stateMask ; 44 enable_interrupt-3 [length = 1] + rjmp .L7 ; + mov r12, r1 ; width ; 7 *movsi/2 [length = 4] + mov r13, r1 ; width + mov r14, r1 ; width + mov r15, r1 ; width + rjmp .L9 ; ; 186 jump [length = 1] +.L10: +/* return 0; +*** +*** // wait for the pulse to stop +*** while ((*port & bit) == stateMask) { +*** if (++width == maxloops) +*/ +.LM6: + ldi r24,-1 ; , ; 50 addsi3/3 [length = 5] + sub r12,r24 ; width, + sbc r13,r24 ; width, + sbc r14,r24 ; width, + sbc r15,r24 ; width, + cp r16,r12 ; maxloops, width ; 51 *cmpsi/2 [length = 4] + cpc r17,r13 ; maxloops, width + cpc r18,r14 ; maxloops, width + cpc r19,r15 ; maxloops, width + breq .L13 ; , ; 52 branch [length = 1] +.L9: +/* if (++width == maxloops) */ +.LM7: + ld r24,Z ; D.1554, *port_7(D) ; 60 movqi_insn/4 [length = 1] + and r24,r22 ; D.1554, bit ; 62 andqi3/1 [length = 1] + cp r24,r20 ; D.1554, stateMask ; 63 *cmpqi/2 [length = 1] + breq .L10 ; , ; 64 branch [length = 1] +/* return 0; +*** } +*** return width; +*/ +.LM8: + mov r22,r12 ; D.1553, width ; 108 movqi_insn/1 [length = 1] + mov r23,r13 ; D.1553, width ; 109 movqi_insn/1 [length = 1] + mov r24,r14 ; D.1553, width ; 110 movqi_insn/1 [length = 1] + mov r25,r15 ; D.1553, width ; 111 movqi_insn/1 [length = 1] +/* epilogue start */ +.LM9: + pop r17 ; ; 171 popqi [length = 1] + pop r16 ; ; 172 popqi [length = 1] + pop r15 ; ; 173 popqi [length = 1] + pop r14 ; ; 174 popqi [length = 1] + pop r13 ; ; 175 popqi [length = 1] + pop r12 ; ; 176 popqi [length = 1] + ret ; 177 return_from_epilogue [length = 1] +.L13: +.LM10: + ldi r22,0 ; D.1553 ; 120 movqi_insn/1 [length = 1] + ldi r23,0 ; D.1553 ; 121 movqi_insn/1 [length = 1] + ldi r24,0 ; D.1553 ; 122 movqi_insn/1 [length = 1] + ldi r25,0 ; D.1553 ; 123 movqi_insn/1 [length = 1] +/* epilogue start */ +.LM11: + pop r17 ; ; 138 popqi [length = 1] + pop r16 ; ; 139 popqi [length = 1] + pop r15 ; ; 140 popqi [length = 1] + pop r14 ; ; 141 popqi [length = 1] + pop r13 ; ; 142 popqi [length = 1] + pop r12 ; ; 143 popqi [length = 1] + ret ; 144 return_from_epilogue [length = 1] diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Print.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Print.cpp new file mode 100644 index 0000000..1e4c99a --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Print.cpp @@ -0,0 +1,266 @@ +/* + Print.cpp - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified 03 August 2015 by Chuck Todd + */ + +#include +#include +#include +#include +#include "Arduino.h" + +#include "Print.h" + +// Public Methods ////////////////////////////////////////////////////////////// + +/* default implementation: may be overridden */ +size_t Print::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + while (size--) { + if (write(*buffer++)) n++; + else break; + } + return n; +} + +size_t Print::print(const __FlashStringHelper *ifsh) +{ + PGM_P p = reinterpret_cast(ifsh); + size_t n = 0; + while (1) { + unsigned char c = pgm_read_byte(p++); + if (c == 0) break; + if (write(c)) n++; + else break; + } + return n; +} + +size_t Print::print(const String &s) +{ + return write(s.c_str(), s.length()); +} + +size_t Print::print(const char str[]) +{ + return write(str); +} + +size_t Print::print(char c) +{ + return write(c); +} + +size_t Print::print(unsigned char b, int base) +{ + return print((unsigned long) b, base); +} + +size_t Print::print(int n, int base) +{ + return print((long) n, base); +} + +size_t Print::print(unsigned int n, int base) +{ + return print((unsigned long) n, base); +} + +size_t Print::print(long n, int base) +{ + if (base == 0) { + return write(n); + } else if (base == 10) { + if (n < 0) { + int t = print('-'); + n = -n; + return printNumber(n, 10) + t; + } + return printNumber(n, 10); + } else { + return printNumber(n, base); + } +} + +size_t Print::print(unsigned long n, int base) +{ + if (base == 0) return write(n); + else return printNumber(n, base); +} + +size_t Print::print(double n, int digits) +{ + return printFloat(n, digits); +} + +size_t Print::println(const __FlashStringHelper *ifsh) +{ + size_t n = print(ifsh); + n += println(); + return n; +} + +size_t Print::print(const Printable& x) +{ + return x.printTo(*this); +} + +size_t Print::println(void) +{ + return write("\r\n"); +} + +size_t Print::println(const String &s) +{ + size_t n = print(s); + n += println(); + return n; +} + +size_t Print::println(const char c[]) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(char c) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(unsigned char b, int base) +{ + size_t n = print(b, base); + n += println(); + return n; +} + +size_t Print::println(int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(double num, int digits) +{ + size_t n = print(num, digits); + n += println(); + return n; +} + +size_t Print::println(const Printable& x) +{ + size_t n = print(x); + n += println(); + return n; +} + +// Private Methods ///////////////////////////////////////////////////////////// + +size_t Print::printNumber(unsigned long n, uint8_t base) +{ + char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + // prevent crash if called with base == 1 + if (base < 2) base = 10; + + do { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + return write(str); +} + +size_t Print::printFloat(double number, uint8_t digits) +{ + size_t n = 0; + + if (isnan(number)) return print("nan"); + if (isinf(number)) return print("inf"); + if (number > 4294967040.0) return print ("ovf"); // constant determined empirically + if (number <-4294967040.0) return print ("ovf"); // constant determined empirically + + // Handle negative numbers + if (number < 0.0) + { + n += print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8_t i=0; i 0) { + n += print('.'); + } + + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + unsigned int toPrint = (unsigned int)(remainder); + n += print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Stream.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Stream.cpp new file mode 100644 index 0000000..9eff663 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Stream.cpp @@ -0,0 +1,318 @@ +/* + Stream.cpp - adds parsing methods to Stream class + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Created July 2011 + parsing functions based on TextFinder library by Michael Margolis + + findMulti/findUntil routines written by Jim Leonard/Xuth + */ + +#include "Arduino.h" +#include "Stream.h" + +#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait + +// protected method to read stream with timeout +int Stream::timedRead() +{ + int c; + _startMillis = millis(); + do { + c = read(); + if (c >= 0) return c; + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// protected method to peek stream with timeout +int Stream::timedPeek() +{ + int c; + _startMillis = millis(); + do { + c = peek(); + if (c >= 0) return c; + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// returns peek of the next digit in the stream or -1 if timeout +// discards non-numeric characters +int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal) +{ + int c; + while (1) { + c = timedPeek(); + + if( c < 0 || + c == '-' || + (c >= '0' && c <= '9') || + (detectDecimal && c == '.')) return c; + + switch( lookahead ){ + case SKIP_NONE: return -1; // Fail code. + case SKIP_WHITESPACE: + switch( c ){ + case ' ': + case '\t': + case '\r': + case '\n': break; + default: return -1; // Fail code. + } + case SKIP_ALL: + break; + } + read(); // discard non-numeric + } +} + +// Public Methods +////////////////////////////////////////////////////////////// + +void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait +{ + _timeout = timeout; +} + + // find returns true if the target string is found +bool Stream::find(char *target) +{ + return findUntil(target, strlen(target), NULL, 0); +} + +// reads data from the stream until the target string of given length is found +// returns true if target string is found, false if timed out +bool Stream::find(char *target, size_t length) +{ + return findUntil(target, length, NULL, 0); +} + +// as find but search ends if the terminator string is found +bool Stream::findUntil(char *target, char *terminator) +{ + return findUntil(target, strlen(target), terminator, strlen(terminator)); +} + +// reads data from the stream until the target string of the given length is found +// search terminated if the terminator string is found +// returns true if target string is found, false if terminated or timed out +bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen) +{ + if (terminator == NULL) { + MultiTarget t[1] = {{target, targetLen, 0}}; + return findMulti(t, 1) == 0 ? true : false; + } else { + MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}}; + return findMulti(t, 2) == 0 ? true : false; + } +} + +// returns the first valid (long) integer value from the current position. +// lookahead determines how parseInt looks ahead in the stream. +// See LookaheadMode enumeration at the top of the file. +// Lookahead is terminated by the first character that is not a valid part of an integer. +// Once parsing commences, 'ignore' will be skipped in the stream. +long Stream::parseInt(LookaheadMode lookahead, char ignore) +{ + bool isNegative = false; + long value = 0; + int c; + + c = peekNextDigit(lookahead, false); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == ignore) + ; // ignore this character + else if(c == '-') + isNegative = true; + else if(c >= '0' && c <= '9') // is c a digit? + value = value * 10 + c - '0'; + read(); // consume the character we got with peek + c = timedPeek(); + } + while( (c >= '0' && c <= '9') || c == ignore ); + + if(isNegative) + value = -value; + return value; +} + +// as parseInt but returns a floating point value +float Stream::parseFloat(LookaheadMode lookahead, char ignore) +{ + bool isNegative = false; + bool isFraction = false; + long value = 0; + int c; + float fraction = 1.0; + + c = peekNextDigit(lookahead, true); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == ignore) + ; // ignore + else if(c == '-') + isNegative = true; + else if (c == '.') + isFraction = true; + else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + if(isFraction) + fraction *= 0.1; + } + read(); // consume the character we got with peek + c = timedPeek(); + } + while( (c >= '0' && c <= '9') || (c == '.' && !isFraction) || c == ignore ); + + if(isNegative) + value = -value; + if(isFraction) + return value * fraction; + else + return value; +} + +// read characters from stream into buffer +// terminates if length characters have been read, or timeout (see setTimeout) +// returns the number of characters placed in the buffer +// the buffer is NOT null terminated. +// +size_t Stream::readBytes(char *buffer, size_t length) +{ + size_t count = 0; + while (count < length) { + int c = timedRead(); + if (c < 0) break; + *buffer++ = (char)c; + count++; + } + return count; +} + + +// as readBytes with terminator character +// terminates if length characters have been read, timeout, or if the terminator character detected +// returns the number of characters placed in the buffer (0 means no valid data found) + +size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) +{ + size_t index = 0; + while (index < length) { + int c = timedRead(); + if (c < 0 || c == terminator) break; + *buffer++ = (char)c; + index++; + } + return index; // return number of characters, not including null terminator +} + +String Stream::readString() +{ + String ret; + int c = timedRead(); + while (c >= 0) + { + ret += (char)c; + c = timedRead(); + } + return ret; +} + +String Stream::readStringUntil(char terminator) +{ + String ret; + int c = timedRead(); + while (c >= 0 && c != terminator) + { + ret += (char)c; + c = timedRead(); + } + return ret; +} + +int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) { + // any zero length target string automatically matches and would make + // a mess of the rest of the algorithm. + for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { + if (t->len <= 0) + return t - targets; + } + + while (1) { + int c = timedRead(); + if (c < 0) + return -1; + + for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { + // the simple case is if we match, deal with that first. + if (c == t->str[t->index]) { + if (++t->index == t->len) + return t - targets; + else + continue; + } + + // if not we need to walk back and see if we could have matched further + // down the stream (ie '1112' doesn't match the first position in '11112' + // but it will match the second position so we can't just reset the current + // index to 0 when we find a mismatch. + if (t->index == 0) + continue; + + int origIndex = t->index; + do { + --t->index; + // first check if current char works against the new current index + if (c != t->str[t->index]) + continue; + + // if it's the only char then we're good, nothing more to check + if (t->index == 0) { + t->index++; + break; + } + + // otherwise we need to check the rest of the found string + int diff = origIndex - t->index; + size_t i; + for (i = 0; i < t->index; ++i) { + if (t->str[i] != t->str[i + diff]) + break; + } + + // if we successfully got through the previous loop then our current + // index is good. + if (i == t->index) { + t->index++; + break; + } + + // otherwise we just try the next index + } while (t->index); + } + } + // unreachable + return -1; +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Tone.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Tone.cpp new file mode 100644 index 0000000..98567c7 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/Tone.cpp @@ -0,0 +1,619 @@ +/* Tone.cpp + + A Tone Generator Library + + Written by Brett Hagman + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Version Modified By Date Comments +------- ----------- -------- -------- +0001 B Hagman 09/08/02 Initial coding +0002 B Hagman 09/08/18 Multiple pins +0003 B Hagman 09/08/18 Moved initialization from constructor to begin() +0004 B Hagman 09/09/26 Fixed problems with ATmega8 +0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers + 09/11/25 Changed pin toggle method to XOR + 09/11/25 Fixed timer0 from being excluded +0006 D Mellis 09/12/29 Replaced objects with functions +0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register +0008 S Kanemoto 12/06/22 Fixed for Leonardo by @maris_HY +0009 J Reucker 15/04/10 Issue #292 Fixed problems with ATmega8 (thanks to Pete62) +0010 jipp 15/04/13 added additional define check #2923 +*************************************************/ + +#include +#include +#include "Arduino.h" +#include "pins_arduino.h" + +#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__) +#define TCCR2A TCCR2 +#define TCCR2B TCCR2 +#define COM2A1 COM21 +#define COM2A0 COM20 +#define OCR2A OCR2 +#define TIMSK2 TIMSK +#define OCIE2A OCIE2 +#define TIMER2_COMPA_vect TIMER2_COMP_vect +#define TIMSK1 TIMSK +#endif + +// timerx_toggle_count: +// > 0 - duration specified +// = 0 - stopped +// < 0 - infinitely (until stop() method called, or new play() called) + +#if !defined(__AVR_ATmega8__) +volatile long timer0_toggle_count; +volatile uint8_t *timer0_pin_port; +volatile uint8_t timer0_pin_mask; +#endif + +volatile long timer1_toggle_count; +volatile uint8_t *timer1_pin_port; +volatile uint8_t timer1_pin_mask; +volatile long timer2_toggle_count; +volatile uint8_t *timer2_pin_port; +volatile uint8_t timer2_pin_mask; + +#if defined(TIMSK3) +volatile long timer3_toggle_count; +volatile uint8_t *timer3_pin_port; +volatile uint8_t timer3_pin_mask; +#endif + +#if defined(TIMSK4) +volatile long timer4_toggle_count; +volatile uint8_t *timer4_pin_port; +volatile uint8_t timer4_pin_mask; +#endif + +#if defined(TIMSK5) +volatile long timer5_toggle_count; +volatile uint8_t *timer5_pin_port; +volatile uint8_t timer5_pin_mask; +#endif + + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER2 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ }; + +#elif defined(__AVR_ATmega8__) + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER2 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ }; + +#elif defined(__AVR_ATmega32U4__) + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER3 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 3 /*, 1 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ }; + +#else + +#define AVAILABLE_TONE_PINS 1 +#define USE_TIMER2 + +// Leave timer 0 to last. +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ }; + +#endif + + + +static int8_t toneBegin(uint8_t _pin) +{ + int8_t _timer = -1; + + // if we're already using the pin, the timer should be configured. + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == _pin) { + return pgm_read_byte(tone_pin_to_timer_PGM + i); + } + } + + // search for an unused timer. + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == 255) { + tone_pins[i] = _pin; + _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); + break; + } + } + + if (_timer != -1) + { + // Set timer specific stuff + // All timers in CTC mode + // 8 bit timers will require changing prescalar values, + // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar + switch (_timer) + { + #if defined(TCCR0A) && defined(TCCR0B) && defined(WGM01) + case 0: + // 8 bit timer + TCCR0A = 0; + TCCR0B = 0; + bitWrite(TCCR0A, WGM01, 1); + bitWrite(TCCR0B, CS00, 1); + timer0_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer0_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12) + case 1: + // 16 bit timer + TCCR1A = 0; + TCCR1B = 0; + bitWrite(TCCR1B, WGM12, 1); + bitWrite(TCCR1B, CS10, 1); + timer1_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer1_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR2A) && defined(TCCR2B) + case 2: + // 8 bit timer + TCCR2A = 0; + TCCR2B = 0; + bitWrite(TCCR2A, WGM21, 1); + bitWrite(TCCR2B, CS20, 1); + timer2_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer2_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3) + case 3: + // 16 bit timer + TCCR3A = 0; + TCCR3B = 0; + bitWrite(TCCR3B, WGM32, 1); + bitWrite(TCCR3B, CS30, 1); + timer3_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer3_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4) + case 4: + // 16 bit timer + TCCR4A = 0; + TCCR4B = 0; + #if defined(WGM42) + bitWrite(TCCR4B, WGM42, 1); + #elif defined(CS43) + // TODO this may not be correct + // atmega32u4 + bitWrite(TCCR4B, CS43, 1); + #endif + bitWrite(TCCR4B, CS40, 1); + timer4_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer4_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + + #if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5) + case 5: + // 16 bit timer + TCCR5A = 0; + TCCR5B = 0; + bitWrite(TCCR5B, WGM52, 1); + bitWrite(TCCR5B, CS50, 1); + timer5_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer5_pin_mask = digitalPinToBitMask(_pin); + break; + #endif + } + } + + return _timer; +} + + + +// frequency (in hertz) and duration (in milliseconds). + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) +{ + uint8_t prescalarbits = 0b001; + long toggle_count = 0; + uint32_t ocr = 0; + int8_t _timer; + + _timer = toneBegin(_pin); + + if (_timer >= 0) + { + // Set the pinMode as OUTPUT + pinMode(_pin, OUTPUT); + + // if we are using an 8 bit timer, scan through prescalars to find the best fit + if (_timer == 0 || _timer == 2) + { + ocr = IDIBUS_F_CPU / frequency / 2 - 1; + prescalarbits = 0b001; // ck/1: same for both timers + if (ocr > 255) + { + ocr = IDIBUS_F_CPU / frequency / 2 / 8 - 1; + prescalarbits = 0b010; // ck/8: same for both timers + + if (_timer == 2 && ocr > 255) + { + ocr = IDIBUS_F_CPU / frequency / 2 / 32 - 1; + prescalarbits = 0b011; + } + + if (ocr > 255) + { + ocr = IDIBUS_F_CPU / frequency / 2 / 64 - 1; + prescalarbits = _timer == 0 ? 0b011 : 0b100; + + if (_timer == 2 && ocr > 255) + { + ocr = IDIBUS_F_CPU / frequency / 2 / 128 - 1; + prescalarbits = 0b101; + } + + if (ocr > 255) + { + ocr = IDIBUS_F_CPU / frequency / 2 / 256 - 1; + prescalarbits = _timer == 0 ? 0b100 : 0b110; + if (ocr > 255) + { + // can't do any better than /1024 + ocr = IDIBUS_F_CPU / frequency / 2 / 1024 - 1; + prescalarbits = _timer == 0 ? 0b101 : 0b111; + } + } + } + } + +#if defined(TCCR0B) + if (_timer == 0) + { + TCCR0B = (TCCR0B & 0b11111000) | prescalarbits; + } + else +#endif +#if defined(TCCR2B) + { + TCCR2B = (TCCR2B & 0b11111000) | prescalarbits; + } +#else + { + // dummy place holder to make the above ifdefs work + } +#endif + } + else + { + // two choices for the 16 bit timers: ck/1 or ck/64 + ocr = IDIBUS_F_CPU / frequency / 2 - 1; + + prescalarbits = 0b001; + if (ocr > 0xffff) + { + ocr = IDIBUS_F_CPU / frequency / 2 / 64 - 1; + prescalarbits = 0b011; + } + + if (_timer == 1) + { +#if defined(TCCR1B) + TCCR1B = (TCCR1B & 0b11111000) | prescalarbits; +#endif + } +#if defined(TCCR3B) + else if (_timer == 3) + TCCR3B = (TCCR3B & 0b11111000) | prescalarbits; +#endif +#if defined(TCCR4B) + else if (_timer == 4) + TCCR4B = (TCCR4B & 0b11111000) | prescalarbits; +#endif +#if defined(TCCR5B) + else if (_timer == 5) + TCCR5B = (TCCR5B & 0b11111000) | prescalarbits; +#endif + + } + + + // Calculate the toggle count + if (duration > 0) + { + toggle_count = 2 * frequency * duration / 1000; + } + else + { + toggle_count = -1; + } + + // Set the OCR for the given timer, + // set the toggle count, + // then turn on the interrupts + switch (_timer) + { + +#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A) + case 0: + OCR0A = ocr; + timer0_toggle_count = toggle_count; + bitWrite(TIMSK0, OCIE0A, 1); + break; +#endif + + case 1: +#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A) + OCR1A = ocr; + timer1_toggle_count = toggle_count; + bitWrite(TIMSK1, OCIE1A, 1); +#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A) + // this combination is for at least the ATmega32 + OCR1A = ocr; + timer1_toggle_count = toggle_count; + bitWrite(TIMSK, OCIE1A, 1); +#endif + break; + +#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A) + case 2: + OCR2A = ocr; + timer2_toggle_count = toggle_count; + bitWrite(TIMSK2, OCIE2A, 1); + break; +#endif + +#if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A) + case 3: + OCR3A = ocr; + timer3_toggle_count = toggle_count; + bitWrite(TIMSK3, OCIE3A, 1); + break; +#endif + +#if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A) + case 4: + OCR4A = ocr; + timer4_toggle_count = toggle_count; + bitWrite(TIMSK4, OCIE4A, 1); + break; +#endif + +#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A) + case 5: + OCR5A = ocr; + timer5_toggle_count = toggle_count; + bitWrite(TIMSK5, OCIE5A, 1); + break; +#endif + + } + } +} + + +// XXX: this function only works properly for timer 2 (the only one we use +// currently). for the others, it should end the tone, but won't restore +// proper PWM functionality for the timer. +void disableTimer(uint8_t _timer) +{ + switch (_timer) + { + case 0: + #if defined(TIMSK0) + TIMSK0 = 0; + #elif defined(TIMSK) + TIMSK = 0; // atmega32 + #endif + break; + +#if defined(TIMSK1) && defined(OCIE1A) + case 1: + bitWrite(TIMSK1, OCIE1A, 0); + break; +#endif + + case 2: + #if defined(TIMSK2) && defined(OCIE2A) + bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt + #endif + #if defined(TCCR2A) && defined(WGM20) + TCCR2A = (1 << WGM20); + #endif + #if defined(TCCR2B) && defined(CS22) + TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22); + #endif + #if defined(OCR2A) + OCR2A = 0; + #endif + break; + +#if defined(TIMSK3) && defined(OCIE3A) + case 3: + bitWrite(TIMSK3, OCIE3A, 0); + break; +#endif + +#if defined(TIMSK4) && defined(OCIE4A) + case 4: + bitWrite(TIMSK4, OCIE4A, 0); + break; +#endif + +#if defined(TIMSK5) && defined(OCIE5A) + case 5: + bitWrite(TIMSK5, OCIE5A, 0); + break; +#endif + } +} + + +void noTone(uint8_t _pin) +{ + int8_t _timer = -1; + + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == _pin) { + _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); + tone_pins[i] = 255; + break; + } + } + + disableTimer(_timer); + + digitalWrite(_pin, 0); +} + +#ifdef USE_TIMER0 +ISR(TIMER0_COMPA_vect) +{ + if (timer0_toggle_count != 0) + { + // toggle the pin + *timer0_pin_port ^= timer0_pin_mask; + + if (timer0_toggle_count > 0) + timer0_toggle_count--; + } + else + { + disableTimer(0); + *timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER1 +ISR(TIMER1_COMPA_vect) +{ + if (timer1_toggle_count != 0) + { + // toggle the pin + *timer1_pin_port ^= timer1_pin_mask; + + if (timer1_toggle_count > 0) + timer1_toggle_count--; + } + else + { + disableTimer(1); + *timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER2 +ISR(TIMER2_COMPA_vect) +{ + + if (timer2_toggle_count != 0) + { + // toggle the pin + *timer2_pin_port ^= timer2_pin_mask; + + if (timer2_toggle_count > 0) + timer2_toggle_count--; + } + else + { + // need to call noTone() so that the tone_pins[] entry is reset, so the + // timer gets initialized next time we call tone(). + // XXX: this assumes timer 2 is always the first one used. + noTone(tone_pins[0]); +// disableTimer(2); +// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER3 +ISR(TIMER3_COMPA_vect) +{ + if (timer3_toggle_count != 0) + { + // toggle the pin + *timer3_pin_port ^= timer3_pin_mask; + + if (timer3_toggle_count > 0) + timer3_toggle_count--; + } + else + { + disableTimer(3); + *timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER4 +ISR(TIMER4_COMPA_vect) +{ + if (timer4_toggle_count != 0) + { + // toggle the pin + *timer4_pin_port ^= timer4_pin_mask; + + if (timer4_toggle_count > 0) + timer4_toggle_count--; + } + else + { + disableTimer(4); + *timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop + } +} +#endif + + +#ifdef USE_TIMER5 +ISR(TIMER5_COMPA_vect) +{ + if (timer5_toggle_count != 0) + { + // toggle the pin + *timer5_pin_port ^= timer5_pin_mask; + + if (timer5_toggle_count > 0) + timer5_toggle_count--; + } + else + { + disableTimer(5); + *timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop + } +} +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/USBCore.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/USBCore.cpp new file mode 100644 index 0000000..4104916 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/USBCore.cpp @@ -0,0 +1,863 @@ + + +/* Copyright (c) 2010, Peter Barrett +** Sleep/Wakeup support added by Michael Dreher +** +** Permission to use, copy, modify, and/or distribute this software for +** any purpose with or without fee is hereby granted, provided that the +** above copyright notice and this permission notice appear in all copies. +** +** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR +** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES +** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +** SOFTWARE. +*/ + +#include "USBAPI.h" +#include "PluggableUSB.h" +#include + +#if defined(USBCON) + +/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */ +#define TX_RX_LED_PULSE_MS 100 +volatile u8 TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */ +volatile u8 RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */ + +//================================================================== +//================================================================== + +extern const u16 STRING_LANGUAGE[] PROGMEM; +extern const u8 STRING_PRODUCT[] PROGMEM; +extern const u8 STRING_MANUFACTURER[] PROGMEM; +extern const DeviceDescriptor USB_DeviceDescriptorIAD PROGMEM; + +const u16 STRING_LANGUAGE[2] = { + (3<<8) | (2+2), + 0x0409 // English +}; + +#ifndef USB_PRODUCT +// If no product is provided, use USB IO Board +#define USB_PRODUCT "USB IO Board" +#endif + +const u8 STRING_PRODUCT[] PROGMEM = USB_PRODUCT; + +#if USB_VID == 0x2341 +# if defined(USB_MANUFACTURER) +# undef USB_MANUFACTURER +# endif +# define USB_MANUFACTURER "Arduino LLC" +#elif USB_VID == 0x1b4f +# if defined(USB_MANUFACTURER) +# undef USB_MANUFACTURER +# endif +# define USB_MANUFACTURER "SparkFun" +#elif !defined(USB_MANUFACTURER) +// Fall through to unknown if no manufacturer name was provided in a macro +# define USB_MANUFACTURER "Unknown" +#endif + +const u8 STRING_MANUFACTURER[] PROGMEM = USB_MANUFACTURER; + + +#define DEVICE_CLASS 0x02 + +// DEVICE DESCRIPTOR +const DeviceDescriptor USB_DeviceDescriptorIAD = + D_DEVICE(0xEF,0x02,0x01,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,ISERIAL,1); + +//================================================================== +//================================================================== + +volatile u8 _usbConfiguration = 0; +volatile u8 _usbCurrentStatus = 0; // meaning of bits see usb_20.pdf, Figure 9-4. Information Returned by a GetStatus() Request to a Device +volatile u8 _usbSuspendState = 0; // copy of UDINT to check SUSPI and WAKEUPI bits + +static inline void WaitIN(void) +{ + while (!(UEINTX & (1< len) { + n = len; + } + + { + LockEP lock(ep); + // Frame may have been released by the SOF interrupt handler + if (!ReadWriteAllowed()) + continue; + + len -= n; + if (ep & TRANSFER_ZERO) + { + while (n--) + Send8(0); + } + else if (ep & TRANSFER_PGM) + { + while (n--) + Send8(pgm_read_byte(data++)); + } + else + { + while (n--) + Send8(*data++); + } + + if (sendZlp) { + ReleaseTX(); + sendZlp = false; + } else if (!ReadWriteAllowed()) { // ...release if buffer is full... + ReleaseTX(); + if (len == 0) sendZlp = true; + } else if ((len == 0) && (ep & TRANSFER_RELEASE)) { // ...or if forced with TRANSFER_RELEASE + // XXX: TRANSFER_RELEASE is never used can be removed? + ReleaseTX(); + } + } + } + TXLED1; // light the TX LED + TxLEDPulse = TX_RX_LED_PULSE_MS; + return r; +} + +u8 _initEndpoints[USB_ENDPOINTS] = +{ + 0, // Control Endpoint + + EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM + EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT + EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN + + // Following endpoints are automatically initialized to 0 +}; + +#define EP_SINGLE_64 0x32 // EP0 +#define EP_DOUBLE_64 0x36 // Other endpoints +#define EP_SINGLE_16 0x12 + +static +void InitEP(u8 index, u8 type, u8 size) +{ + UENUM = index; + UECONX = (1< 64){ + recvLength = 64; + } + + // Write data to fit to the end (not the beginning) of the array + WaitOUT(); + Recv((u8*)d + len - length, recvLength); + ClearOUT(); + length -= recvLength; + } + return len; +} + +static u8 SendInterfaces() +{ + u8 interfaces = 0; + + CDC_GetInterface(&interfaces); + +#ifdef PLUGGABLE_USB_ENABLED + PluggableUSB().getInterface(&interfaces); +#endif + + return interfaces; +} + +// Construct a dynamic configuration descriptor +// This really needs dynamic endpoint allocation etc +// TODO +static +bool SendConfiguration(int maxlen) +{ + // Count and measure interfaces + InitControl(0); + u8 interfaces = SendInterfaces(); + ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces); + + // Now send them + InitControl(maxlen); + USB_SendControl(0,&config,sizeof(ConfigDescriptor)); + SendInterfaces(); + return true; +} + +static +bool SendDescriptor(USBSetup& setup) +{ + u8 t = setup.wValueH; + if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) + return SendConfiguration(setup.wLength); + + InitControl(setup.wLength); +#ifdef PLUGGABLE_USB_ENABLED + int ret = PluggableUSB().getDescriptor(setup); + if (ret != 0) { + return (ret > 0 ? true : false); + } +#endif + + const u8* desc_addr = 0; + if (USB_DEVICE_DESCRIPTOR_TYPE == t) + { + desc_addr = (const u8*)&USB_DeviceDescriptorIAD; + } + else if (USB_STRING_DESCRIPTOR_TYPE == t) + { + if (setup.wValueL == 0) { + desc_addr = (const u8*)&STRING_LANGUAGE; + } + else if (setup.wValueL == IPRODUCT) { + return USB_SendStringDescriptor(STRING_PRODUCT, strlen(USB_PRODUCT), TRANSFER_PGM); + } + else if (setup.wValueL == IMANUFACTURER) { + return USB_SendStringDescriptor(STRING_MANUFACTURER, strlen(USB_MANUFACTURER), TRANSFER_PGM); + } + else if (setup.wValueL == ISERIAL) { +#ifdef PLUGGABLE_USB_ENABLED + char name[ISERIAL_MAX_LEN]; + PluggableUSB().getShortName(name); + return USB_SendStringDescriptor((uint8_t*)name, strlen(name), 0); +#endif + } + else + return false; + } + + if (desc_addr == 0) + return false; + u8 desc_length = pgm_read_byte(desc_addr); + + USB_SendControl(TRANSFER_PGM,desc_addr,desc_length); + return true; +} + +// Endpoint 0 interrupt +ISR(USB_COM_vect) +{ + SetEP(0); + if (!ReceivedSetupInt()) + return; + + USBSetup setup; + Recv((u8*)&setup,8); + ClearSetupInt(); + + u8 requestType = setup.bmRequestType; + if (requestType & REQUEST_DEVICETOHOST) + WaitIN(); + else + ClearIN(); + + bool ok = true; + if (REQUEST_STANDARD == (requestType & REQUEST_TYPE)) + { + // Standard Requests + u8 r = setup.bRequest; + u16 wValue = setup.wValueL | (setup.wValueH << 8); + if (GET_STATUS == r) + { + if (requestType == (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_DEVICE)) + { + Send8(_usbCurrentStatus); + Send8(0); + } + else + { + // TODO: handle the HALT state of an endpoint here + // see "Figure 9-6. Information Returned by a GetStatus() Request to an Endpoint" in usb_20.pdf for more information + Send8(0); + Send8(0); + } + } + else if (CLEAR_FEATURE == r) + { + if((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE)) + && (wValue == DEVICE_REMOTE_WAKEUP)) + { + _usbCurrentStatus &= ~FEATURE_REMOTE_WAKEUP_ENABLED; + } + } + else if (SET_FEATURE == r) + { + if((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE)) + && (wValue == DEVICE_REMOTE_WAKEUP)) + { + _usbCurrentStatus |= FEATURE_REMOTE_WAKEUP_ENABLED; + } + } + else if (SET_ADDRESS == r) + { + WaitIN(); + UDADDR = setup.wValueL | (1< +#include +#include +#include +#include + +#include "wiring_private.h" + +static void nothing(void) { +} + +static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = { +#if EXTERNAL_NUM_INTERRUPTS > 8 + #warning There are more than 8 external interrupts. Some callbacks may not be initialized. + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 7 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 6 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 5 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 4 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 3 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 2 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 1 + nothing, +#endif +#if EXTERNAL_NUM_INTERRUPTS > 0 + nothing, +#endif +}; + +void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { + if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { + intFunc[interruptNum] = userFunc; + + // Configure the interrupt mode (trigger on low input, any change, rising + // edge, or falling edge). The mode constants were chosen to correspond + // to the configuration bits in the hardware register, so we simply shift + // the mode into place. + + // Enable the interrupt. + + switch (interruptNum) { +#if defined(__AVR_ATmega32U4__) + // I hate doing this, but the register assignment differs between the 1280/2560 + // and the 32U4. Since avrlib defines registers PCMSK1 and PCMSK2 that aren't + // even present on the 32U4 this is the only way to distinguish between them. + case 0: + EICRA = (EICRA & ~((1<= howbig) { + return howsmall; + } + long diff = howbig - howsmall; + return random(diff) + howsmall; +} + +long map(long x, long in_min, long in_max, long out_min, long out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +unsigned int makeWord(unsigned int w) { return w; } +unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; } diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/WString.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/WString.cpp new file mode 100644 index 0000000..043fda7 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/WString.cpp @@ -0,0 +1,750 @@ +/* + WString.cpp - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... + Copyright (c) 2009-10 Hernando Barragan. All rights reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "WString.h" + +/*********************************************/ +/* Constructors */ +/*********************************************/ + +String::String(const char *cstr) +{ + init(); + if (cstr) copy(cstr, strlen(cstr)); +} + +String::String(const String &value) +{ + init(); + *this = value; +} + +String::String(const __FlashStringHelper *pstr) +{ + init(); + *this = pstr; +} + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +String::String(String &&rval) +{ + init(); + move(rval); +} +String::String(StringSumHelper &&rval) +{ + init(); + move(rval); +} +#endif + +String::String(char c) +{ + init(); + char buf[2]; + buf[0] = c; + buf[1] = 0; + *this = buf; +} + +String::String(unsigned char value, unsigned char base) +{ + init(); + char buf[1 + 8 * sizeof(unsigned char)]; + utoa(value, buf, base); + *this = buf; +} + +String::String(int value, unsigned char base) +{ + init(); + char buf[2 + 8 * sizeof(int)]; + itoa(value, buf, base); + *this = buf; +} + +String::String(unsigned int value, unsigned char base) +{ + init(); + char buf[1 + 8 * sizeof(unsigned int)]; + utoa(value, buf, base); + *this = buf; +} + +String::String(long value, unsigned char base) +{ + init(); + char buf[2 + 8 * sizeof(long)]; + ltoa(value, buf, base); + *this = buf; +} + +String::String(unsigned long value, unsigned char base) +{ + init(); + char buf[1 + 8 * sizeof(unsigned long)]; + ultoa(value, buf, base); + *this = buf; +} + +String::String(float value, unsigned char decimalPlaces) +{ + init(); + char buf[33]; + *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); +} + +String::String(double value, unsigned char decimalPlaces) +{ + init(); + char buf[33]; + *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); +} + +String::~String() +{ + if (buffer) free(buffer); +} + +/*********************************************/ +/* Memory Management */ +/*********************************************/ + +inline void String::init(void) +{ + buffer = NULL; + capacity = 0; + len = 0; +} + +void String::invalidate(void) +{ + if (buffer) free(buffer); + buffer = NULL; + capacity = len = 0; +} + +unsigned char String::reserve(unsigned int size) +{ + if (buffer && capacity >= size) return 1; + if (changeBuffer(size)) { + if (len == 0) buffer[0] = 0; + return 1; + } + return 0; +} + +unsigned char String::changeBuffer(unsigned int maxStrLen) +{ + char *newbuffer = (char *)realloc(buffer, maxStrLen + 1); + if (newbuffer) { + buffer = newbuffer; + capacity = maxStrLen; + return 1; + } + return 0; +} + +/*********************************************/ +/* Copy and Move */ +/*********************************************/ + +String & String::copy(const char *cstr, unsigned int length) +{ + if (!reserve(length)) { + invalidate(); + return *this; + } + len = length; + strcpy(buffer, cstr); + return *this; +} + +String & String::copy(const __FlashStringHelper *pstr, unsigned int length) +{ + if (!reserve(length)) { + invalidate(); + return *this; + } + len = length; + strcpy_P(buffer, (PGM_P)pstr); + return *this; +} + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +void String::move(String &rhs) +{ + if (buffer) { + if (rhs && capacity >= rhs.len) { + strcpy(buffer, rhs.buffer); + len = rhs.len; + rhs.len = 0; + return; + } else { + free(buffer); + } + } + buffer = rhs.buffer; + capacity = rhs.capacity; + len = rhs.len; + rhs.buffer = NULL; + rhs.capacity = 0; + rhs.len = 0; +} +#endif + +String & String::operator = (const String &rhs) +{ + if (this == &rhs) return *this; + + if (rhs.buffer) copy(rhs.buffer, rhs.len); + else invalidate(); + + return *this; +} + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +String & String::operator = (String &&rval) +{ + if (this != &rval) move(rval); + return *this; +} + +String & String::operator = (StringSumHelper &&rval) +{ + if (this != &rval) move(rval); + return *this; +} +#endif + +String & String::operator = (const char *cstr) +{ + if (cstr) copy(cstr, strlen(cstr)); + else invalidate(); + + return *this; +} + +String & String::operator = (const __FlashStringHelper *pstr) +{ + if (pstr) copy(pstr, strlen_P((PGM_P)pstr)); + else invalidate(); + + return *this; +} + +/*********************************************/ +/* concat */ +/*********************************************/ + +unsigned char String::concat(const String &s) +{ + return concat(s.buffer, s.len); +} + +unsigned char String::concat(const char *cstr, unsigned int length) +{ + unsigned int newlen = len + length; + if (!cstr) return 0; + if (length == 0) return 1; + if (!reserve(newlen)) return 0; + strcpy(buffer + len, cstr); + len = newlen; + return 1; +} + +unsigned char String::concat(const char *cstr) +{ + if (!cstr) return 0; + return concat(cstr, strlen(cstr)); +} + +unsigned char String::concat(char c) +{ + char buf[2]; + buf[0] = c; + buf[1] = 0; + return concat(buf, 1); +} + +unsigned char String::concat(unsigned char num) +{ + char buf[1 + 3 * sizeof(unsigned char)]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(int num) +{ + char buf[2 + 3 * sizeof(int)]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned int num) +{ + char buf[1 + 3 * sizeof(unsigned int)]; + utoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(long num) +{ + char buf[2 + 3 * sizeof(long)]; + ltoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned long num) +{ + char buf[1 + 3 * sizeof(unsigned long)]; + ultoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(float num) +{ + char buf[20]; + char* string = dtostrf(num, 4, 2, buf); + return concat(string, strlen(string)); +} + +unsigned char String::concat(double num) +{ + char buf[20]; + char* string = dtostrf(num, 4, 2, buf); + return concat(string, strlen(string)); +} + +unsigned char String::concat(const __FlashStringHelper * str) +{ + if (!str) return 0; + int length = strlen_P((const char *) str); + if (length == 0) return 1; + unsigned int newlen = len + length; + if (!reserve(newlen)) return 0; + strcpy_P(buffer + len, (const char *) str); + len = newlen; + return 1; +} + +/*********************************************/ +/* Concatenate */ +/*********************************************/ + +StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(rhs.buffer, rhs.len)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) +{ + StringSumHelper &a = const_cast(lhs); + if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, char c) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(c)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, int num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, float num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, double num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(rhs)) a.invalidate(); + return a; +} + +/*********************************************/ +/* Comparison */ +/*********************************************/ + +int String::compareTo(const String &s) const +{ + if (!buffer || !s.buffer) { + if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer; + if (buffer && len > 0) return *(unsigned char *)buffer; + return 0; + } + return strcmp(buffer, s.buffer); +} + +unsigned char String::equals(const String &s2) const +{ + return (len == s2.len && compareTo(s2) == 0); +} + +unsigned char String::equals(const char *cstr) const +{ + if (len == 0) return (cstr == NULL || *cstr == 0); + if (cstr == NULL) return buffer[0] == 0; + return strcmp(buffer, cstr) == 0; +} + +unsigned char String::operator<(const String &rhs) const +{ + return compareTo(rhs) < 0; +} + +unsigned char String::operator>(const String &rhs) const +{ + return compareTo(rhs) > 0; +} + +unsigned char String::operator<=(const String &rhs) const +{ + return compareTo(rhs) <= 0; +} + +unsigned char String::operator>=(const String &rhs) const +{ + return compareTo(rhs) >= 0; +} + +unsigned char String::equalsIgnoreCase( const String &s2 ) const +{ + if (this == &s2) return 1; + if (len != s2.len) return 0; + if (len == 0) return 1; + const char *p1 = buffer; + const char *p2 = s2.buffer; + while (*p1) { + if (tolower(*p1++) != tolower(*p2++)) return 0; + } + return 1; +} + +unsigned char String::startsWith( const String &s2 ) const +{ + if (len < s2.len) return 0; + return startsWith(s2, 0); +} + +unsigned char String::startsWith( const String &s2, unsigned int offset ) const +{ + if (offset > len - s2.len || !buffer || !s2.buffer) return 0; + return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0; +} + +unsigned char String::endsWith( const String &s2 ) const +{ + if ( len < s2.len || !buffer || !s2.buffer) return 0; + return strcmp(&buffer[len - s2.len], s2.buffer) == 0; +} + +/*********************************************/ +/* Character Access */ +/*********************************************/ + +char String::charAt(unsigned int loc) const +{ + return operator[](loc); +} + +void String::setCharAt(unsigned int loc, char c) +{ + if (loc < len) buffer[loc] = c; +} + +char & String::operator[](unsigned int index) +{ + static char dummy_writable_char; + if (index >= len || !buffer) { + dummy_writable_char = 0; + return dummy_writable_char; + } + return buffer[index]; +} + +char String::operator[]( unsigned int index ) const +{ + if (index >= len || !buffer) return 0; + return buffer[index]; +} + +void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const +{ + if (!bufsize || !buf) return; + if (index >= len) { + buf[0] = 0; + return; + } + unsigned int n = bufsize - 1; + if (n > len - index) n = len - index; + strncpy((char *)buf, buffer + index, n); + buf[n] = 0; +} + +/*********************************************/ +/* Search */ +/*********************************************/ + +int String::indexOf(char c) const +{ + return indexOf(c, 0); +} + +int String::indexOf( char ch, unsigned int fromIndex ) const +{ + if (fromIndex >= len) return -1; + const char* temp = strchr(buffer + fromIndex, ch); + if (temp == NULL) return -1; + return temp - buffer; +} + +int String::indexOf(const String &s2) const +{ + return indexOf(s2, 0); +} + +int String::indexOf(const String &s2, unsigned int fromIndex) const +{ + if (fromIndex >= len) return -1; + const char *found = strstr(buffer + fromIndex, s2.buffer); + if (found == NULL) return -1; + return found - buffer; +} + +int String::lastIndexOf( char theChar ) const +{ + return lastIndexOf(theChar, len - 1); +} + +int String::lastIndexOf(char ch, unsigned int fromIndex) const +{ + if (fromIndex >= len) return -1; + char tempchar = buffer[fromIndex + 1]; + buffer[fromIndex + 1] = '\0'; + char* temp = strrchr( buffer, ch ); + buffer[fromIndex + 1] = tempchar; + if (temp == NULL) return -1; + return temp - buffer; +} + +int String::lastIndexOf(const String &s2) const +{ + return lastIndexOf(s2, len - s2.len); +} + +int String::lastIndexOf(const String &s2, unsigned int fromIndex) const +{ + if (s2.len == 0 || len == 0 || s2.len > len) return -1; + if (fromIndex >= len) fromIndex = len - 1; + int found = -1; + for (char *p = buffer; p <= buffer + fromIndex; p++) { + p = strstr(p, s2.buffer); + if (!p) break; + if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer; + } + return found; +} + +String String::substring(unsigned int left, unsigned int right) const +{ + if (left > right) { + unsigned int temp = right; + right = left; + left = temp; + } + String out; + if (left >= len) return out; + if (right > len) right = len; + char temp = buffer[right]; // save the replaced character + buffer[right] = '\0'; + out = buffer + left; // pointer arithmetic + buffer[right] = temp; //restore character + return out; +} + +/*********************************************/ +/* Modification */ +/*********************************************/ + +void String::replace(char find, char replace) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + if (*p == find) *p = replace; + } +} + +void String::replace(const String& find, const String& replace) +{ + if (len == 0 || find.len == 0) return; + int diff = replace.len - find.len; + char *readFrom = buffer; + char *foundAt; + if (diff == 0) { + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + memcpy(foundAt, replace.buffer, replace.len); + readFrom = foundAt + replace.len; + } + } else if (diff < 0) { + char *writeTo = buffer; + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + unsigned int n = foundAt - readFrom; + memcpy(writeTo, readFrom, n); + writeTo += n; + memcpy(writeTo, replace.buffer, replace.len); + writeTo += replace.len; + readFrom = foundAt + find.len; + len += diff; + } + strcpy(writeTo, readFrom); + } else { + unsigned int size = len; // compute size needed for result + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + readFrom = foundAt + find.len; + size += diff; + } + if (size == len) return; + if (size > capacity && !changeBuffer(size)) return; // XXX: tell user! + int index = len - 1; + while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) { + readFrom = buffer + index + find.len; + memmove(readFrom + diff, readFrom, len - (readFrom - buffer)); + len += diff; + buffer[len] = 0; + memcpy(buffer + index, replace.buffer, replace.len); + index--; + } + } +} + +void String::remove(unsigned int index){ + // Pass the biggest integer as the count. The remove method + // below will take care of truncating it at the end of the + // string. + remove(index, (unsigned int)-1); +} + +void String::remove(unsigned int index, unsigned int count){ + if (index >= len) { return; } + if (count <= 0) { return; } + if (count > len - index) { count = len - index; } + char *writeTo = buffer + index; + len = len - count; + strncpy(writeTo, buffer + index + count,len - index); + buffer[len] = 0; +} + +void String::toLowerCase(void) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + *p = tolower(*p); + } +} + +void String::toUpperCase(void) +{ + if (!buffer) return; + for (char *p = buffer; *p; p++) { + *p = toupper(*p); + } +} + +void String::trim(void) +{ + if (!buffer || len == 0) return; + char *begin = buffer; + while (isspace(*begin)) begin++; + char *end = buffer + len - 1; + while (isspace(*end) && end >= begin) end--; + len = end + 1 - begin; + if (begin > buffer) memcpy(buffer, begin, len); + buffer[len] = 0; +} + +/*********************************************/ +/* Parsing / Conversion */ +/*********************************************/ + +long String::toInt(void) const +{ + if (buffer) return atol(buffer); + return 0; +} + +float String::toFloat(void) const +{ + return float(toDouble()); +} + +double String::toDouble(void) const +{ + if (buffer) return atof(buffer); + return 0; +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/abi.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/abi.cpp new file mode 100644 index 0000000..8d719b8 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/abi.cpp @@ -0,0 +1,35 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__)); +extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__)); + +void __cxa_pure_virtual(void) { + // We might want to write some diagnostics to uart in this case + //std::terminate(); + abort(); +} + +void __cxa_deleted_virtual(void) { + // We might want to write some diagnostics to uart in this case + //std::terminate(); + abort(); +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/hooks.c b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/hooks.c new file mode 100644 index 0000000..641eabc --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/hooks.c @@ -0,0 +1,31 @@ +/* + Copyright (c) 2012 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * Empty yield() hook. + * + * This function is intended to be used by library writers to build + * libraries or sketches that supports cooperative threads. + * + * Its defined as a weak symbol and it can be redefined to implement a + * real cooperative scheduler. + */ +static void __empty() { + // Empty +} +void yield(void) __attribute__ ((weak, alias("__empty"))); diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/main.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/main.cpp new file mode 100644 index 0000000..434cd40 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/main.cpp @@ -0,0 +1,52 @@ +/* + main.cpp - Main loop for Arduino sketches + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +// Declared weak in Arduino.h to allow user redefinitions. +int atexit(void (* /*func*/ )()) { return 0; } + +// Weak empty variant initialization function. +// May be redefined by variant files. +void initVariant() __attribute__((weak)); +void initVariant() { } + +void setupUSB() __attribute__((weak)); +void setupUSB() { } + +int main(void) +{ + init(); + + initVariant(); + +#if defined(USBCON) + USBDevice.attach(); +#endif + + setup(); + + for (;;) { + loop(); + if (serialEventRun) serialEventRun(); + } + + return 0; +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/new.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/new.cpp new file mode 100644 index 0000000..fc30cf8 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/new.cpp @@ -0,0 +1,41 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +void *operator new(size_t size) { + return malloc(size); +} + +void *operator new[](size_t size) { + return malloc(size); +} + +void * operator new(size_t size, void * ptr) noexcept { + (void)size; + return ptr; +} + +void operator delete(void * ptr) { + free(ptr); +} + +void operator delete[](void * ptr) { + free(ptr); +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring.c b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring.c new file mode 100644 index 0000000..2028fa5 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring.c @@ -0,0 +1,392 @@ +/* + wiring.c - Partial implementation of the Wiring API for the ATmega8. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include "wiring_private.h" + +// the prescaler is set so that timer0 ticks every 64 clock cycles, and the +// the overflow handler is called every 256 ticks. +#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) + +// the whole number of milliseconds per timer0 overflow +#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000) + +// the fractional number of milliseconds per timer0 overflow. we shift right +// by three to fit these numbers into a byte. (for the clock speeds we care +// about - 8 and 16 MHz - this doesn't lose precision.) +#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) +#define FRACT_MAX (1000 >> 3) + +volatile unsigned long timer0_overflow_count = 0; +volatile unsigned long timer0_millis = 0; +static unsigned char timer0_fract = 0; + +#if defined(TIM0_OVF_vect) +ISR(TIM0_OVF_vect) +#else +ISR(TIMER0_OVF_vect) +#endif +{ + // copy these to local variables so they can be stored in registers + // (volatile variables must be read from memory on every access) + unsigned long m = timer0_millis; + unsigned char f = timer0_fract; + + m += MILLIS_INC; + f += FRACT_INC; + if (f >= FRACT_MAX) { + f -= FRACT_MAX; + m += 1; + } + + timer0_fract = f; + timer0_millis = m; + timer0_overflow_count++; +} + +unsigned long millis() +{ + unsigned long m; + uint8_t oldSREG = SREG; + + // disable interrupts while we read timer0_millis or we might get an + // inconsistent value (e.g. in the middle of a write to timer0_millis) + cli(); + m = timer0_millis; + SREG = oldSREG; + + return m; +} + +unsigned long micros() { + unsigned long m; + uint8_t oldSREG = SREG, t; + + cli(); + m = timer0_overflow_count; +#if defined(TCNT0) + t = TCNT0; +#elif defined(TCNT0L) + t = TCNT0L; +#else + #error TIMER 0 not defined +#endif + +#ifdef TIFR0 + if ((TIFR0 & _BV(TOV0)) && (t < 255)) + m++; +#else + if ((TIFR & _BV(TOV0)) && (t < 255)) + m++; +#endif + + SREG = oldSREG; + + return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); +} + +void delay(unsigned long ms) +{ + uint32_t start = micros(); + + while (ms > 0) { + yield(); + while ( ms > 0 && (micros() - start) >= 1000) { + ms--; + start += 1000; + } + } +} + +/* Delay for the given number of microseconds. Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */ +void delayMicroseconds(unsigned int us) +{ + // call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable) + + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); +#if IDIBUS_F_CPU >= 24000000L + // for the 24 MHz clock for the aventurous ones, trying to overclock + + // zero delay fix + if (!us) return; // = 3 cycles, (4 when true) + + // the following loop takes a 1/6 of a microsecond (4 cycles) + // per iteration, so execute it six times for each microsecond of + // delay requested. + us *= 6; // x6 us, = 7 cycles + + // account for the time taken in the preceeding commands. + // we just burned 22 (24) cycles above, remove 5, (5*4=20) + // us is at least 6 so we can substract 5 + us -= 5; //=2 cycles + +#elif IDIBUS_F_CPU >= 20000000L + // for the 20 MHz clock on rare Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call takes 18 (20) cycles, which is 1us + __asm__ __volatile__ ( + "nop" "\n\t" + "nop" "\n\t" + "nop" "\n\t" + "nop"); //just waiting 4 cycles + if (us <= 1) return; // = 3 cycles, (4 when true) + + // the following loop takes a 1/5 of a microsecond (4 cycles) + // per iteration, so execute it five times for each microsecond of + // delay requested. + us = (us << 2) + us; // x5 us, = 7 cycles + + // account for the time taken in the preceeding commands. + // we just burned 26 (28) cycles above, remove 7, (7*4=28) + // us is at least 10 so we can substract 7 + us -= 7; // 2 cycles + +#elif IDIBUS_F_CPU >= 16000000L + // for the 16 MHz clock on most Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 1us + if (us <= 1) return; // = 3 cycles, (4 when true) + + // the following loop takes 1/4 of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; // x4 us, = 4 cycles + + // account for the time taken in the preceeding commands. + // we just burned 19 (21) cycles above, remove 5, (5*4=20) + // us is at least 8 so we can substract 5 + us -= 5; // = 2 cycles, + +#elif IDIBUS_F_CPU >= 12000000L + // for the 12 MHz clock if somebody is working with USB + + // for a 1 microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 1.5us + if (us <= 1) return; // = 3 cycles, (4 when true) + + // the following loop takes 1/3 of a microsecond (4 cycles) + // per iteration, so execute it three times for each microsecond of + // delay requested. + us = (us << 1) + us; // x3 us, = 5 cycles + + // account for the time taken in the preceeding commands. + // we just burned 20 (22) cycles above, remove 5, (5*4=20) + // us is at least 6 so we can substract 5 + us -= 5; //2 cycles + +#elif IDIBUS_F_CPU >= 8000000L + // for the 8 MHz internal clock + + // for a 1 and 2 microsecond delay, simply return. the overhead + // of the function call takes 14 (16) cycles, which is 2us + if (us <= 2) return; // = 3 cycles, (4 when true) + + // the following loop takes 1/2 of a microsecond (4 cycles) + // per iteration, so execute it twice for each microsecond of + // delay requested. + us <<= 1; //x2 us, = 2 cycles + + // account for the time taken in the preceeding commands. + // we just burned 17 (19) cycles above, remove 4, (4*4=16) + // us is at least 6 so we can substract 4 + us -= 4; // = 2 cycles + +#else + // for the 1 MHz internal clock (default settings for common Atmega microcontrollers) + + // the overhead of the function calls is 14 (16) cycles + if (us <= 16) return; //= 3 cycles, (4 when true) + if (us <= 25) return; //= 3 cycles, (4 when true), (must be at least 25 if we want to substract 22) + + // compensate for the time taken by the preceeding and next commands (about 22 cycles) + us -= 22; // = 2 cycles + // the following loop takes 4 microseconds (4 cycles) + // per iteration, so execute it us/4 times + // us is at least 4, divided by 4 gives us 1 (no zero delay bug) + us >>= 2; // us div 4, = 4 cycles + + +#endif + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); + // return = 4 cycles +} + +void init() +{ + // this needs to be called before setup() or some functions won't + // work there + sei(); + + // on the ATmega168, timer 0 is also used for fast hardware pwm + // (using phase-correct PWM would mean that timer 0 overflowed half as often + // resulting in different millis() behavior on the ATmega8 and ATmega168) +#if defined(TCCR0A) && defined(WGM01) + sbi(TCCR0A, WGM01); + sbi(TCCR0A, WGM00); +#endif + + // set timer 0 prescale factor to 64 +#if defined(__AVR_ATmega128__) + // CPU specific: different values for the ATmega128 + sbi(TCCR0, CS02); +#elif defined(TCCR0) && defined(CS01) && defined(CS00) + // this combination is for the standard atmega8 + sbi(TCCR0, CS01); + sbi(TCCR0, CS00); +#elif defined(TCCR0B) && defined(CS01) && defined(CS00) + // this combination is for the standard 168/328/1280/2560 + sbi(TCCR0B, CS01); + sbi(TCCR0B, CS00); +#elif defined(TCCR0A) && defined(CS01) && defined(CS00) + // this combination is for the __AVR_ATmega645__ series + sbi(TCCR0A, CS01); + sbi(TCCR0A, CS00); +#else + #error Timer 0 prescale factor 64 not set correctly +#endif + + // enable timer 0 overflow interrupt +#if defined(TIMSK) && defined(TOIE0) + sbi(TIMSK, TOIE0); +#elif defined(TIMSK0) && defined(TOIE0) + sbi(TIMSK0, TOIE0); +#else + #error Timer 0 overflow interrupt not set correctly +#endif + + // timers 1 and 2 are used for phase-correct hardware pwm + // this is better for motors as it ensures an even waveform + // note, however, that fast pwm mode can achieve a frequency of up + // 8 MHz (with a 16 MHz clock) at 50% duty cycle + +#if defined(TCCR1B) && defined(CS11) && defined(CS10) + TCCR1B = 0; + + // set timer 1 prescale factor to 64 + sbi(TCCR1B, CS11); +#if IDIBUS_F_CPU >= 8000000L + sbi(TCCR1B, CS10); +#endif +#elif defined(TCCR1) && defined(CS11) && defined(CS10) + sbi(TCCR1, CS11); +#if IDIBUS_F_CPU >= 8000000L + sbi(TCCR1, CS10); +#endif +#endif + // put timer 1 in 8-bit phase correct pwm mode +#if defined(TCCR1A) && defined(WGM10) + sbi(TCCR1A, WGM10); +#endif + + // set timer 2 prescale factor to 64 +#if defined(TCCR2) && defined(CS22) + sbi(TCCR2, CS22); +#elif defined(TCCR2B) && defined(CS22) + sbi(TCCR2B, CS22); +//#else + // Timer 2 not finished (may not be present on this CPU) +#endif + + // configure timer 2 for phase correct pwm (8-bit) +#if defined(TCCR2) && defined(WGM20) + sbi(TCCR2, WGM20); +#elif defined(TCCR2A) && defined(WGM20) + sbi(TCCR2A, WGM20); +//#else + // Timer 2 not finished (may not be present on this CPU) +#endif + +#if defined(TCCR3B) && defined(CS31) && defined(WGM30) + sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64 + sbi(TCCR3B, CS30); + sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode +#endif + +#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */ + sbi(TCCR4B, CS42); // set timer4 prescale factor to 64 + sbi(TCCR4B, CS41); + sbi(TCCR4B, CS40); + sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode + sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A + sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D +#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */ +#if defined(TCCR4B) && defined(CS41) && defined(WGM40) + sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64 + sbi(TCCR4B, CS40); + sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode +#endif +#endif /* end timer4 block for ATMEGA1280/2560 and similar */ + +#if defined(TCCR5B) && defined(CS51) && defined(WGM50) + sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64 + sbi(TCCR5B, CS50); + sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode +#endif + +#if defined(ADCSRA) + // set a2d prescaler so we are inside the desired 50-200 KHz range. + #if IDIBUS_F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #elif IDIBUS_F_CPU >= 8000000 // 8 MHz / 64 = 125 KHz + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + cbi(ADCSRA, ADPS0); + #elif IDIBUS_F_CPU >= 4000000 // 4 MHz / 32 = 125 KHz + sbi(ADCSRA, ADPS2); + cbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #elif IDIBUS_F_CPU >= 2000000 // 2 MHz / 16 = 125 KHz + sbi(ADCSRA, ADPS2); + cbi(ADCSRA, ADPS1); + cbi(ADCSRA, ADPS0); + #elif IDIBUS_F_CPU >= 1000000 // 1 MHz / 8 = 125 KHz + cbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #else // 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2 + cbi(ADCSRA, ADPS2); + cbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + #endif + // enable a2d conversions + sbi(ADCSRA, ADEN); +#endif + + // the bootloader connects pins 0 and 1 to the USART; disconnect them + // here so they can be used as normal digital i/o; they will be + // reconnected in Serial.begin() +#if defined(UCSRB) + UCSRB = 0; +#elif defined(UCSR0B) + UCSR0B = 0; +#endif +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_analog.c b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_analog.c new file mode 100644 index 0000000..e237d6d --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_analog.c @@ -0,0 +1,294 @@ +/* + wiring_analog.c - analog input and output + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + Modified 28 September 2010 by Mark Sproul +*/ + +#include "wiring_private.h" +#include "pins_arduino.h" + +uint8_t analog_reference = DEFAULT; + +void analogReference(uint8_t mode) +{ + // can't actually set the register here because the default setting + // will connect AVCC and the AREF pin, which would cause a short if + // there's something connected to AREF. + analog_reference = mode; +} + +int analogRead(uint8_t pin) +{ + uint8_t low, high; + +#if defined(analogPinToChannel) +#if defined(__AVR_ATmega32U4__) + if (pin >= 18) pin -= 18; // allow for channel or pin numbers +#endif + pin = analogPinToChannel(pin); +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + if (pin >= 54) pin -= 54; // allow for channel or pin numbers +#elif defined(__AVR_ATmega32U4__) + if (pin >= 18) pin -= 18; // allow for channel or pin numbers +#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) + if (pin >= 24) pin -= 24; // allow for channel or pin numbers +#else + if (pin >= 14) pin -= 14; // allow for channel or pin numbers +#endif + +#if defined(ADCSRB) && defined(MUX5) + // the MUX5 bit of ADCSRB selects whether we're reading from channels + // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). + ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); +#endif + + // set the analog reference (high two bits of ADMUX) and select the + // channel (low 4 bits). this also sets ADLAR (left-adjust result) + // to 0 (the default). +#if defined(ADMUX) +#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + ADMUX = (analog_reference << 4) | (pin & 0x07); +#else + ADMUX = (analog_reference << 6) | (pin & 0x07); +#endif +#endif + + // without a delay, we seem to read from the wrong channel + //delay(1); + +#if defined(ADCSRA) && defined(ADCL) + // start the conversion + sbi(ADCSRA, ADSC); + + // ADSC is cleared when the conversion finishes + while (bit_is_set(ADCSRA, ADSC)); + + // we have to read ADCL first; doing so locks both ADCL + // and ADCH until ADCH is read. reading ADCL second would + // cause the results of each conversion to be discarded, + // as ADCL and ADCH would be locked when it completed. + low = ADCL; + high = ADCH; +#else + // we dont have an ADC, return 0 + low = 0; + high = 0; +#endif + + // combine the two bytes + return (high << 8) | low; +} + +// Right now, PWM output only works on the pins with +// hardware support. These are defined in the appropriate +// pins_*.c file. For the rest of the pins, we default +// to digital output. +void analogWrite(uint8_t pin, int val) +{ + // We need to make sure the PWM output is enabled for those pins + // that support it, as we turn it off when digitally reading or + // writing with them. Also, make sure the pin is in output mode + // for consistenty with Wiring, which doesn't require a pinMode + // call for the analog output pins. + pinMode(pin, OUTPUT); + if (val == 0) + { + digitalWrite(pin, LOW); + } + else if (val == 255) + { + digitalWrite(pin, HIGH); + } + else + { + switch(digitalPinToTimer(pin)) + { + // XXX fix needed for atmega8 + #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__) + case TIMER0A: + // connect pwm to pin on timer 0 + sbi(TCCR0, COM00); + OCR0 = val; // set pwm duty + break; + #endif + + #if defined(TCCR0A) && defined(COM0A1) + case TIMER0A: + // connect pwm to pin on timer 0, channel A + sbi(TCCR0A, COM0A1); + OCR0A = val; // set pwm duty + break; + #endif + + #if defined(TCCR0A) && defined(COM0B1) + case TIMER0B: + // connect pwm to pin on timer 0, channel B + sbi(TCCR0A, COM0B1); + OCR0B = val; // set pwm duty + break; + #endif + + #if defined(TCCR1A) && defined(COM1A1) + case TIMER1A: + // connect pwm to pin on timer 1, channel A + sbi(TCCR1A, COM1A1); + OCR1A = val; // set pwm duty + break; + #endif + + #if defined(TCCR1A) && defined(COM1B1) + case TIMER1B: + // connect pwm to pin on timer 1, channel B + sbi(TCCR1A, COM1B1); + OCR1B = val; // set pwm duty + break; + #endif + + #if defined(TCCR1A) && defined(COM1C1) + case TIMER1C: + // connect pwm to pin on timer 1, channel C + sbi(TCCR1A, COM1C1); + OCR1C = val; // set pwm duty + break; + #endif + + #if defined(TCCR2) && defined(COM21) + case TIMER2: + // connect pwm to pin on timer 2 + sbi(TCCR2, COM21); + OCR2 = val; // set pwm duty + break; + #endif + + #if defined(TCCR2A) && defined(COM2A1) + case TIMER2A: + // connect pwm to pin on timer 2, channel A + sbi(TCCR2A, COM2A1); + OCR2A = val; // set pwm duty + break; + #endif + + #if defined(TCCR2A) && defined(COM2B1) + case TIMER2B: + // connect pwm to pin on timer 2, channel B + sbi(TCCR2A, COM2B1); + OCR2B = val; // set pwm duty + break; + #endif + + #if defined(TCCR3A) && defined(COM3A1) + case TIMER3A: + // connect pwm to pin on timer 3, channel A + sbi(TCCR3A, COM3A1); + OCR3A = val; // set pwm duty + break; + #endif + + #if defined(TCCR3A) && defined(COM3B1) + case TIMER3B: + // connect pwm to pin on timer 3, channel B + sbi(TCCR3A, COM3B1); + OCR3B = val; // set pwm duty + break; + #endif + + #if defined(TCCR3A) && defined(COM3C1) + case TIMER3C: + // connect pwm to pin on timer 3, channel C + sbi(TCCR3A, COM3C1); + OCR3C = val; // set pwm duty + break; + #endif + + #if defined(TCCR4A) + case TIMER4A: + //connect pwm to pin on timer 4, channel A + sbi(TCCR4A, COM4A1); + #if defined(COM4A0) // only used on 32U4 + cbi(TCCR4A, COM4A0); + #endif + OCR4A = val; // set pwm duty + break; + #endif + + #if defined(TCCR4A) && defined(COM4B1) + case TIMER4B: + // connect pwm to pin on timer 4, channel B + sbi(TCCR4A, COM4B1); + OCR4B = val; // set pwm duty + break; + #endif + + #if defined(TCCR4A) && defined(COM4C1) + case TIMER4C: + // connect pwm to pin on timer 4, channel C + sbi(TCCR4A, COM4C1); + OCR4C = val; // set pwm duty + break; + #endif + + #if defined(TCCR4C) && defined(COM4D1) + case TIMER4D: + // connect pwm to pin on timer 4, channel D + sbi(TCCR4C, COM4D1); + #if defined(COM4D0) // only used on 32U4 + cbi(TCCR4C, COM4D0); + #endif + OCR4D = val; // set pwm duty + break; + #endif + + + #if defined(TCCR5A) && defined(COM5A1) + case TIMER5A: + // connect pwm to pin on timer 5, channel A + sbi(TCCR5A, COM5A1); + OCR5A = val; // set pwm duty + break; + #endif + + #if defined(TCCR5A) && defined(COM5B1) + case TIMER5B: + // connect pwm to pin on timer 5, channel B + sbi(TCCR5A, COM5B1); + OCR5B = val; // set pwm duty + break; + #endif + + #if defined(TCCR5A) && defined(COM5C1) + case TIMER5C: + // connect pwm to pin on timer 5, channel C + sbi(TCCR5A, COM5C1); + OCR5C = val; // set pwm duty + break; + #endif + + case NOT_ON_TIMER: + default: + if (val < 128) { + digitalWrite(pin, LOW); + } else { + digitalWrite(pin, HIGH); + } + } + } +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_digital.c b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_digital.c new file mode 100644 index 0000000..45412ab --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_digital.c @@ -0,0 +1,179 @@ +/* + wiring_digital.c - digital input and output functions + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + Modified 28 September 2010 by Mark Sproul +*/ + +#define ARDUINO_MAIN +#include "wiring_private.h" +#include "pins_arduino.h" + +void pinMode(uint8_t pin, uint8_t mode) +{ + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t *reg, *out; + + if (port == NOT_A_PIN) return; + + // JWS: can I let the optimizer do this? + reg = portModeRegister(port); + out = portOutputRegister(port); + + if (mode == INPUT) { + uint8_t oldSREG = SREG; + cli(); + *reg &= ~bit; + *out &= ~bit; + SREG = oldSREG; + } else if (mode == INPUT_PULLUP) { + uint8_t oldSREG = SREG; + cli(); + *reg &= ~bit; + *out |= bit; + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + *reg |= bit; + SREG = oldSREG; + } +} + +// Forcing this inline keeps the callers from having to push their own stuff +// on the stack. It is a good performance win and only takes 1 more byte per +// user than calling. (It will take more bytes on the 168.) +// +// But shouldn't this be moved into pinMode? Seems silly to check and do on +// each digitalread or write. +// +// Mark Sproul: +// - Removed inline. Save 170 bytes on atmega1280 +// - changed to a switch statment; added 32 bytes but much easier to read and maintain. +// - Added more #ifdefs, now compiles for atmega645 +// +//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline)); +//static inline void turnOffPWM(uint8_t timer) +static void turnOffPWM(uint8_t timer) +{ + switch (timer) + { + #if defined(TCCR1A) && defined(COM1A1) + case TIMER1A: cbi(TCCR1A, COM1A1); break; + #endif + #if defined(TCCR1A) && defined(COM1B1) + case TIMER1B: cbi(TCCR1A, COM1B1); break; + #endif + #if defined(TCCR1A) && defined(COM1C1) + case TIMER1C: cbi(TCCR1A, COM1C1); break; + #endif + + #if defined(TCCR2) && defined(COM21) + case TIMER2: cbi(TCCR2, COM21); break; + #endif + + #if defined(TCCR0A) && defined(COM0A1) + case TIMER0A: cbi(TCCR0A, COM0A1); break; + #endif + + #if defined(TCCR0A) && defined(COM0B1) + case TIMER0B: cbi(TCCR0A, COM0B1); break; + #endif + #if defined(TCCR2A) && defined(COM2A1) + case TIMER2A: cbi(TCCR2A, COM2A1); break; + #endif + #if defined(TCCR2A) && defined(COM2B1) + case TIMER2B: cbi(TCCR2A, COM2B1); break; + #endif + + #if defined(TCCR3A) && defined(COM3A1) + case TIMER3A: cbi(TCCR3A, COM3A1); break; + #endif + #if defined(TCCR3A) && defined(COM3B1) + case TIMER3B: cbi(TCCR3A, COM3B1); break; + #endif + #if defined(TCCR3A) && defined(COM3C1) + case TIMER3C: cbi(TCCR3A, COM3C1); break; + #endif + + #if defined(TCCR4A) && defined(COM4A1) + case TIMER4A: cbi(TCCR4A, COM4A1); break; + #endif + #if defined(TCCR4A) && defined(COM4B1) + case TIMER4B: cbi(TCCR4A, COM4B1); break; + #endif + #if defined(TCCR4A) && defined(COM4C1) + case TIMER4C: cbi(TCCR4A, COM4C1); break; + #endif + #if defined(TCCR4C) && defined(COM4D1) + case TIMER4D: cbi(TCCR4C, COM4D1); break; + #endif + + #if defined(TCCR5A) + case TIMER5A: cbi(TCCR5A, COM5A1); break; + case TIMER5B: cbi(TCCR5A, COM5B1); break; + case TIMER5C: cbi(TCCR5A, COM5C1); break; + #endif + } +} + +void digitalWrite(uint8_t pin, uint8_t val) +{ + uint8_t timer = digitalPinToTimer(pin); + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t *out; + + if (port == NOT_A_PIN) return; + + // If the pin that support PWM output, we need to turn it off + // before doing a digital write. + if (timer != NOT_ON_TIMER) turnOffPWM(timer); + + out = portOutputRegister(port); + + uint8_t oldSREG = SREG; + cli(); + + if (val == LOW) { + *out &= ~bit; + } else { + *out |= bit; + } + + SREG = oldSREG; +} + +int digitalRead(uint8_t pin) +{ + uint8_t timer = digitalPinToTimer(pin); + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + + if (port == NOT_A_PIN) return LOW; + + // If the pin that support PWM output, we need to turn it off + // before getting a digital reading. + if (timer != NOT_ON_TIMER) turnOffPWM(timer); + + if (*portInputRegister(port) & bit) return HIGH; + return LOW; +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_pulse.c b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_pulse.c new file mode 100644 index 0000000..d6e0434 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_pulse.c @@ -0,0 +1,93 @@ +/* + wiring_pulse.c - pulseIn() function + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include "wiring_private.h" +#include "pins_arduino.h" + +/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH + * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds + * to 3 minutes in length, but must be called at least a few dozen microseconds + * before the start of the pulse. + * + * This function performs better with short pulses in noInterrupt() context + */ +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) +{ + // cache the port and bit of the pin in order to speed up the + // pulse width measuring loop and achieve finer resolution. calling + // digitalRead() instead yields much coarser resolution. + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + uint8_t stateMask = (state ? bit : 0); + + // convert the timeout from microseconds to a number of times through + // the initial loop; it takes approximately 16 clock cycles per iteration + unsigned long maxloops = microsecondsToClockCycles(timeout)/16; + + unsigned long width = countPulseASM(portInputRegister(port), bit, stateMask, maxloops); + + // prevent clockCyclesToMicroseconds to return bogus values if countPulseASM timed out + if (width) + return clockCyclesToMicroseconds(width * 16 + 16); + else + return 0; +} + +/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH + * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds + * to 3 minutes in length, but must be called at least a few dozen microseconds + * before the start of the pulse. + * + * ATTENTION: + * this function relies on micros() so cannot be used in noInterrupt() context + */ +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout) +{ + // cache the port and bit of the pin in order to speed up the + // pulse width measuring loop and achieve finer resolution. calling + // digitalRead() instead yields much coarser resolution. + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + uint8_t stateMask = (state ? bit : 0); + + unsigned long startMicros = micros(); + + // wait for any previous pulse to end + while ((*portInputRegister(port) & bit) == stateMask) { + if (micros() - startMicros > timeout) + return 0; + } + + // wait for the pulse to start + while ((*portInputRegister(port) & bit) != stateMask) { + if (micros() - startMicros > timeout) + return 0; + } + + unsigned long start = micros(); + // wait for the pulse to stop + while ((*portInputRegister(port) & bit) == stateMask) { + if (micros() - startMicros > timeout) + return 0; + } + return micros() - start; +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_shift.c b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_shift.c new file mode 100644 index 0000000..a9b3be5 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/ArduinoCore/src/core/wiring_shift.c @@ -0,0 +1,56 @@ +/* + wiring_shift.c - shiftOut() function + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include "wiring_private.h" + +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) { + uint8_t value = 0; + uint8_t i; + + for (i = 0; i < 8; ++i) { + digitalWrite(clockPin, HIGH); + if (bitOrder == LSBFIRST) + value |= digitalRead(dataPin) << i; + else + value |= digitalRead(dataPin) << (7 - i); + digitalWrite(clockPin, LOW); + } + return value; +} + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) +{ + uint8_t i; + + for (i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) { + digitalWrite(dataPin, val & 1); + val >>= 1; + } else { + digitalWrite(dataPin, (val & 128) != 0); + val <<= 1; + } + + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/1xGen_Test.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/1xGen_Test.cpp new file mode 100644 index 0000000..e69de29 diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusCallbackInterface.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusCallbackInterface.h new file mode 100644 index 0000000..8b31dad --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusCallbackInterface.h @@ -0,0 +1,29 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_CALLBACK_INTERFACE_H_ +#define _IDIBUS_CALLBACK_INTERFACE_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusCallbackInterface { + public: + static void USART_Callback_InterruptTX (IdiBusCallbackInterface *inst) { inst->USART_TxInterruptFunc(); } + static void USART_Callback_InterruptRX (IdiBusCallbackInterface *inst) { inst->USART_RxInterruptFunc(); } + static void USART_Callback_InterruptUDRE (IdiBusCallbackInterface *inst) { inst->USART_UdreInterruptFunc(); } + virtual void USART_RxInterruptFunc(void) {} + virtual void USART_TxInterruptFunc(void) {} + virtual void USART_UdreInterruptFunc(void) {} + + static void TIM_Callback_InterruptCOMPA (IdiBusCallbackInterface *inst) { inst->TIM_COMPA_InterruptFunc(); } + static void TIM_Callback_InterruptCOMPB (IdiBusCallbackInterface *inst) { inst->TIM_COMPB_InterruptFunc(); } + static void TIM_Callback_InterruptCOMPC (IdiBusCallbackInterface *inst) { inst->TIM_COMPC_InterruptFunc(); } + static void TIM_Callback_InterruptOVF (IdiBusCallbackInterface *inst) { inst->TIM_OVF_InterruptFunc(); } + virtual void TIM_COMPA_InterruptFunc (void) {} + virtual void TIM_COMPB_InterruptFunc (void) {} + virtual void TIM_COMPC_InterruptFunc (void) {} + virtual void TIM_OVF_InterruptFunc (void) {} + }; + +typedef void (*CallbackTypeFunction)(IdiBusCallbackInterface*); +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_CALLBACK_INTERFACE_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsDisable.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsDisable.h new file mode 100644 index 0000000..e301c62 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsDisable.h @@ -0,0 +1,18 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_INTERRUPTS_DISABLE_H_ +#define _IDIBUS_INTERRUPTS_DISABLE_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_USART0_ISR_DISABLE +//#define IDIBUS_USART1_ISR_DISABLE +//#define IDIBUS_USART2_ISR_DISABLE +#define IDIBUS_USART3_ISR_DISABLE + +#define IDIBUS_TIM0_ISR_DISABLE +//#define IDIBUS_TIM1_ISR_DISABLE +//#define IDIBUS_TIM2_ISR_DISABLE +//#define IDIBUS_TIM3_ISR_DISABLE +//#define IDIBUS_TIM4_ISR_DISABLE +//#define IDIBUS_TIM5_ISR_DISABLE +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_INTERRUPTS_DISABLE_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsList.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsList.cpp new file mode 100644 index 0000000..0b9f7c5 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsList.cpp @@ -0,0 +1,65 @@ +//############################################################################################################################################################################################################# +#include "IdiBusInterruptsList.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +struct IDIBUS_INTERRUPT_LISTENERS_STR InterruptListenersList; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#ifndef IDIBUS_USART0_ISR_DISABLE +ISR(USART0_RX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptRX(InterruptListenersList.USART0_CallbackInstance); } +ISR(USART0_TX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptTX(InterruptListenersList.USART0_CallbackInstance); } +ISR(USART0_UDRE_vect) { IdiBusCallbackInterface::USART_Callback_InterruptUDRE(InterruptListenersList.USART0_CallbackInstance); } +#endif +#ifndef IDIBUS_USART1_ISR_DISABLE +ISR(USART1_RX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptRX(InterruptListenersList.USART1_CallbackInstance); } +ISR(USART1_TX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptTX(InterruptListenersList.USART1_CallbackInstance); } +ISR(USART1_UDRE_vect) { IdiBusCallbackInterface::USART_Callback_InterruptUDRE(InterruptListenersList.USART1_CallbackInstance); } +#endif +#ifndef IDIBUS_USART2_ISR_DISABLE +ISR(USART2_RX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptRX(InterruptListenersList.USART2_CallbackInstance); } +ISR(USART2_TX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptTX(InterruptListenersList.USART2_CallbackInstance); } +ISR(USART2_UDRE_vect) { IdiBusCallbackInterface::USART_Callback_InterruptUDRE(InterruptListenersList.USART2_CallbackInstance); } +#endif +#ifndef IDIBUS_USART3_ISR_DISABLE +ISR(USART3_RX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptRX(InterruptListenersList.USART3_CallbackInstance); } +ISR(USART3_TX_vect) { IdiBusCallbackInterface::USART_Callback_InterruptTX(InterruptListenersList.USART3_CallbackInstance); } +ISR(USART3_UDRE_vect) { IdiBusCallbackInterface::USART_Callback_InterruptUDRE(InterruptListenersList.USART3_CallbackInstance); } +#endif +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#ifndef IDIBUS_TIM0_ISR_DISABLE +ISR(TIMER0_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM0_CallbackInstance); } +ISR(TIMER0_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM0_CallbackInstance); } +ISR(TIMER0_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM0_CallbackInstance); } +#endif +#ifndef IDIBUS_TIM1_ISR_DISABLE +ISR(TIMER1_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM1_CallbackInstance); } +ISR(TIMER1_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM1_CallbackInstance); } +ISR(TIMER1_COMPC_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPC(InterruptListenersList.TIM1_CallbackInstance); } +ISR(TIMER1_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM1_CallbackInstance); } +#endif +#ifndef IDIBUS_TIM2_ISR_DISABLE +ISR(TIMER2_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM2_CallbackInstance); } +ISR(TIMER2_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM2_CallbackInstance); } +ISR(TIMER2_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM2_CallbackInstance); } +#endif +#ifndef IDIBUS_TIM3_ISR_DISABLE +ISR(TIMER3_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM3_CallbackInstance); } +ISR(TIMER3_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM3_CallbackInstance); } +ISR(TIMER3_COMPC_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPC(InterruptListenersList.TIM3_CallbackInstance); } +ISR(TIMER3_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM3_CallbackInstance); } +#endif +#ifndef IDIBUS_TIM4_ISR_DISABLE +ISR(TIMER4_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM4_CallbackInstance); } +ISR(TIMER4_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM4_CallbackInstance); } +ISR(TIMER4_COMPC_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPC(InterruptListenersList.TIM4_CallbackInstance); } +ISR(TIMER4_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM4_CallbackInstance); } +#endif +#ifndef IDIBUS_TIM5_ISR_DISABLE +ISR(TIMER5_COMPA_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPA(InterruptListenersList.TIM5_CallbackInstance); } +ISR(TIMER5_COMPB_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPB(InterruptListenersList.TIM5_CallbackInstance); } +ISR(TIMER5_COMPC_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptCOMPC(InterruptListenersList.TIM5_CallbackInstance); } +ISR(TIMER5_OVF_vect) { IdiBusCallbackInterface::TIM_Callback_InterruptOVF(InterruptListenersList.TIM5_CallbackInstance); } +#endif +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsList.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsList.h new file mode 100644 index 0000000..d660d42 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusComInterrupts/IdiBusInterruptsList.h @@ -0,0 +1,48 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_INTERRUPTS_LIST_H_ +#define _IDIBUS_INTERRUPTS_LIST_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +#include +#include +#include "IdiBusCallbackInterface.h" +#include "IdiBusInterruptsDisable.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +struct IDIBUS_INTERRUPT_LISTENERS_STR { + #ifndef IDIBUS_USART0_ISR_DISABLE + IdiBusCallbackInterface *USART0_CallbackInstance; + #endif + #ifndef IDIBUS_USART1_ISR_DISABLE + IdiBusCallbackInterface *USART1_CallbackInstance; + #endif + #ifndef IDIBUS_USART2_ISR_DISABLE + IdiBusCallbackInterface *USART2_CallbackInstance; + #endif + #ifndef IDIBUS_USART3_ISR_DISABLE + IdiBusCallbackInterface *USART3_CallbackInstance; + #endif + + #ifndef IDIBUS_TIM0_ISR_DISABLE + IdiBusCallbackInterface *TIM0_CallbackInstance; + #endif + #ifndef IDIBUS_TIM1_ISR_DISABLE + IdiBusCallbackInterface *TIM1_CallbackInstance; + #endif + #ifndef IDIBUS_TIM2_ISR_DISABLE + IdiBusCallbackInterface *TIM2_CallbackInstance; + #endif + #ifndef IDIBUS_TIM3_ISR_DISABLE + IdiBusCallbackInterface *TIM3_CallbackInstance; + #endif + #ifndef IDIBUS_TIM4_ISR_DISABLE + IdiBusCallbackInterface *TIM4_CallbackInstance; + #endif + #ifndef IDIBUS_TIM5_ISR_DISABLE + IdiBusCallbackInterface *TIM5_CallbackInstance; + #endif + }; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern struct IDIBUS_INTERRUPT_LISTENERS_STR InterruptListenersList; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //_IDIBUS_INTERRUPTS_LIST_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusDateTime.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusDateTime.cpp new file mode 100644 index 0000000..4685cac --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusDateTime.cpp @@ -0,0 +1,57 @@ +//############################################################################################################################################################################################################# +#include "IdiBusDateTime.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiDateFormat::IdiDateFormat(uint8_t day, uint8_t month, uint8_t century, uint8_t year99) +{ + this->Day = day; + this->Month = month; + this->Century = century; + this->Year99 = year99; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiDateFormat::isValid(void) +{ + if ( (this->Day == 0) || (this->Day > 31) || + (this->Month == 0) || (this->Month > 12) || + (this->Century > 99) || (this->Year99 > 99) ) { return 0; } +return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiDateFormat::getSize(void) { return IDIDATE_FORMAT_LENGTH; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiDateFormat::getBufForMMES(uint8_t *Data) +{ + Data[IDIDATE_FORMAT_DAY_Pos] = this->Day; + Data[IDIDATE_FORMAT_MONTH_Pos] = this->Month; + Data[IDIDATE_FORMAT_CENTURY_Pos] = this->Century; + Data[IDIDATE_FORMAT_YEAR99_Pos] = this->Year99; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +IdiTimeFormat::IdiTimeFormat(uint8_t seconds, uint8_t minutes, uint8_t hours, int8_t timezone) +{ + this->Seconds = seconds; + this->Minutes = minutes; + this->Hours = hours; + this->TimeZone = timezone; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiTimeFormat::isValid(void) +{ + if ( (this->Seconds > 60) || (this->Minutes > 60) || (this->Hours > 23) || + (this->TimeZone < IDITIME_FORMAT_TIMEZONE_MIN) || (this->TimeZone > IDITIME_FORMAT_TIMEZONE_MAX) ) { return 0; } + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiTimeFormat::getSize(void) { return IDITIME_FORMAT_LENGTH; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiTimeFormat::getBufForMMES(uint8_t *Data) +{ + Data[IDITIME_FORMAT_SECONDS_Pos] = this->Seconds; + Data[IDITIME_FORMAT_MINUTES_Pos] = this->Minutes; + Data[IDITIME_FORMAT_HOURS_Pos] = this->Hours; + Data[IDITIME_FORMAT_TIMEZONE_Pos] = (uint8_t)this->TimeZone; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusDateTime.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusDateTime.h new file mode 100644 index 0000000..0bebb1b --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusDateTime.h @@ -0,0 +1,32 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_DATE_TIME_H_ +#define _IDIBUS_DATE_TIME_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiDateFormat { + public: + IdiDateFormat(uint8_t day, uint8_t month, uint8_t century, uint8_t year99); + uint8_t Day; + uint8_t Month; + uint8_t Century; + uint8_t Year99; + uint8_t isValid(void); + uint8_t getSize(void); + void getBufForMMES(uint8_t *Data); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiTimeFormat { + public: + IdiTimeFormat(uint8_t seconds, uint8_t minutes, uint8_t hours, int8_t timezone); + uint8_t Seconds; + uint8_t Minutes; + uint8_t Hours; + int8_t TimeZone; + uint8_t isValid(void); + uint8_t getSize(void); + void getBufForMMES(uint8_t *Data); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_DATE_TIME_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusMes.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusMes.cpp new file mode 100644 index 0000000..af55832 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusMes.cpp @@ -0,0 +1,128 @@ +//############################################################################################################################################################################################################# +#include "IdiBusMes.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMessage::IsGroupAddr(void) { return ( (this->SlAddr >= IDIBUS_GROUP_0_ADDR)&&(this->SlAddr <= IDIBUS_GROUP_15_ADDR) ) ? 1 : 0; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMessage::IsCommand(void) { return ( this->ComFunc >= IDIMMES_COM_START_NUM ) ? 1 : 0; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMessage::IsModuleError(uint8_t ErrCode) { return ((ErrCode >= IDIER_MODULE_NUM_START)&&(ErrCode <= IDIER_MODULE_NUM_END)) ? 1 : 0; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMessage::IsModuleCommand(void) +{ + switch (this->ComFunc) + { + case(IDIMMES_COM_C_Init) : + case(IDIMMES_COM_C_ShtDown) : + case(IDIMMES_COM_C_Freeze) : + case(IDIMMES_COM_C_Resume) : + case(IDIMMES_COM_C_SetAlarmL12) : + case(IDIMMES_COM_C_SetAlarmL) : + case(IDIMMES_COM_C_SyncRead) : + case(IDIMMES_COM_C_SyncDoChnl) : + case(IDIMMES_COM_C_SyncDo) : + case(IDIMMES_COM_C_SyncClear) : + case(IDIMMES_COM_C_SendTimeDate) : + case(IDIMMES_COM_C_MkTimedMaster) : + case(IDIMMES_COM_C_FmwUpd) : + case(IDIMMES_COM_C_EndFmwUpd) : + case(IDIMMES_COM_C_FmwWrite) : + case(IDIMMES_COM_C_ReadDevFullSN_MS) : + case(IDIMMES_COM_C_WriteSnIPv4IPv6) : + case(IDIMMES_COM_C_WriteSnVerifyDates) : + case(IDIMMES_COM_C_WriteSnAES256) : + case(IDIMMES_COM_C_DummyModule) : + case(IDIMMES_COM_C_CheckModuleLongOp) : { return 1; } + default : {} + } + return 0; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +IdiBusMMES::IdiBusMMES (uint8_t SlAddr, uint8_t *TX_DataP, uint16_t TX_DataLength) +{ + this->SlAddr = SlAddr; + this->MMPS.LongMes = 0; + this->MMPS.AlarmMes = 0; + this->MMPS.EncryptedAes = 0; + this->DEV.NUM = 0; + this->DEV.ALLCH = 0; + this->CHNL.ALLSAME = 0; + this->CHNL.NUM = 0; + this->ComFunc = 1; + + this->TxData = TX_DataP; + this->TxDataLength = TX_DataLength; + this->RxData = NULL; + this->RxDataLength = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusMMES::IdiBusMMES (uint8_t SlAddr) +{ + this->SlAddr = SlAddr; + this->MMPS.LongMes = 0; + this->MMPS.AlarmMes = 0; + this->MMPS.EncryptedAes = 0; + this->DEV.NUM = 0; + this->DEV.ALLCH = 0; + this->CHNL.ALLSAME = 0; + this->CHNL.NUM = 0; + this->ComFunc = IDIMMES_COM_C_Dummy; + + this->TxData = NULL; + this->TxDataLength = 0; + this->RxData = NULL; + this->RxDataLength = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMMES::IsValid(void) +{ + if ( (this->ComFunc == 0) || this->IsModuleCommand() || this->IsGroupAddr() ) { return 0; } + return 1; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +IdiBusMMESG::IdiBusMMESG (uint8_t SlAddr, uint8_t *TX_DataP, uint16_t TX_DataLength) +{ + this->SlAddr = SlAddr; + this->MMPS.LongMes = 0; + this->MMPS.AlarmMes = 0; + this->MMPS.EncryptedAes = 0; + this->ComFunc = IDIMMES_COM_C_DummyModule; + + this->TxData = TX_DataP; + this->TxDataLength = TX_DataLength; + this->RxData = NULL; + this->RxDataLength = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusMMESG::IdiBusMMESG (uint8_t SlAddr) +{ + this->SlAddr = SlAddr; + this->MMPS.LongMes = 0; + this->MMPS.AlarmMes = 0; + this->MMPS.EncryptedAes = 0; + this->ComFunc = IDIMMES_COM_C_Dummy; + + this->TxData = NULL; + this->TxDataLength = 0; + this->RxData = NULL; + this->RxDataLength = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusMMESG::IsValid(void) +{ + uint8_t isModuleCommand = this->IsModuleCommand(); + uint8_t isGroupAddress = this->IsGroupAddr(); + + if ( this->ComFunc == IDIMMES_NOT_FAST_FUNC ) { return 0; } + if ( isGroupAddress ) + { + if ( isModuleCommand != 0 ) { return 0; } + } + else if ( isModuleCommand == 0 ) { return 0; } + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusMes.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusMes.h new file mode 100644 index 0000000..2576ccd --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusMes.h @@ -0,0 +1,50 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_MES_H_ +#define _IDIBUS_MES_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusMessage { + public : + uint8_t SlAddr; + struct { + uint8_t LongMes : 1; + uint8_t AlarmMes : 1; + uint8_t EncryptedAes : 1; + } MMPS; + uint8_t ComFunc; + uint8_t *TxData; + uint16_t TxDataLength; + uint8_t *RxData; + uint16_t RxDataLength; + + uint8_t IsGroupAddr(void); + uint8_t IsModuleCommand(void); + uint8_t IsCommand(void); + uint8_t IsModuleError(uint8_t ErrCode); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusMMES : public IdiBusMessage { + public : + IdiBusMMES (uint8_t SlAddr, uint8_t *TX_DataP, uint16_t TX_DataLength); + IdiBusMMES (uint8_t SlAddr); + struct { + uint8_t NUM : 5; + uint8_t ALLCH : 1; + } DEV; + struct { + uint8_t NUM : 7; + uint8_t ALLSAME : 1; + } CHNL; + uint8_t IsValid(void); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusMMESG : public IdiBusMessage { + public : + IdiBusMMESG (uint8_t SlAddr, uint8_t *TX_DataP, uint16_t TX_DataLength); + IdiBusMMESG (uint8_t SlAddr); + uint8_t IsValid(void); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_MES_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerial.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerial.cpp new file mode 100644 index 0000000..6eaa7ff --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerial.cpp @@ -0,0 +1,621 @@ +//############################################################################################################################################################################################################# +#include "IdiBusSerial.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSerial::IdiBusSerial(void) +{ + this->RS485_DIR_GPIO.DDR = (uint8_t*)&this->InitProtectionVar; + this->RS485_DIR_GPIO.PIN = (uint8_t*)&this->InitProtectionVar; + this->RS485_DIR_GPIO.PORT = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S0_Gpio.DDR = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S0_Gpio.PIN = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S0_Gpio.PORT = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S1_Gpio.DDR = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S1_Gpio.PIN = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S1_Gpio.PORT = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S2_Gpio.DDR = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S2_Gpio.PIN = (uint8_t*)&this->InitProtectionVar; + this->BAUDRATE_DIPSW.S2_Gpio.PORT = (uint8_t*)&this->InitProtectionVar; + this->USARTN.UCSRNA = (uint8_t*)&this->InitProtectionVar; + this->USARTN.UCSRNB = (uint8_t*)&this->InitProtectionVar; + this->USARTN.UCSRNC = (uint8_t*)&this->InitProtectionVar; + this->USARTN.UBRRN = (uint16_t*)&this->InitProtectionVar; + this->USARTN.UDRN = (uint8_t*)&this->InitProtectionVar; + this->TIMN.TCCRNA = (uint8_t*)&this->InitProtectionVar; + this->TIMN.TCCRNB = (uint8_t*)&this->InitProtectionVar; + this->TIMN.TIMSKN = (uint8_t*)&this->InitProtectionVar; + this->TIMN.TIFRN = (uint8_t*)&this->InitProtectionVar; + this->TIMN.OCRNA = (uint16_t*)&this->InitProtectionVar; + this->TIMN.OCRNB = (uint16_t*)&this->InitProtectionVar; + this->TIMN.TCNTN = (uint16_t*)&this->InitProtectionVar; + this->InitState = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::Init(IDIBUS_SERIAL_INIT_TYPEDEF *InitT) +{ + if ( (this->GetGpioParamsArduino(InitT->RS485_DIR_PIN, &this->RS485_DIR_GPIO) == 0) || + (this->GetGpioParamsArduino(InitT->BAUDRATE_DIPSW_S0_PIN, &this->BAUDRATE_DIPSW.S0_Gpio) == 0) || + (this->GetGpioParamsArduino(InitT->BAUDRATE_DIPSW_S1_PIN, &this->BAUDRATE_DIPSW.S1_Gpio) == 0) || + (this->GetGpioParamsArduino(InitT->BAUDRATE_DIPSW_S2_PIN, &this->BAUDRATE_DIPSW.S2_Gpio) == 0) ) { return 0; } + + return this->BaseInit(InitT->USART_NUMBER, InitT->TIMER_NUMBER, InitT->CONFIG); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::Init(IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF *InitT) +{ + if ( (this->GetGpioParams(&InitT->RS485_DIR_GPIO, &this->RS485_DIR_GPIO) == 0) || + (this->GetGpioParams(&InitT->BAUDRATE_DIPSW.S0, &this->BAUDRATE_DIPSW.S0_Gpio) == 0) || + (this->GetGpioParams(&InitT->BAUDRATE_DIPSW.S1, &this->BAUDRATE_DIPSW.S1_Gpio) == 0) || + (this->GetGpioParams(&InitT->BAUDRATE_DIPSW.S2, &this->BAUDRATE_DIPSW.S2_Gpio) == 0) ) { return 0; } + + return this->BaseInit(InitT->USART_NUMBER, InitT->TIMER_NUMBER, InitT->CONFIG); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::BaseInit( enum IDIBUS_SERIAL_USARTN_NUMBER USART_NUM, enum IDIBUS_SERIAL_TIMER_NUMBER TIMER_NUM, enum IDIBUS_SERIAL_USARTN_CONFIG CONF) +{ + // Pointers Init + switch (USART_NUM) + { + case (IDIBUS_SERIAL_USART0) : { + #if defined IDIBUS_USART0_ISR_DISABLE + return 0; + #else + this->USARTN.UCSRNA = &(UCSR0A); + this->USARTN.UCSRNB = &(UCSR0B); + this->USARTN.UCSRNC = &(UCSR0C); + this->USARTN.UBRRN = &(UBRR0); + this->USARTN.UDRN = &(UDR0); + InterruptListenersList.USART0_CallbackInstance = this; + #endif + break; } + case (IDIBUS_SERIAL_USART1) : { + #if defined IDIBUS_USART1_ISR_DISABLE + return 0; + #else + this->USARTN.UCSRNA = &(UCSR1A); + this->USARTN.UCSRNB = &(UCSR1B); + this->USARTN.UCSRNC = &(UCSR1C); + this->USARTN.UBRRN = &(UBRR1); + this->USARTN.UDRN = &(UDR1); + InterruptListenersList.USART1_CallbackInstance = this; + #endif + break; } + case (IDIBUS_SERIAL_USART2) : { + #if defined IDIBUS_USART2_ISR_DISABLE + return 0; + #else + this->USARTN.UCSRNA = &(UCSR2A); + this->USARTN.UCSRNB = &(UCSR2B); + this->USARTN.UCSRNC = &(UCSR2C); + this->USARTN.UBRRN = &(UBRR2); + this->USARTN.UDRN = &(UDR2); + InterruptListenersList.USART2_CallbackInstance = this; + #endif + break; } + case (IDIBUS_SERIAL_USART3) : { + #if defined IDIBUS_USART3_ISR_DISABLE + return 0; + #else + this->USARTN.UCSRNA = &(UCSR3A); + this->USARTN.UCSRNB = &(UCSR3B); + this->USARTN.UCSRNC = &(UCSR3C); + this->USARTN.UBRRN = &(UBRR3); + this->USARTN.UDRN = &(UDR3); + InterruptListenersList.USART3_CallbackInstance = this; + #endif + break; } + default : { return 0; } + } + + switch (TIMER_NUM) + { + case (IDIBUS_TIMER_1) : { + #if defined IDIBUS_TIM1_ISR_DISABLE + return 0; + #else + this->TIMN.TCCRNA = &(TCCR1A); + this->TIMN.TCCRNB = &(TCCR1B); + this->TIMN.TIMSKN = &(TIMSK1); + this->TIMN.TIFRN = &(TIFR1); + this->TIMN.OCRNA = &(OCR1A); + this->TIMN.OCRNB = &(OCR1B); + this->TIMN.TCNTN = &(TCNT1); + InterruptListenersList.TIM1_CallbackInstance = this; + #endif + break; } + case (IDIBUS_TIMER_3) : { + #if defined IDIBUS_TIM3_ISR_DISABLE + return 0; + #else + this->TIMN.TCCRNA = &(TCCR3A); + this->TIMN.TCCRNB = &(TCCR3B); + this->TIMN.TIMSKN = &(TIMSK3); + this->TIMN.TIFRN = &(TIFR3); + this->TIMN.OCRNA = &(OCR3A); + this->TIMN.OCRNB = &(OCR3B); + this->TIMN.TCNTN = &(TCNT3); + InterruptListenersList.TIM3_CallbackInstance = this; + #endif + break; } + case (IDIBUS_TIMER_4) : { + #if defined IDIBUS_TIM4_ISR_DISABLE + return 0; + #else + this->TIMN.TCCRNA = &(TCCR4A); + this->TIMN.TCCRNB = &(TCCR4B); + this->TIMN.TIMSKN = &(TIMSK4); + this->TIMN.TIFRN = &(TIFR4); + this->TIMN.OCRNA = &(OCR4A); + this->TIMN.OCRNB = &(OCR4B); + this->TIMN.TCNTN = &(TCNT4); + InterruptListenersList.TIM4_CallbackInstance = this; + #endif + break; } + case (IDIBUS_TIMER_5) : { + #if defined IDIBUS_TIM5_ISR_DISABLE + return 0; + #else + this->TIMN.TCCRNA = &(TCCR5A); + this->TIMN.TCCRNB = &(TCCR5B); + this->TIMN.TIMSKN = &(TIMSK5); + this->TIMN.TIFRN = &(TIFR5); + this->TIMN.OCRNA = &(OCR5A); + this->TIMN.OCRNB = &(OCR5B); + this->TIMN.TCNTN = &(TCNT5); + InterruptListenersList.TIM5_CallbackInstance = this; + #endif + break; } + default : { return 0; } + } + + // GPIO Init + uint8_t SREG_Temp = SREG; + cli(); + *this->RS485_DIR_GPIO.PORT &= ~this->RS485_DIR_GPIO.PIN_MASK; + *this->RS485_DIR_GPIO.DDR |= this->RS485_DIR_GPIO.PIN_MASK; + + *this->BAUDRATE_DIPSW.S0_Gpio.PORT &= ~this->BAUDRATE_DIPSW.S0_Gpio.PIN_MASK; + *this->BAUDRATE_DIPSW.S0_Gpio.DDR &= ~this->BAUDRATE_DIPSW.S0_Gpio.PIN_MASK; + + *this->BAUDRATE_DIPSW.S1_Gpio.PORT &= ~this->BAUDRATE_DIPSW.S1_Gpio.PIN_MASK; + *this->BAUDRATE_DIPSW.S1_Gpio.DDR &= ~this->BAUDRATE_DIPSW.S1_Gpio.PIN_MASK; + + *this->BAUDRATE_DIPSW.S2_Gpio.PORT &= ~this->BAUDRATE_DIPSW.S2_Gpio.PIN_MASK; + *this->BAUDRATE_DIPSW.S2_Gpio.DDR &= ~this->BAUDRATE_DIPSW.S2_Gpio.PIN_MASK; + if ( SREG_Temp & (0x01U << SREG_I) ) { sei(); } + + // USART Init + *this->USARTN.UBRRN = 0; + *this->USARTN.UCSRNA = (1U<USARTN.UCSRNB = 0; + this->BAUDRATE = 0; + switch (CONF) + { + case (IDIBUS_SERIAL_8N1) : { *this->USARTN.UCSRNC = (1U<USARTN.UCSRNC = (1U<USARTN.UCSRNC = (1U<USARTN.UCSRNC = (1U<USARTN.UCSRNC = (1U<USARTN.UCSRNC = (1U<TIMN.TCCRNB = 0; // Counter stop + *this->TIMN.TCCRNA = 0; // Normal Mode + *this->TIMN.TIMSKN = 0; + + this->InitState = 1; + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::SetBaudrate(enum IDIBUS_SERIAL_BAUDRATE Baudrate) +{ + switch ( Baudrate ) + { + case (IDIBUS_BAUDRATE_DSW_CODE_2400B) : { + this->SetBaudrateLL(2400); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_2400B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_2400B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint32_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_9600B) : { + this->SetBaudrateLL(9600); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_9600B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_9600B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint32_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_19200B) : { + this->SetBaudrateLL(19200); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_19200B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_19200B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_115200B) : { + this->SetBaudrateLL(115200); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_115200B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_115200B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_250K) : { + this->SetBaudrateLL(250000); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_250K_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_250K_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_500K) : { + this->SetBaudrateLL(500000); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_500K_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_500K_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_1M) : { + this->SetBaudrateLL(1000000); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_1M_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_1M_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_10M) : { + this->SetBaudrateLL(10000000); + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_10M_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_10M_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + default : { return; } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::UpdateBaudrateFromDipSwitch(void) +{ + uint8_t BaudrateCode = 0; + uint32_t BaudrateCodeValue; + if ( (*this->BAUDRATE_DIPSW.S2_Gpio.PIN & this->BAUDRATE_DIPSW.S2_Gpio.PIN_MASK) != 0 ) { BaudrateCode |= 0x04; } + if ( (*this->BAUDRATE_DIPSW.S1_Gpio.PIN & this->BAUDRATE_DIPSW.S1_Gpio.PIN_MASK) != 0 ) { BaudrateCode |= 0x02; } + if ( (*this->BAUDRATE_DIPSW.S0_Gpio.PIN & this->BAUDRATE_DIPSW.S0_Gpio.PIN_MASK) != 0 ) { BaudrateCode |= 0x01; } + + switch (BaudrateCode) + { + case (IDIBUS_BAUDRATE_DSW_CODE_2400B) : { BaudrateCodeValue = 2400U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_9600B) : { BaudrateCodeValue = 9600U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_19200B) : { BaudrateCodeValue = 19200U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_115200B) : { BaudrateCodeValue = 115200U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_250K) : { BaudrateCodeValue = 250000U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_500K) : { BaudrateCodeValue = 500000U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_1M) : { BaudrateCodeValue = 1000000U; break; } + case (IDIBUS_BAUDRATE_DSW_CODE_10M) : { BaudrateCodeValue = 10000000U; break; } + default : { return; } + } + if ( this->BAUDRATE != BaudrateCodeValue ) + { + this->SetBaudrateLL(BaudrateCodeValue); + switch ( BaudrateCode ) + { + case (IDIBUS_BAUDRATE_DSW_CODE_2400B) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_2400B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_2400B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_9600B) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_9600B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_9600B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_19200B) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_19200B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_19200B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_115200B) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_115200B_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_115200B_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_250K) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_250K_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_250K_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_500K) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_500K_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_500K_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_1M) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_1M_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_1M_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + case (IDIBUS_BAUDRATE_DSW_CODE_10M) : { + this->TimerInterFrameCompValue = (uint16_t)( ((uint64_t)IDIBUS_10M_INTERFRAME_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE ) / 1000000ULL ); + this->TimerTimeoutCompValue = (uint16_t)( ((uint64_t)IDIBUS_10M_MASTER_RESPONSE_TIMEOUT_US * (uint64_t)F_CPU / (uint64_t)IDIBUS_SERIAL_TIMER_PR_VALUE) / 1000000ULL ); + break; } + default : { return; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::SetBaudrateLL(uint32_t Baudrate) +{ + uint16_t UBRR_2X; + if ( ((F_CPU / 8U) % Baudrate) < (Baudrate / 2) ) + { + UBRR_2X = (uint16_t)( ((uint32_t)F_CPU / 8U) / Baudrate ); + if ( UBRR_2X != 0 ) { UBRR_2X--; } + } + else { UBRR_2X = (uint16_t)( ((uint32_t)F_CPU / 16U) / Baudrate ); } // WARNING CHANGED DIVIDER FROM 8 TO 16!!! //(F_CPU / 8U) / Baudrate + 1 - 1 + *this->USARTN.UBRRN = UBRR_2X; + this->BAUDRATE = Baudrate; + if ( this->InitState == 1 ) { this->InitState = 2; } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +void IdiBusSerial::Start(void) +{ + *this->USARTN.UCSRNB = (1U<RS485_DIR_GPIO.PORT |= this->RS485_DIR_GPIO.PIN_MASK; // Dir to Tx + sei(); + this->TransferComplete = 1; // +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::Stop(void) +{ + *this->TIMN.TCCRNB = 0; // Timer Stop + cli(); + *this->RS485_DIR_GPIO.PORT &= ~this->RS485_DIR_GPIO.PIN_MASK; // Dir to RX + sei(); + *this->USARTN.UCSRNB = 0; // USART TX/RX Periph disable + this->TransferComplete = 1; // +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::SendRequestAsync(uint8_t *_TxBuf_, uint16_t _TxBufLength_) +{ + if ( (this->TransferComplete == 0) || (this->InitState != 2) ) { return 0; } + + this->ERROR_STATUS.SumVar = 0; + if ( _TxBufLength_ == 0 ) { this->ERROR_STATUS.BF.TxZerolength = 1; return 0; } + else if ( _TxBufLength_ > IDIBUS_SERIAL_TX_BUF_SIZE ) { this->ERROR_STATUS.BF.TxOverflow = 1; return 0; } + + memcpy(this->TxBuf, _TxBuf_, _TxBufLength_); + this->TransferComplete = 0; + this->RequestType = _IDIBUS_SERIAL_TX_RX_; + + *this->TIMN.OCRNA = this->TimerInterFrameCompValue; + if ( this->TimerTimeoutCompValue > (0xFFFFU - this->TimerInterFrameCompValue) ) + { + *this->TIMN.OCRNB = 0xFFFFU; + this->TimerTimeoutOverflow = (uint16_t)( this->TimerTimeoutCompValue - (0xFFFFU - this->TimerInterFrameCompValue) ); + } + else + { + *this->TIMN.OCRNB = (uint16_t)(this->TimerTimeoutCompValue + this->TimerInterFrameCompValue); + this->TimerTimeoutOverflow = 0; + } + *this->TIMN.TCNTN = 0; + *this->TIMN.TIFRN = (1U << USARTN_TIM_TIFR_OCFA_Pos) | (1U << USARTN_TIM_TIFR_OCFB_Pos); // Interframe and Response timeouts + *this->TIMN.TIMSKN = (1U << USRTN_TIM_TIMSK_OCIEA_Pos) | (1U << USRTN_TIM_TIMSK_OCIEB_Pos); + + this->TxBufCounter = 1; + this->TxBufLength = _TxBufLength_; + this->RxBufCounter = 0; + *this->USARTN.UDRN = this->TxBuf[0]; + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::SendRequestSync(uint8_t *_TxBuf_, uint16_t _TxBufLength_) +{ + if ( this->InitState != 2 ) { return 0; } + while ( this->TransferComplete == 0 ) { } + if ( this->SendRequestAsync(_TxBuf_, _TxBufLength_) == 0 ) { return 0; } + while ( this->TransferComplete == 0 ) { } + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::WriteAsync(uint8_t *_TxBuf_, uint16_t _TxBufLength_) +{ + if ( (this->TransferComplete == 0) || (this->InitState != 2) ) { return 0; } + + this->ERROR_STATUS.SumVar = 0; + if ( _TxBufLength_ == 0 ) { this->ERROR_STATUS.BF.TxZerolength = 1; return 0; } + else if ( _TxBufLength_ > IDIBUS_SERIAL_TX_BUF_SIZE ) { this->ERROR_STATUS.BF.TxOverflow = 1; return 0; } + + this->TransferComplete = 0; + memcpy(this->TxBuf, _TxBuf_, _TxBufLength_); + this->RequestType = _IDIBUS_SERIAL_TX_; + + *this->TIMN.OCRNA = this->TimerInterFrameCompValue; + *this->TIMN.TCNTN = 0; + *this->TIMN.TIFRN = (1U << USARTN_TIM_TIFR_OCFA_Pos) | (1U << USARTN_TIM_TIFR_OCFB_Pos); // Interframe Timeout + *this->TIMN.TIMSKN = (1U << USRTN_TIM_TIMSK_OCIEA_Pos); + + this->TxBufCounter = 1; + this->TxBufLength = _TxBufLength_; + *this->USARTN.UDRN = this->TxBuf[0]; + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::WriteSync(uint8_t *_TxBuf_, uint16_t _TxBufLength_) +{ + if ( this->InitState != 2 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + if ( this->WriteAsync(_TxBuf_, _TxBufLength_) == 0 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + return 1; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t *IdiBusSerial::getTxBufPointer(void) +{ + if ( this->TransferComplete ) { return this->TxBuf; } + else { return NULL; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t *IdiBusSerial::getRxBufPointer (void) +{ + return this->RxBuf; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::SendRequestAsync(uint16_t DataLength) +{ + if ( (this->TransferComplete == 0) || (this->InitState != 2) ) { return 0; } + this->ERROR_STATUS.SumVar = 0; + this->TransferComplete = 0; + this->RequestType = _IDIBUS_SERIAL_TX_RX_; + + *this->TIMN.OCRNA = this->TimerInterFrameCompValue; + if ( this->TimerTimeoutCompValue > (0xFFFFU - this->TimerInterFrameCompValue) ) + { + *this->TIMN.OCRNB = 0xFFFFU; + this->TimerTimeoutOverflow = (uint16_t)( this->TimerTimeoutCompValue - (0xFFFFU - this->TimerInterFrameCompValue) ); + } + else + { + *this->TIMN.OCRNB = (uint16_t)(this->TimerTimeoutCompValue + this->TimerInterFrameCompValue); + this->TimerTimeoutOverflow = 0; + } + *this->TIMN.TCNTN = 0; + *this->TIMN.TIFRN = (1U << USARTN_TIM_TIFR_OCFA_Pos) | (1U << USARTN_TIM_TIFR_OCFB_Pos); // Interframe and Response timeouts + *this->TIMN.TIMSKN = (1U << USRTN_TIM_TIMSK_OCIEA_Pos) | (1U << USRTN_TIM_TIMSK_OCIEB_Pos); + + this->TxBufCounter = 1; + this->TxBufLength = DataLength; + this->RxBufCounter = 0; + *this->USARTN.UDRN = this->TxBuf[0]; + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::SendRequestSync(uint16_t DataLength) +{ + if ( this->InitState != 2 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + if ( this->SendRequestAsync(DataLength) == 0 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::WriteAsync(uint16_t DataLength) +{ + if ( (this->TransferComplete == 0) || (this->InitState != 2) ) { return 0; } + this->ERROR_STATUS.SumVar = 0; + this->TransferComplete = 0; + this->RequestType = _IDIBUS_SERIAL_TX_; + + *this->TIMN.OCRNA = this->TimerInterFrameCompValue; + *this->TIMN.TCNTN = 0; + *this->TIMN.TIFRN = (1U << USARTN_TIM_TIFR_OCFA_Pos) | (1U << USARTN_TIM_TIFR_OCFB_Pos); // Interframe Timeout + *this->TIMN.TIMSKN = (1U << USRTN_TIM_TIMSK_OCIEA_Pos); + + this->TxBufCounter = 1; + this->TxBufLength = DataLength; + *this->USARTN.UDRN = this->TxBuf[0]; + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::WriteSync(uint16_t DataLength) +{ + if ( this->InitState != 2 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + if ( this->WriteAsync(DataLength) == 0 ) { return 0; } + while ( this->TransferComplete == 0 ) {} + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::IsTransferComplete(void) { return this->TransferComplete; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint16_t IdiBusSerial::GetRxBufCounter(void) { return this->RxBufCounter; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IDIBUS_SERIAL_ERROR_STATUS_TYPE IdiBusSerial::GetErrorStatus(void) { return this->ERROR_STATUS; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint32_t IdiBusSerial::GetBaudrate(void) { return this->BAUDRATE; } +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +void IdiBusSerial::USART_RxInterruptFunc (void) +{ + *this->TIMN.TCNTN = 0; + if ( (*this->USARTN.UCSRNA & ( (1U<RxBufCounter < IDIBUS_SERIAL_RX_BUF_SIZE ) { this->RxBuf[this->RxBufCounter++] = *this->USARTN.UDRN; } + else { this->ERROR_STATUS.BF.RxOverflow = 1; (void)*this->USARTN.UDRN; } + } + else { this->ERROR_STATUS.BF.LLComERR = 1; (void)*this->USARTN.UDRN; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::USART_TxInterruptFunc (void) +{ + if ( this->TxBufCounter != this->TxBufLength ) { *this->USARTN.UDRN = this->TxBuf[this->TxBufCounter++]; } + else + { + switch (this->RequestType) + { + case (_IDIBUS_SERIAL_TX_RX_) : { + *this->RS485_DIR_GPIO.PORT &= ~this->RS485_DIR_GPIO.PIN_MASK; + *this->USARTN.UCSRNB |= (1U<TIMN.TCCRNB = IDIBUS_SERIAL_TIMER_PR_REG; //Timer Start + break; } + case (_IDIBUS_SERIAL_TX_) : { + *this->TIMN.TCCRNB = IDIBUS_SERIAL_TIMER_PR_REG; //Timer Start + break; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::TIM_COMPA_InterruptFunc (void) +{ + switch (this->RequestType) + { + case ( _IDIBUS_SERIAL_TX_RX_ ) : { + if ( this->RxBufCounter != 0 ) // Interframe Timeout < Response < Request Timeout + { + *this->TIMN.TCCRNB = 0; // Timer Stop + *this->USARTN.UCSRNB &= ~( (1U<RS485_DIR_GPIO.PORT |= this->RS485_DIR_GPIO.PIN_MASK; // Dir to TX + this->TransferComplete = 1; // Complete + } + break; } + case (_IDIBUS_SERIAL_TX_) : { + *this->TIMN.TCCRNB = 0; // Timer Stop + this->TransferComplete = 1; // Complete + break; } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSerial::TIM_COMPB_InterruptFunc (void) +{ + if ( this->TimerTimeoutOverflow != 0 ) + { + *this->TIMN.OCRNB = this->TimerTimeoutOverflow; + *this->TIMN.TCNTN = 0; + *this->TIMN.TIFRN = (1U << USARTN_TIM_TIFR_OCFB_Pos); + this->TimerTimeoutOverflow = 0; + } + else + { + *this->TIMN.TCCRNB = 0; //Timer Stop + *this->USARTN.UCSRNB &= ~( (1U<RS485_DIR_GPIO.PORT |= this->RS485_DIR_GPIO.PIN_MASK; + this->ERROR_STATUS.BF.TimeoutERR = 1; + this->TransferComplete = 1; + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSerial::GetGpioParams(IDIBUS_SERIAL_GPIO_INIT *InitSTR, IDIBUS_SERIAL_GPIO *gpio) +{ + if ( InitSTR->PIN_NUM > 7 ) { return 0; } + + if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTA ) { gpio->PORT = &PORTA; gpio->DDR = &DDRA; gpio->PIN = &PINA; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTB ) { gpio->PORT = &PORTB; gpio->DDR = &DDRB; gpio->PIN = &PINB; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTC ) { gpio->PORT = &PORTC; gpio->DDR = &DDRC; gpio->PIN = &PINC; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTD ) { gpio->PORT = &PORTD; gpio->DDR = &DDRD; gpio->PIN = &PIND; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTE ) { gpio->PORT = &PORTE; gpio->DDR = &DDRE; gpio->PIN = &PINE; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTF ) { gpio->PORT = &PORTF; gpio->DDR = &DDRF; gpio->PIN = &PINF; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTG ) { gpio->PORT = &PORTG; gpio->DDR = &DDRG; gpio->PIN = &PING; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTH ) { gpio->PORT = &PORTH; gpio->DDR = &DDRH; gpio->PIN = &PINH; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTJ ) { gpio->PORT = &PORTJ; gpio->DDR = &DDRJ; gpio->PIN = &PINJ; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTK ) { gpio->PORT = &PORTK; gpio->DDR = &DDRK; gpio->PIN = &PINK; } + else if ( (uint16_t)InitSTR->PORT == (uint16_t)&PORTL ) { gpio->PORT = &PORTL; gpio->DDR = &DDRL; gpio->PIN = &PINL; } + else { return 0; } + gpio->PIN_MASK = (0x01U << InitSTR->PIN_NUM); + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerial::GetGpioParamsArduino(uint8_t PinNum, IDIBUS_SERIAL_GPIO *gpio) +{ + uint8_t PortCode; + if ( (PinNum >= NUM_DIGITAL_PINS) || ((PortCode = digitalPinToPort(PinNum)) == NOT_A_PIN) ) { return 0; } + gpio->PIN_MASK = digitalPinToBitMask(PinNum); + gpio->PORT = portOutputRegister(PortCode); + gpio->DDR = portModeRegister(PortCode); + gpio->PIN = portInputRegister(PortCode); + return 1; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerial.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerial.h new file mode 100644 index 0000000..d69c074 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerial.h @@ -0,0 +1,123 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_SERIAL_H_ +#define _IDIBUS_SERIAL_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +#include "IdiBusSerialDefs.h" +#include "IdiBusInterruptsList.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_SERIAL_USARTN_NUMBER { + IDIBUS_SERIAL_USART0, + IDIBUS_SERIAL_USART1, + IDIBUS_SERIAL_USART2, + IDIBUS_SERIAL_USART3 + }; +enum IDIBUS_SERIAL_TIMER_NUMBER { + IDIBUS_TIMER_1 = 1, + IDIBUS_TIMER_3 = 3, + IDIBUS_TIMER_4, + IDIBUS_TIMER_5 + }; +enum IDIBUS_SERIAL_USARTN_CONFIG { + IDIBUS_SERIAL_8N1, + IDIBUS_SERIAL_8N2, + IDIBUS_SERIAL_8E1, + IDIBUS_SERIAL_8E2, + IDIBUS_SERIAL_8O1, + IDIBUS_SERIAL_8O2 + }; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + enum IDIBUS_SERIAL_USARTN_NUMBER USART_NUMBER; + enum IDIBUS_SERIAL_TIMER_NUMBER TIMER_NUMBER; + enum IDIBUS_SERIAL_USARTN_CONFIG CONFIG; + uint8_t RS485_DIR_PIN; + uint8_t BAUDRATE_DIPSW_S0_PIN; + uint8_t BAUDRATE_DIPSW_S1_PIN; + uint8_t BAUDRATE_DIPSW_S2_PIN; + } IDIBUS_SERIAL_INIT_TYPEDEF; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + enum IDIBUS_SERIAL_USARTN_NUMBER USART_NUMBER; + enum IDIBUS_SERIAL_TIMER_NUMBER TIMER_NUMBER; + enum IDIBUS_SERIAL_USARTN_CONFIG CONFIG; + IDIBUS_SERIAL_GPIO_INIT RS485_DIR_GPIO; + struct { + IDIBUS_SERIAL_GPIO_INIT S0; + IDIBUS_SERIAL_GPIO_INIT S1; + IDIBUS_SERIAL_GPIO_INIT S2; + } BAUDRATE_DIPSW; + } IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusSerial : public IdiBusCallbackInterface { + + public : + IdiBusSerial(void); + + uint8_t Init(IDIBUS_SERIAL_INIT_TYPEDEF *InitT); + uint8_t Init(IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF *InitT); + void SetBaudrate(enum IDIBUS_SERIAL_BAUDRATE Baudrate); + void UpdateBaudrateFromDipSwitch(void); + + void Start (void); // Hold Line + void Stop (void); // TX/RX disable, Release Line + + uint8_t SendRequestAsync(uint8_t *_TxBuf_, uint16_t _TxBufLength_); + uint8_t SendRequestSync (uint8_t *_TxBuf_, uint16_t _TxBufLength_); + + uint8_t WriteSync (uint8_t *_TxBuf_, uint16_t _TxBufLength_); + uint8_t WriteAsync(uint8_t *_TxBuf_, uint16_t _TxBufLength_); + + uint8_t IsTransferComplete(void); + uint16_t GetRxBufCounter(void); + IDIBUS_SERIAL_ERROR_STATUS_TYPE GetErrorStatus(void); + uint32_t GetBaudrate(void); + + private : + IDIBUS_SERIAL_USART_HW_TYPE USARTN; + IDIBUS_SERIAL_USARTN_16BIT_TIMER TIMN; + + IDIBUS_SERIAL_GPIO RS485_DIR_GPIO; + IDIBUS_SERIAL_BAUDRATE_DIPSW_TYPE BAUDRATE_DIPSW; + uint32_t BAUDRATE; + + uint8_t TxBuf[IDIBUS_SERIAL_TX_BUF_SIZE]; + uint16_t TxBufLength; + uint16_t TxBufCounter; + + uint8_t RxBuf[IDIBUS_SERIAL_RX_BUF_SIZE]; + uint16_t RxBufCounter; + IDIBUS_SERIAL_ERROR_STATUS_TYPE ERROR_STATUS; + + uint16_t TimerInterFrameCompValue; + uint16_t TimerTimeoutCompValue; + uint16_t TimerTimeoutOverflow; + + enum IDIBUS_SERIAL_REQUEST_TYPE RequestType; + volatile uint8_t TransferComplete; + uint16_t InitProtectionVar; + uint8_t InitState; + + // Interrupt Vectors Pointers + virtual void USART_RxInterruptFunc(void) override; + virtual void USART_TxInterruptFunc(void) override; + virtual void TIM_COMPA_InterruptFunc(void) override; + virtual void TIM_COMPB_InterruptFunc(void) override; + + // Routine + uint8_t BaseInit(enum IDIBUS_SERIAL_USARTN_NUMBER USART_NUM, enum IDIBUS_SERIAL_TIMER_NUMBER TIMER_NUM, enum IDIBUS_SERIAL_USARTN_CONFIG CONF); + uint8_t GetGpioParams(IDIBUS_SERIAL_GPIO_INIT *InitSTR, IDIBUS_SERIAL_GPIO *gpio); + uint8_t GetGpioParamsArduino(uint8_t PinNum, IDIBUS_SERIAL_GPIO *gpio); + void SetBaudrateLL(uint32_t Baudrate); + + protected : + uint8_t *getTxBufPointer (void); + uint8_t *getRxBufPointer (void); + uint8_t SendRequestAsync(uint16_t DataLength); + uint8_t SendRequestSync(uint16_t DataLength); + uint8_t WriteAsync(uint16_t DataLength); + uint8_t WriteSync(uint16_t DataLength); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //_IDIBUS_SERIAL_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialDefs.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialDefs.h new file mode 100644 index 0000000..778d4d8 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialDefs.h @@ -0,0 +1,138 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_SERIAL_COMDEFS_H_ +#define _IDIBUS_SERIAL_COMDEFS_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#if defined (__AVR_ATmega2560__) +#define USARTN_UCSRNA_RXC_Pos 7U +#define USARTN_UCSRNA_TXC_Pos 6U +#define USARTN_UCSRNA_UDR_Pos 5U +#define USARTN_UCSRNA_FE_Pos 4U +#define USARTN_UCSRNA_DOR_Pos 3U +#define USARTN_UCSRNA_UPE_Pos 2U +#define USARTN_UCSRNA_U2X_Pos 1U +#define USARTN_UCSRNA_MPCM_Pos 0U + +#define USARTN_UCSRNB_RXCIE_Pos 7U +#define USARTN_UCSRNB_TXCIE_Pos 6U +#define USARTN_UCSRNB_UDRIE_Pos 5U +#define USARTN_UCSRNB_RXEN_Pos 4U +#define USARTN_UCSRNB_TXEN_Pos 3U +#define USARTN_UCSRNB_UCSZ2_Pos 2U +#define USARTN_UCSRNB_RXB8_Pos 1U +#define USARTN_UCSRNB_TXB8_Pos 0U + +#define USARTN_UCSRNC_UMSEL1 7U +#define USARTN_UCSRNC_UMSEL0 6U +#define USARTN_UCSRNC_UPM1 5U +#define USARTN_UCSRNC_UPM0 4U +#define USARTN_UCSRNC_USBS 3U +#define USARTN_UCSRNC_UCSZ1 2U +#define USARTN_UCSRNC_UCSZ0 1U +#define USARTN_UCSRNC_UCPOL 0U + +#define USARTN_TIM_TCCRA_WGMN1_Pos 1U + +#define USARTN_TIM_TCCRB_PR1 1U +#define USARTN_TIM_TCCRB_PR8 2U +#define USARTN_TIM_TCCRB_PR64 3U +#define USARTN_TIM_TCCRB_PR256 4U +#define USARTN_TIM_TCCRB_PR1024 5U + +#define USRTN_TIM_TIMSK_TOIE_Pos 0U +#define USRTN_TIM_TIMSK_OCIEA_Pos 1U +#define USRTN_TIM_TIMSK_OCIEB_Pos 2U +#define USRTN_TIM_TIMSK_OCIEC_Pos 3U + +#define USARTN_TIM_TIFR_TOV_Pos 0U +#define USARTN_TIM_TIFR_OCFA_Pos 1U +#define USARTN_TIM_TIFR_OCFB_Pos 2U +#define USARTN_TIM_TIFR_OCFC_Pos 3U + +#endif //#if defined (__AVR_ATmega2560__) +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_BAUDRATE_DSW_CODE_19200B 0x00 +#define IDIBUS_BAUDRATE_DSW_CODE_500K 0x01 +#define IDIBUS_BAUDRATE_DSW_CODE_2400B 0x02 +#define IDIBUS_BAUDRATE_DSW_CODE_9600B 0x03 +#define IDIBUS_BAUDRATE_DSW_CODE_115200B 0x04 +#define IDIBUS_BAUDRATE_DSW_CODE_250K 0x05 +#define IDIBUS_BAUDRATE_DSW_CODE_1M 0x06 +#define IDIBUS_BAUDRATE_DSW_CODE_10M 0x07 +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_SERIAL_TIMER_PR_REG USARTN_TIM_TCCRB_PR64 + +#if IDIBUS_SERIAL_TIMER_PR_REG == USARTN_TIM_TCCRB_PR1 +#define IDIBUS_SERIAL_TIMER_PR_VALUE 1U +#elif IDIBUS_SERIAL_TIMER_PR_REG == USARTN_TIM_TCCRB_PR8 +#define IDIBUS_SERIAL_TIMER_PR_VALUE 8U +#elif IDIBUS_SERIAL_TIMER_PR_REG == USARTN_TIM_TCCRB_PR64 +#define IDIBUS_SERIAL_TIMER_PR_VALUE 64U +#elif IDIBUS_SERIAL_TIMER_PR_REG == USARTN_TIM_TCCRB_PR256 +#define IDIBUS_SERIAL_TIMER_PR_VALUE 256U +#elif IDIBUS_SERIAL_TIMER_PR_REG == USARTN_TIM_TCCRB_PR1024 +#define IDIBUS_SERIAL_TIMER_PR_VALUE 1024U +#else +#error "Idibus Serial: Incorrect Timer Prescaler value !" +#endif //#if IDIBUS_T_CPU==CPU_ATmega2560 +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_SERIAL_TX_BUF_SIZE IDIMMES_MAX_MES_SIZE +#define IDIBUS_SERIAL_RX_BUF_SIZE IDISMES_MAX_MES_SIZE +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_SERIAL_REQUEST_TYPE { + _IDIBUS_SERIAL_TX_RX_, + _IDIBUS_SERIAL_TX_, + //Alarm + }; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + volatile uint8_t *UCSRNA; + volatile uint8_t *UCSRNB; + volatile uint8_t *UCSRNC; + volatile uint16_t *UBRRN; + volatile uint8_t *UDRN; + } IDIBUS_SERIAL_USART_HW_TYPE; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + volatile uint8_t *TCCRNA; + volatile uint8_t *TCCRNB; + volatile uint8_t *TIMSKN; + volatile uint8_t *TIFRN; + volatile uint16_t *OCRNA; + volatile uint16_t *OCRNB; + volatile uint16_t *TCNTN; + } IDIBUS_SERIAL_USARTN_16BIT_TIMER; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef union { + uint8_t SumVar; + struct { + uint8_t TimeoutERR : 1; + uint8_t TxOverflow : 1; + uint8_t RxOverflow : 1; + uint8_t LLComERR : 1; + uint8_t TxZerolength : 1; + uint8_t Reserved : 3; + } BF; + } IDIBUS_SERIAL_ERROR_STATUS_TYPE; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + uint8_t PIN_MASK; + volatile uint8_t *PORT; + volatile uint8_t *DDR; + volatile uint8_t *PIN; + } IDIBUS_SERIAL_GPIO; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + uint8_t PIN_NUM; + volatile uint8_t *PORT; + } IDIBUS_SERIAL_GPIO_INIT; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct { + IDIBUS_SERIAL_GPIO S0_Gpio; + IDIBUS_SERIAL_GPIO S1_Gpio; + IDIBUS_SERIAL_GPIO S2_Gpio; + } IDIBUS_SERIAL_BAUDRATE_DIPSW_TYPE; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //_IDIBUS_SERIAL_COMDEFS_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialLine.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialLine.cpp new file mode 100644 index 0000000..8d9d6a9 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialLine.cpp @@ -0,0 +1,122 @@ +//############################################################################################################################################################################################################# +#include "IdiBusSerialLine.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSerialLine::IdiBusSerialLine(void) : IdiBusSerial() +{ +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerialLine::sendMMES (IdiBusMMES *MMES) +{ + if ( MMES->IsValid() == 0 ) { return IDIERMST_INVALID_TX_REQUEST_FORMAT; } + + uint8_t *TxMesBuf = this->getTxBufPointer(); + if ( TxMesBuf == NULL ) { return IDIERMST_TX_MES; } + + uint8_t *RxMesBuf = this->getRxBufPointer(); + uint16_t DataPos; + + // Fill Header + TxMesBuf[IDIMMES_ADDR_Pos] = MMES->SlAddr; + TxMesBuf[IDIMMES_MMPS_Pos] = (MMES->MMPS.LongMes << IDIMMES_MMPS_LONG_MES_Pos) | + (IDIMMES_MMPS_MES_TYPE_MMES << IDIMMES_MMPS_MES_TYPE_Pos) | + (0x00U << IDIMMES_MMPS_FAST_FUNC_Pos) | + (MMES->MMPS.AlarmMes << IDIMMES_MMPS_ALARM_FRAME_Pos) | + (MMES->MMPS.EncryptedAes << IDIMMES_MMPS_ENCRYPTED_AES_Pos); + TxMesBuf[IDIMMES_DEV_Pos] = (MMES->DEV.NUM << IDIMMES_DEV_NUM_Pos) | (MMES->DEV.ALLCH << IDIMMES_DEV_ALLCH_Pos); + TxMesBuf[IDIMMES_CHNL_Pos] = (MMES->CHNL.NUM << IDIMMES_CHNL_NUM_Pos) | (MMES->CHNL.ALLSAME << IDIMMES_CHNL_ALLSAME_Pos); + DataPos = IDIMMES_CHNL_Pos + 1; + + // If Not Fast Function add command/function + if ( MMES->ComFunc < 16 ) { TxMesBuf[IDIMMES_MMPS_Pos] |= (MMES->ComFunc << IDIMMES_MMPS_FAST_FUNC_Pos); } + else { TxMesBuf[DataPos++] = MMES->ComFunc; } + + // Fill Data + if ( MMES->TxDataLength != 0 ) { memcpy(&TxMesBuf[DataPos], &MMES->TxData[0], MMES->TxDataLength); } + + // Add CRC + uint16_t CRC = MODBUS_CRC16::CRC16_TF(&TxMesBuf[0], (uint16_t)(DataPos + MMES->TxDataLength)); + TxMesBuf[DataPos + MMES->TxDataLength] = (uint8_t)(CRC >> 8); + TxMesBuf[DataPos + MMES->TxDataLength + 1] = (uint8_t) CRC; + + if ( this->SendRequestSync(DataPos + MMES->TxDataLength + MODBUS_CRC16_SIZE) == 0 ) { return IDIERMST_TX_MES; } + + IDIBUS_SERIAL_ERROR_STATUS_TYPE SerialError = this->GetErrorStatus(); + uint16_t RxMessageLength; + + if ( SerialError.BF.TimeoutERR != 0 ) { return IDIERMST_RCV_TIMEOUT; } + else if ( (SerialError.SumVar != 0) || ((RxMessageLength = this->GetRxBufCounter()) < IDISMES_MIN_MES_SIZE) ) { return IDIERMST_MES_RX_INTEGRITY; } + else + { + uint16_t CRC = MODBUS_CRC16::CRC16_TF( &RxMesBuf[0], (uint16_t)(RxMessageLength-MODBUS_CRC16_SIZE) ); + uint16_t ReceivedCRC = ((uint16_t)RxMesBuf[RxMessageLength-2] << 8) | RxMesBuf[RxMessageLength-1]; + if ( CRC != ReceivedCRC ) { return IDIERMST_CRC; } + else if ( RxMesBuf[IDISMES_ADDR_Pos] != MMES->SlAddr ) { return IDIERMST_INVALID_ADDR_NUM; } + else + { + MMES->RxDataLength = RxMessageLength - (IDISMES_ERROR_Pos + MODBUS_CRC16_SIZE); + MMES->RxData = &RxMesBuf[IDISMES_ERROR_Pos]; + return IDIER_NOPE; + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSerialLine::sendMMESG (IdiBusMMESG *MMESG) +{ + if ( MMESG->IsValid() == 0 ) { return IDIERMST_INVALID_TX_REQUEST_FORMAT ; } + + uint8_t *TxMesBuf = this->getTxBufPointer(); + if ( TxMesBuf == NULL ) { return IDIERMST_TX_MES; } + + uint8_t *RxMesBuf = this->getRxBufPointer(); + uint16_t DataPos; + + // Fill Header + TxMesBuf[IDIMMES_ADDR_Pos] = MMESG->SlAddr; + TxMesBuf[IDIMMES_MMPS_Pos] = (MMESG->MMPS.LongMes << IDIMMES_MMPS_LONG_MES_Pos) | + (IDIMMES_MMPS_MES_TYPE_MMESG << IDIMMES_MMPS_MES_TYPE_Pos) | + (0x00 << IDIMMES_MMPS_FAST_FUNC_Pos) | + (MMESG->MMPS.AlarmMes << IDIMMES_MMPS_ALARM_FRAME_Pos) | + (MMESG->MMPS.EncryptedAes << IDIMMES_MMPS_ENCRYPTED_AES_Pos); + DataPos = IDIMMES_MMPS_Pos + 1; + // If Not Fast Function add command/function + if ( MMESG->ComFunc < 16 ) { TxMesBuf[IDIMMES_MMPS_Pos] |= (MMESG->ComFunc << IDIMMES_MMPS_FAST_FUNC_Pos); } + else { TxMesBuf[DataPos++] = MMESG->ComFunc; } + + // Fill Data + if ( MMESG->TxDataLength != 0 ) { memcpy(&TxMesBuf[DataPos], &MMESG->TxData[0], MMESG->TxDataLength); } + + // Add CRC + uint16_t CRC = MODBUS_CRC16::CRC16_TF(&TxMesBuf[0], (uint16_t)(DataPos + MMESG->TxDataLength)); + TxMesBuf[DataPos + MMESG->TxDataLength] = (uint8_t)(CRC >> 8); + TxMesBuf[DataPos + MMESG->TxDataLength + 1] = (uint8_t) CRC; + + if ( MMESG->IsGroupAddr() != 0 ) + { + if ( this->WriteSync(DataPos + MMESG->TxDataLength + MODBUS_CRC16_SIZE) == 0 ) { return IDIERMST_TX_MES; } + return IDIER_NOPE; + } + else //Module commands + { + if ( this->SendRequestSync(DataPos + MMESG->TxDataLength + MODBUS_CRC16_SIZE) == 0 ) { return IDIERMST_TX_MES; } + + uint16_t RxMessageLength; + IDIBUS_SERIAL_ERROR_STATUS_TYPE SerialError = this->GetErrorStatus(); + + if ( SerialError.BF.TimeoutERR != 0 ) { return IDIERMST_RCV_TIMEOUT; } + else if ( (SerialError.SumVar != 0) || ((RxMessageLength = this->GetRxBufCounter()) < IDISMES_MIN_MES_SIZE) ) { return IDIERMST_TX_MES; } + else + { + uint16_t CRC = MODBUS_CRC16::CRC16_TF( &RxMesBuf[0], (uint16_t)(RxMessageLength-MODBUS_CRC16_SIZE) ); + uint16_t ReceivedCRC = ((uint16_t)RxMesBuf[RxMessageLength-2] << 8) | RxMesBuf[RxMessageLength-1]; + if ( CRC != ReceivedCRC ) { return IDIERMST_CRC; } + else if ( RxMesBuf[IDISMES_ADDR_Pos] != MMESG->SlAddr ) { return IDIERMST_INVALID_ADDR_NUM; } + { + MMESG->RxDataLength = RxMessageLength - (IDISMES_ERROR_Pos + MODBUS_CRC16_SIZE); + MMESG->RxData = &RxMesBuf[IDISMES_ERROR_Pos]; + return IDIER_NOPE; + } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialLine.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialLine.h new file mode 100644 index 0000000..528f335 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSerialLine.h @@ -0,0 +1,17 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_STD_LINE_H_ +#define _IDIBUS_STD_LINE_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +#include "IdiBusSerial.h" +#include "IdiBusMes.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusSerialLine : public IdiBusSerial { + public : + IdiBusSerialLine(); + uint8_t sendMMES (IdiBusMMES *MMES); // return ErrorCode but not look into [data] + uint8_t sendMMESG (IdiBusMMESG *MMESG); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_STD_LINE_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSlave.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSlave.cpp new file mode 100644 index 0000000..5188341 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSlave.cpp @@ -0,0 +1,351 @@ +//############################################################################################################################################################################################################# +#include "IdiBusSlave.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSlave::IdiBusSlave( IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress ) +{ + this->Line = SlaveLine; + this->Address = SlaveAddress; + this->CRC_AVR.CRC_ErrAvrBufCounter = 0; + this->CRC_AVR.CRC_ErrAvrBufPos = 0; + this->CRC_AVR.CRC_ErrAvrBufSum = 0; + this->CRC_MultipleError = 0; + this->ModuleError = IDIER_NOPE; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSlave::IdiBusSlave(void) +{ + this->Line = NULL; + this->Address = 1; + this->CRC_AVR.CRC_ErrAvrBufCounter = 0; + this->CRC_AVR.CRC_ErrAvrBufPos = 0; + this->CRC_AVR.CRC_ErrAvrBufSum = 0; + this->CRC_MultipleError = 0; + this->ModuleError = IDIER_NOPE; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSlave::Init(IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) +{ + this->Line = SlaveLine; + this->Address = SlaveAddress; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::SendRequestMMES(IdiBusMMES *MMES) +{ + if ( this->Line == NULL ) { return IDIERMST_TX_MES; } + uint8_t RequestError = this->Line->sendMMES(MMES); + this->CrcAvrErrorCalc(RequestError); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if ( MMES->IsModuleError(MMES->RxData[0]) ) + { + if ( MMES->RxDataLength != 1 ) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { this->ModuleError = MMES->RxData[0]; return MMES->RxData[0]; } + } + this->ModuleError = IDIER_NOPE; + return IDIER_NOPE; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::SendRequestMMESG(IdiBusMMESG *MMESG) +{ + if ( this->Line == NULL ) { return IDIERMST_TX_MES; } + uint8_t RequestError = this->Line->sendMMESG(MMESG); + this->CrcAvrErrorCalc(RequestError); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if ( MMESG->IsGroupAddr() == 0 ) + { + if ( MMESG->IsModuleError(MMESG->RxData[0]) ) + { + if ( MMESG->RxDataLength != 1 ) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { this->ModuleError = MMESG->RxData[0]; return MMESG->RxData[0]; } + } + } + this->ModuleError = IDIER_NOPE; + return IDIER_NOPE; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::SendModuleSimpleSetCommand(uint8_t Command) +{ + IdiBusMMESG MMESG(this->Address); + MMESG.ComFunc = Command; + uint8_t RequestError = this->SendRequestMMESG(&MMESG); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if (MMESG.RxDataLength != 1) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { return MMESG.RxData[0]; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::SendModuleSimpleSetCommand(uint8_t Command, uint8_t *TxData, uint16_t TxDataLength) +{ + IdiBusMMESG MMESG(this->Address, TxData, TxDataLength); + MMESG.ComFunc = Command; + uint8_t RequestError = this->SendRequestMMESG(&MMESG); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if (MMESG.RxDataLength != 1) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { return MMESG.RxData[0]; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSlave::CrcAvrErrorCalc(uint8_t ErrorCode) +{ + uint8_t ErrorBufCode; + if ( ErrorCode == IDIERMST_CRC ) { ErrorBufCode = 1; } + else { ErrorBufCode = 0; } + + this->CRC_AVR.CRC_ErrAvrBufSum = this->CRC_AVR.CRC_ErrAvrBufSum + ErrorBufCode - this->CRC_AVR.CRC_ErrAvrBuf[this->CRC_AVR.CRC_ErrAvrBufPos]; + this->CRC_AVR.CRC_ErrAvrBuf[this->CRC_AVR.CRC_ErrAvrBufPos] = ErrorBufCode; + if ( this->CRC_AVR.CRC_ErrAvrBufPos == (IDIER_MULTIPLE_CRC_AVRBUF_SIZE - 1) ) { this->CRC_AVR.CRC_ErrAvrBufPos = 0; } + else { this->CRC_AVR.CRC_ErrAvrBufPos++; } + + if ( this->CRC_AVR.CRC_ErrAvrBufCounter < IDIER_MULTIPLE_CRC_AVRBUF_SIZE ) { this->CRC_AVR.CRC_ErrAvrBufCounter++; } + else + { + if ( this->CRC_AVR.CRC_ErrAvrBufSum >= IDIER_MULTIPLE_CRC_AVRBUF_THR ) { this->CRC_MultipleError = 1; } + else { this->CRC_MultipleError = 0; } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::c_Init(void) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_Init); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_Init(uint8_t Group) { return (Group > IDIBUS_GROUP_LAST_NUMBER) ? IDIERMST_INVALID_TX_PARAM : this->SendModuleSimpleSetCommand(IDIMMES_COM_C_Init, &Group, 1); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_ShtDown(void) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_ShtDown); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_Freeze(void) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_Freeze); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_Resume(void) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_Resume); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_DummyModule(void) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_DummyModule); } +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::c_SendTimeDate(IdiTimeFormat Time, IdiDateFormat Date) +{ + if ( (Time.isValid() == 0) || (Date.isValid() == 0) ) { return IDIERMST_INVALID_TX_PARAM; } + uint8_t TxData[IDIMMES_C_DATETIME_LENGTH]; + Time.getBufForMMES(&TxData[IDIMMES_C_DATETIME_TIME_Pos]); + Date.getBufForMMES(&TxData[IDIMMES_C_DATETIME_DATE_Pos]); + return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_SendTimeDate, TxData, IDIMMES_C_DATETIME_LENGTH ); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_ReadDevFullSN_MS(void) +{ + IdiBusMMESG MMESG (this->Address); + MMESG.ComFunc = IDIMMES_COM_C_ReadDevFullSN_MS; + uint8_t RequestError = this->SendRequestMMESG(&MMESG); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if ( MMESG.RxDataLength != (IDISN_FULL_LENGTH - IDISN_VARP_AES256_Length + 2 + 1) ) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else if ( MMESG.RxData[0] != IDIER_NOPE ) { return MMESG.RxData[0]; } + else + { + this->ModuleST.parseSmesDataNoAes(&MMESG.RxData[1]); + return IDIER_NOPE; + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_WriteSnIPv4IPv6(uint32_t IPv4, uint32_t IPv6_B3, uint32_t IPv6_B2, uint32_t IPv6_B1, uint32_t IPv6_B0) +{ + uint8_t TxData[IDISN_VARP_IPv4_Length + IDISN_VARP_IPv6_Length]; + TxData[0] = (uint8_t)(IPv4 >> 24); + TxData[1] = (uint8_t)(IPv4 >> 16); + TxData[2] = (uint8_t)(IPv4 >> 8); + TxData[3] = (uint8_t)(IPv4); + TxData[4] = (uint8_t)(IPv6_B3 >> 24); + TxData[5] = (uint8_t)(IPv6_B3 >> 16); + TxData[6] = (uint8_t)(IPv6_B3 >> 8); + TxData[7] = (uint8_t)(IPv6_B3); + TxData[8] = (uint8_t)(IPv6_B2 >> 24); + TxData[9] = (uint8_t)(IPv6_B2 >> 16); + TxData[10] = (uint8_t)(IPv6_B2 >> 8); + TxData[11] = (uint8_t)(IPv6_B2); + TxData[12] = (uint8_t)(IPv6_B1 >> 24); + TxData[13] = (uint8_t)(IPv6_B1 >> 16); + TxData[14] = (uint8_t)(IPv6_B1 >> 8); + TxData[15] = (uint8_t)(IPv6_B1); + TxData[16] = (uint8_t)(IPv6_B0 >> 24); + TxData[17] = (uint8_t)(IPv6_B0 >> 16); + TxData[18] = (uint8_t)(IPv6_B0 >> 8); + TxData[19] = (uint8_t)(IPv6_B0); + uint8_t RequestError = this->SendModuleSimpleSetCommand(IDIMMES_COM_C_WriteSnIPv4IPv6, TxData, IDISN_VARP_IPv4_Length + IDISN_VARP_IPv6_Length ); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else + { + memcpy(this->ModuleST.SN.VAR.IPv4, &TxData[0], IDISN_VARP_IPv4_Length); + memcpy(this->ModuleST.SN.VAR.IPv6, &TxData[4], IDISN_VARP_IPv6_Length); + return IDIER_NOPE; + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_WriteSnVerifyDates(IdiDateFormat VDate, IdiDateFormat VEXPDate) +{ + if ( (VDate.isValid() == 0) || (VEXPDate.isValid() == 0) ) { return IDIERMST_INVALID_TX_PARAM; } + uint8_t TxData[IDIDATE_FORMAT_LENGTH * 2]; + VDate.getBufForMMES(&TxData[0]); + VEXPDate.getBufForMMES(&TxData[IDIDATE_FORMAT_LENGTH]); + uint8_t RequestError = this->SendModuleSimpleSetCommand(IDIMMES_COM_C_WriteSnVerifyDates, TxData, IDIDATE_FORMAT_LENGTH * 2 ); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else + { + this->ModuleST.SN.VAR.VerifDate = VDate; + this->ModuleST.SN.VAR.VerifExpDate = VEXPDate; + return IDIER_NOPE; + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_WriteSnAES256(uint8_t *AES256_key) { return this->SendModuleSimpleSetCommand(IDIMMES_COM_C_WriteSnAES256, AES256_key, IDISN_VARP_AES256_Length); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_CheckModuleLongOp(void) +{ + IdiBusMMESG MMESG (this->Address); + MMESG.ComFunc = IDIMMES_COM_C_CheckModuleLongOp; + uint8_t RequestError = this->SendRequestMMESG(&MMESG); + if ( RequestError != IDIER_NOPE ) { return RequestError; } + else if ( MMESG.RxDataLength != (IDILONGOP_MES_DATA_LENGTH + 1) ) { return IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else if ( MMESG.RxData[0] != IDIER_NOPE ) { return MMESG.RxData[0]; } + else + { + uint8_t DataPos = 1; + this->ModuleLongOpData.State = MMESG.RxData[DataPos + IDILONGOP_STATE_Pos]; + this->ModuleLongOpData.Timeout = ((uint32_t)MMESG.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 0] << 24) | + ((uint32_t)MMESG.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 1] << 16) | + ((uint32_t)MMESG.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 2] << 8 ) | + ((uint32_t)MMESG.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 3] ); + return IDIER_NOPE; + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::c_Dummy(uint8_t Device, uint8_t Channel) +{ + IdiBusDevice *DEV; + IdiBusChannel *CHNL; + if ( (DEV = this->getDevice(Device)) == NULL ) { return IDIERMST_INVALID_DEV_NUM; } + if ( (CHNL = DEV->getChannel(Channel)) == NULL ) { return IDIERMST_INVALID_CHN_NUM; } + + IdiBusMMES MMES(this->Address); + MMES.ComFunc = IDIMMES_COM_C_Dummy; + MMES.DEV.NUM = Device; + MMES.CHNL.NUM = Channel; + + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { CHNL->MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { CHNL->MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { CHNL->MMES_Error = MMES.RxData[0]; } + return CHNL->MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_AssignGroup(uint8_t Device, uint8_t Channel, uint8_t Group) +{ + IdiBusDevice *DEV; + IdiBusChannel *CHNL; + if ( (DEV = this->getDevice(Device)) == NULL ) { return IDIERMST_INVALID_DEV_NUM; } + if ( (CHNL = DEV->getChannel(Channel)) == NULL ) { return IDIERMST_INVALID_CHN_NUM; } + if ( Group > IDIBUS_GROUP_LAST_NUMBER ) { CHNL->MMES_Error = IDIERMST_INVALID_TX_PARAM; } + else + { + IdiBusMMES MMES(this->Address, &Group, 1); + MMES.ComFunc = IDIMMES_COM_C_AssignGroup; + MMES.DEV.NUM = Device; + MMES.CHNL.NUM = Channel; + + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { CHNL->MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { CHNL->MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { CHNL->MMES_Error = MMES.RxData[0]; } + } + return CHNL->MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t IdiBusSlave::c_CheckChannelLongOp(uint8_t Device, uint8_t Channel) +{ + IdiBusDevice *DEV; + IdiBusChannel *CHNL; + if ( (DEV = this->getDevice(Device)) == NULL ) { return IDIERMST_INVALID_DEV_NUM; } + if ( (CHNL = DEV->getChannel(Channel)) == NULL ) { return IDIERMST_INVALID_CHN_NUM; } + + IdiBusMMES MMES(this->Address); + MMES.ComFunc = IDIMMES_COM_C_CheckChannelLongOp; + MMES.DEV.NUM = Device; + MMES.CHNL.NUM = Channel; + + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { CHNL->MMES_Error = RequestError; } + else if ( MMES.RxDataLength != (IDILONGOP_MES_DATA_LENGTH + 1) ) { CHNL->MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else if ( MMES.RxData[0] != IDIER_NOPE ) { CHNL->MMES_Error = MMES.RxData[0]; } + else + { + CHNL->MMES_Error = IDIER_NOPE; + uint8_t DataPos = 1; + CHNL->LONG_OP.State = MMES.RxData[DataPos + IDILONGOP_STATE_Pos]; + CHNL->LONG_OP.Timeout = ((uint32_t)MMES.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 0] << 24) | + ((uint32_t)MMES.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 1] << 16) | + ((uint32_t)MMES.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 2] << 8 ) | + ((uint32_t)MMES.RxData[DataPos + IDILONGOP_REMAIN_TIME_Pos + 3] ); + } + return CHNL->MMES_Error; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBusSlave::getAddress(void) { return this->Address; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBusSlave::setAes256ToSn(uint8_t *AES256_key) { memcpy(this->ModuleST.SN.VAR.AES, AES256_key, IDISN_VARP_AES256_Length); } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusLongOpData IdiBusSlave::getModuleLongOpData(void) { return this->ModuleLongOpData; } +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusLongOpData IdiBusSlave::getChLongOpData(uint8_t Device, uint8_t Channel) +{ + IdiBusDevice *DEV; + IdiBusChannel *CHNL; + if ( ((DEV = this->getDevice(Device)) != NULL) && ((CHNL = DEV->getChannel(Channel)) != NULL) ) + { + return CHNL->LONG_OP; + } + IdiBusLongOpData NewData; + return NewData; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiMasterState IdiBusSlave::getModuleSN(void) { return this->ModuleST; } +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +void IdiMasterState::parseSmesDataNoAes(uint8_t *Data) +{ + this->STATE.B0S.StError = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_ST_ERROR_Pos) & 0x01; + this->STATE.B0S.StState = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_ST_STATE_Pos) & IDISTATUS_B0S_ST_STATE_Msk; + this->STATE.B0S.AesSupported = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_AES_SUPPORTED_Pos) & 0x01; + this->STATE.B0S.AesInstalled = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_AES_INSTALLED_Pos) & 0x01; + this->STATE.B0S.SendAlarmL0 = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_SEND_ALARM_L0_Pos) & 0x01; + this->STATE.B0S.SendAlarmL1 = (Data[IDISTATUS_B0S_Pos] >> IDISTATUS_B0S_SEND_ALARM_L1_Pos) & 0x01; + + this->STATE.B1S.ModuleType = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_MODULE_TYPE_Pos) & IDISTATUS_B1S_MODULE_TYPE_Msk; + this->STATE.B1S.BridgeConnected = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_BRIDGE_CONNECTED_Pos) & 0x01; + this->STATE.B1S.SelfInit = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_SELF_INIT_Pos) & 0x01; + this->STATE.B1S.TimeoutLed = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_TIMEOUT_LED_Pos) & 0x01; + this->STATE.B1S.NoMMESTimeout = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_NO_MMES_TIMEOUT_Pos) & 0x01; + this->STATE.B1S.CatchAlarmL0 = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_CATCH_ALARM_L0_Pos) & 0x01; + this->STATE.B1S.CatchAlarmL1 = (Data[IDISTATUS_B1S_Pos] >> IDISTATUS_B1S_CATCH_ALARM_L1_Pos) & 0x01; + + memcpy(this->SN.FIX.GS1_country, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_GS1_COUNTRY_Pos], IDISN_FIXP_GS1_COUNTRY_Length); + memcpy(this->SN.FIX.GS1_company, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_GS1_COMPANY_Pos], IDISN_FIXP_GS1_COMPANY_Length); + memcpy(this->SN.FIX.ModuleType, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_MODULE_TYPE_Pos], IDISN_FIXP_MODULE_TYPE_Length); + memcpy(this->SN.FIX.HW_rev, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_HW_REV_Pos], IDISN_FIXP_HW_REV_Length); + memcpy(this->SN.FIX.Serial, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_SERIAL_Pos], IDISN_FIXP_SERIAL_Length); + memcpy(this->SN.FIX.MAC, &Data[IDISTATUS_SN_Pos + IDISN_FIXP_MAC_Pos], IDISN_FIXP_MAC_Length); + memcpy(this->SN.VAR.SW_rev, &Data[IDISTATUS_SN_Pos + IDISN_VARP_SW_REV_Pos], IDISN_VARP_SW_REV_Length); + memcpy(this->SN.VAR.IPv4, &Data[IDISTATUS_SN_Pos + IDISN_VARP_IPv4_Pos], IDISN_VARP_IPv4_Length); + memcpy(this->SN.VAR.IPv6, &Data[IDISTATUS_SN_Pos + IDISN_VARP_IPv6_Pos], IDISN_VARP_IPv6_Length); + + uint8_t *VerifDateP = &Data[IDISTATUS_SN_Pos + IDISN_VARP_VERIF_DATE_Pos]; + uint8_t *VerifExpDateP = &Data[IDISTATUS_SN_Pos + IDISN_VARP_EXPIR_DATE_Pos]; + IdiDateFormat verifDate(VerifDateP[0], VerifDateP[1], VerifDateP[2], VerifDateP[3]); + IdiDateFormat verifExpDate(VerifExpDateP[0], VerifExpDateP[1], VerifExpDateP[2], VerifExpDateP[3]); + this->SN.VAR.VerifDate = verifDate; + this->SN.VAR.VerifExpDate = verifExpDate; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSlave.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSlave.h new file mode 100644 index 0000000..731bf28 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSlave.h @@ -0,0 +1,122 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_SLAVE_H_ +#define _IDIBUS_SLAVE_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSystem.h" +#include "IdiBusDateTime.h" +#include "IdiBusMes.h" +#include "IdiBusSerialLine.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiMasterState { + public : + IDISTATUS_STATE_TYPE STATE; + struct { + struct { + uint8_t GS1_country[3]; + uint8_t GS1_company[6]; + uint8_t ModuleType[3]; + uint8_t HW_rev[2]; + uint8_t Serial[7]; + uint8_t MAC[6]; + } FIX; + struct VAR { + VAR() : VerifDate(0,0,0,0), VerifExpDate(0,0,0,0) {} + uint8_t SW_rev[2]; + IdiDateFormat VerifDate; + IdiDateFormat VerifExpDate; + uint8_t IPv4[4]; + uint8_t IPv6[16]; + uint8_t AES[32]; + } VAR; + } SN; + void parseSmesDataNoAes(uint8_t *Data); +}; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +class IdiBusLongOpData { + public : + IdiBusLongOpData() { this->State = IDILONGOP_STATE_COMPLETE_NO_ERR; this->Timeout = 0; } + uint8_t State; + uint32_t Timeout; +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusChannel { + public : + IdiBusChannel() { this->MMES_Error = IDIER_NOPE; } + IdiBusLongOpData LONG_OP; + uint8_t MMES_Error; +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBusDevice { + public : + IdiBusDevice (void *ParentModule) { this->Module = ParentModule; } + virtual IdiBusChannel *getChannel(uint8_t Num) { return NULL; } + protected : + void *Module; +}; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +class IdiBusSlave { + + public : + // Constructors and init + IdiBusSlave(IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); + IdiBusSlave(void); + void Init(IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); + + // Standard communication API + uint8_t SendRequestMMES(IdiBusMMES *MMES); + uint8_t SendRequestMMESG(IdiBusMMESG *MMESG); + + //Module commands (return ErrorCode) + uint8_t c_Init (void); + uint8_t c_Init (uint8_t Gpoup); + uint8_t c_ShtDown (void); + uint8_t c_Freeze (void); + uint8_t c_Resume (void); + uint8_t c_ReadDevFullSN_MS(void); + uint8_t c_WriteSnIPv4IPv6(uint32_t IPv4, uint32_t IPv6_B3, uint32_t IPv6_B2, uint32_t IPv6_B1, uint32_t IPv6_B0); + uint8_t c_WriteSnVerifyDates(IdiDateFormat VDate, IdiDateFormat VEXPDate); + uint8_t c_WriteSnAES256(uint8_t *AES256_key); + uint8_t c_SendTimeDate(IdiTimeFormat Time, IdiDateFormat Date); + uint8_t c_DummyModule(void); + uint8_t c_CheckModuleLongOp(void); + + // Channel Commands + uint8_t c_Dummy(uint8_t Device, uint8_t Channel); + uint8_t c_AssignGroup(uint8_t Device, uint8_t Channel, uint8_t Group); + uint8_t c_CheckChannelLongOp(uint8_t Device, uint8_t Channel); + + // Utils + uint8_t getAddress(void); + void setAes256ToSn(uint8_t *AES256_key); + IdiBusLongOpData getModuleLongOpData(void); + IdiBusLongOpData getChLongOpData(uint8_t Device, uint8_t Channel); + IdiMasterState getModuleSN(void); + + // Interface - must be overridden in derived classes + virtual IdiBusDevice *getDevice(uint8_t Num) { return NULL; } + + protected : + IdiBusSerialLine *Line; + uint8_t Address; + IdiMasterState ModuleST; + uint8_t ModuleError; + IdiBusLongOpData ModuleLongOpData; + uint8_t CRC_MultipleError; + struct { + uint8_t CRC_ErrAvrBuf[16]; + uint8_t CRC_ErrAvrBufCounter; + uint8_t CRC_ErrAvrBufPos; + uint8_t CRC_ErrAvrBufSum; + } CRC_AVR; + + uint8_t SendModuleSimpleSetCommand(uint8_t Command); + uint8_t SendModuleSimpleSetCommand(uint8_t Command, uint8_t *TxData, uint16_t TxDataLength); + void CrcAvrErrorCalc(uint8_t ErrorCode); +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_SLAVE_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSystem.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSystem.h new file mode 100644 index 0000000..979d5ff --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdiBusSystem.h @@ -0,0 +1,25 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_SYSTEM_H_ +#define _IDIBUS_SYSTEM_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "Arduino.h" +#include "pins_arduino.h" + +#include +#include +#include +#include +#include "IdiBusDefs.h" +#include "MODBUS_CRC.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#ifndef F_CPU +#error "IdibusSerial: F_CPU not defined!" +#endif + +#if defined __AVR_ATmega2560__ +#else +#error "IdibusSerial: Unsupported ControllerType!" +#endif +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#ifndef _IDIBUS_SYSTEM_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdibusDefs.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdibusDefs.h new file mode 100644 index 0000000..eb625e5 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/IdibusDefs.h @@ -0,0 +1,446 @@ +//############################################################################################################################################################################################################# +#ifndef _INC_IDIBUS_DEFS_H_ +#define _INC_IDIBUS_DEFS_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +#include "MODBUS_CRC.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_BAUDRATE_DSW_CODE_19200B 0x00 +#define IDIBUS_BAUDRATE_DSW_CODE_500K 0x01 +#define IDIBUS_BAUDRATE_DSW_CODE_2400B 0x02 +#define IDIBUS_BAUDRATE_DSW_CODE_9600B 0x03 +#define IDIBUS_BAUDRATE_DSW_CODE_115200B 0x04 +#define IDIBUS_BAUDRATE_DSW_CODE_250K 0x05 +#define IDIBUS_BAUDRATE_DSW_CODE_1M 0x06 +#define IDIBUS_BAUDRATE_DSW_CODE_10M 0x07 + +// Full timeout will be (InterframeTimeout + ResponseTimeout) for request(Write + Read) or InterframeTimeout for write(Write only) +#define IDIBUS_2400B_INTERFRAME_TIMEOUT_US 16042ULL //11 * 3.5 / Baudrate +#define IDIBUS_9600B_INTERFRAME_TIMEOUT_US 4011ULL +#define IDIBUS_19200B_INTERFRAME_TIMEOUT_US 2006ULL +#define IDIBUS_115200B_INTERFRAME_TIMEOUT_US 1750ULL +#define IDIBUS_250K_INTERFRAME_TIMEOUT_US 1750ULL +#define IDIBUS_500K_INTERFRAME_TIMEOUT_US 1750ULL +#define IDIBUS_1M_INTERFRAME_TIMEOUT_US 1750ULL +#define IDIBUS_10M_INTERFRAME_TIMEOUT_US 1750ULL + +#define IDIBUS_2400B_ALARM_TIMEOUT_US 34375ULL //11 * 3.5 / Baudrate +#define IDIBUS_9600B_ALARM_TIMEOUT_US 8594ULL +#define IDIBUS_19200B_ALARM_TIMEOUT_US 4297ULL +#define IDIBUS_115200B_ALARM_TIMEOUT_US 1750ULL +#define IDIBUS_250K_ALARM_TIMEOUT_US 1750ULL +#define IDIBUS_500K_ALARM_TIMEOUT_US 1750ULL +#define IDIBUS_1M_ALARM_TIMEOUT_US 1750ULL +#define IDIBUS_10M_ALARM_TIMEOUT_US 1750ULL + +#define IDIBUS_2400B_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_2400B_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_9600B_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_9600B_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_19200B_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_19200B_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_115200B_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_115200B_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_250K_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_250K_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_500K_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_500K_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_1M_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_1M_INTERFRAME_TIMEOUT_US * 3 / 2 ) +#define IDIBUS_10M_MASTER_RESPONSE_TIMEOUT_US (IDIBUS_10M_INTERFRAME_TIMEOUT_US * 3 / 2 ) + +#define IDIBUS_2400B_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_2400B_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_9600B_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_9600B_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_19200B_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_19200B_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_115200B_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_115200B_INTERFRAME_TIMEOUT_US) +#define IDIBUS_250K_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_250K_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_500K_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_500K_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_1M_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_1M_INTERFRAME_TIMEOUT_US ) +#define IDIBUS_10M_SLAVE_RESPONSE_TIMEOUT_US (IDIBUS_10M_INTERFRAME_TIMEOUT_US ) + + +enum IDIBUS_SERIAL_BAUDRATE { + IDIBUS_BAUDRATE_2400 = IDIBUS_BAUDRATE_DSW_CODE_2400B, + IDIBUS_BAUDRATE_9600 = IDIBUS_BAUDRATE_DSW_CODE_9600B, + IDIBUS_BAUDRATE_19200 = IDIBUS_BAUDRATE_DSW_CODE_19200B, + IDIBUS_BAUDRATE_115200 = IDIBUS_BAUDRATE_DSW_CODE_115200B, + IDIBUS_BAUDRATE_250K = IDIBUS_BAUDRATE_DSW_CODE_250K, + IDIBUS_BAUDRATE_500K = IDIBUS_BAUDRATE_DSW_CODE_500K, + IDIBUS_BAUDRATE_1M = IDIBUS_BAUDRATE_DSW_CODE_1M, + IDIBUS_BAUDRATE_10M = IDIBUS_BAUDRATE_DSW_CODE_10M +}; + +#define IDIBUS_LINK_LED_NO_MMES_TIMEOUT_0_SEC 60U +#define IDIBUS_LINK_LED_NO_MMES_TIMEOUT_0_MS ( IDIBUS_LINK_LED_NO_MMES_TIMEOUT_0_SEC * 1000U ) +#define IDIBUS_LINK_LED_NO_MMES_TIMEOUT_1_SEC 15U +#define IDIBUS_LINK_LED_NO_MMES_TIMEOUT_1_MS ( IDIBUS_LINK_LED_NO_MMES_TIMEOUT_1_SEC * 1000U ) + +enum IDIBUS_RXTIMER_TIMEOUT_MODE { + IDIBUS_TIMER_MODE_RX_TIMEOUT = 0x00, + IDIBUS_TIMER_MODE_ALARM_TIMEOUT, + IDIBUS_TIMER_MODE_RESPONSE_TIMEOUT +}; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDISN_FIXP_Pos 0U +#define IDISN_FIXP_GS1_COUNTRY_Pos ( IDISN_FIXP_Pos + 0U) +#define IDISN_FIXP_GS1_COUNTRY_Length 3 +#define IDISN_FIXP_GS1_COMPANY_Pos ( IDISN_FIXP_GS1_COUNTRY_Pos + IDISN_FIXP_GS1_COUNTRY_Length ) +#define IDISN_FIXP_GS1_COMPANY_Length 6 +#define IDISN_FIXP_MODULE_TYPE_Pos ( IDISN_FIXP_GS1_COMPANY_Pos + IDISN_FIXP_GS1_COMPANY_Length ) +#define IDISN_FIXP_MODULE_TYPE_Length 3 +#define IDISN_FIXP_HW_REV_Pos ( IDISN_FIXP_MODULE_TYPE_Pos + IDISN_FIXP_MODULE_TYPE_Length ) +#define IDISN_FIXP_HW_REV_Length 2 +#define IDISN_FIXP_SERIAL_Pos ( IDISN_FIXP_HW_REV_Pos + IDISN_FIXP_HW_REV_Length ) +#define IDISN_FIXP_SERIAL_Length 7 +#define IDISN_FIXP_MAC_Pos ( IDISN_FIXP_SERIAL_Pos + IDISN_FIXP_SERIAL_Length ) +#define IDISN_FIXP_MAC_Length 6 +#define IDISN_FIXP_LENGTH ( IDISN_FIXP_GS1_COUNTRY_Length + IDISN_FIXP_GS1_COMPANY_Length + IDISN_FIXP_MODULE_TYPE_Length + \ +IDISN_FIXP_HW_REV_Length + IDISN_FIXP_SERIAL_Length + IDISN_FIXP_MAC_Length ) + +#define IDISN_VARP_Pos IDISN_FIXP_LENGTH +#define IDISN_VARP_SW_REV_Pos ( IDISN_VARP_Pos + 0U ) +#define IDISN_VARP_SW_REV_Length 2U +#define IDISN_VARP_VERIF_DATE_Pos ( IDISN_VARP_SW_REV_Pos + IDISN_VARP_SW_REV_Length ) +#define IDISN_VARP_VERIF_DATE_Length 4U +#define IDISN_VARP_EXPIR_DATE_Pos ( IDISN_VARP_VERIF_DATE_Pos + IDISN_VARP_VERIF_DATE_Length ) +#define IDISN_VARP_EXPIR_DATE_Length 4U +#define IDISN_VARP_IPv4_Pos ( IDISN_VARP_EXPIR_DATE_Pos + IDISN_VARP_EXPIR_DATE_Length ) +#define IDISN_VARP_IPv4_Length 4U +#define IDISN_VARP_IPv6_Pos ( IDISN_VARP_IPv4_Pos + IDISN_VARP_IPv4_Length ) +#define IDISN_VARP_IPv6_Length 16U +#define IDISN_VARP_AES256_Pos ( IDISN_VARP_IPv6_Pos + IDISN_VARP_IPv6_Length ) +#define IDISN_VARP_AES256_Length 32U +#define IDISN_VARP_LENGTH ( IDISN_VARP_SW_REV_Length + IDISN_VARP_VERIF_DATE_Length + IDISN_VARP_EXPIR_DATE_Length + \ +IDISN_VARP_IPv4_Length + IDISN_VARP_IPv6_Length + IDISN_VARP_AES256_Length ) + +#define IDISN_FULL_LENGTH ( IDISN_FIXP_LENGTH + IDISN_VARP_LENGTH ) +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define ISIBUS_MASTER_MAIN_ADDR 255U +#define ISIBUS_MASTER_SPARE_ADDR 254U +#define IDIBUS_SLAVE_ADDR_MIN 1U +#define IDIBUS_SLAVE_ADDR_MAX 229U +#define IDIBUS_DEVELOPER_ADDR_0 250U +#define IDIBUS_DEVELOPER_ADDR_1 251U +#define IDIBUS_DEVELOPER_ADDR_2 252U +#define IDIBUS_DEVELOPER_ADDR_3 253U +#define IDIBUS_GROUP_0_ADDR 230U +#define IDIBUS_GROUP_1_ADDR 231U +#define IDIBUS_GROUP_2_ADDR 232U +#define IDIBUS_GROUP_3_ADDR 233U +#define IDIBUS_GROUP_4_ADDR 234U +#define IDIBUS_GROUP_5_ADDR 235U +#define IDIBUS_GROUP_6_ADDR 236U +#define IDIBUS_GROUP_7_ADDR 237U +#define IDIBUS_GROUP_8_ADDR 238U +#define IDIBUS_GROUP_9_ADDR 239U +#define IDIBUS_GROUP_10_ADDR 240U +#define IDIBUS_GROUP_11_ADDR 241U +#define IDIBUS_GROUP_12_ADDR 242U +#define IDIBUS_GROUP_13_ADDR 243U +#define IDIBUS_GROUP_14_ADDR 244U +#define IDIBUS_GROUP_15_ADDR 245U + +#define IDIBUS_GROUPS_NUMBER 16U +#define IDIBUS_GROUP_FIRST_NUMBER 0U +#define IDIBUS_GROUP_LAST_NUMBER 15U +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDIMMES_ADDR_Pos 00U +#define IDIMMES_MMPS_Pos 01U +#define IDIMMES_MMPS_LONG_MES_Pos 0U +#define IDIMMES_MMPS_LONG_MES_Msk 0x01U +#define IDIMMES_MMPS_MES_TYPE_Pos 1U +#define IDIMMES_MMPS_MES_TYPE_Msk 0x02U +#define IDIMMES_MMPS_MES_TYPE_MMES 0x00U +#define IDIMMES_MMPS_MES_TYPE_MMESG 0x01U +#define IDIMMES_MMPS_FAST_FUNC_Pos 2U +#define IDIMMES_MMPS_FAST_FUNC_Msk 0x3CU +#define IDIMMES_MMPS_ALARM_FRAME_Pos 6U +#define IDIMMES_MMPS_ALARM_FRAME_Msk 0x40U +#define IDIMMES_MMPS_ENCRYPTED_AES_Pos 7U +#define IDIMMES_MMPS_ENCRYPTED_AES_Msk 0x80U +#define IDIMMES_DEV_Pos 02U +#define IDIMMES_DEV_NUM_Pos 0U +#define IDIMMES_DEV_NUM_Msk 0x1FU +#define IDIMMES_DEV_ALLCH_Pos 5U +#define IDIMMES_DEV_ALLCH_Msk 0x20U +#define IDIMMES_CHNL_Pos 03U +#define IDIMMES_CHNL_NUM_Pos 0U +#define IDIMMES_CHNL_NUM_Msk 0x7FU +#define IDIMMES_CHNL_ALLSAME_Pos 7U +#define IDIMMES_CHNL_ALLSAME_Msk 0x80U +#define IDIMMES_DATA_FUNC_COM_DATA_Pos 04U +#define IDIMMES_MAX_HEADER_LENGTH (IDIMMES_DATA_FUNC_COM_DATA_Pos + 1) +#define IDIMMES_MAX_DATA_SIZE 256U +#define IDIMMES_MAX_MES_SIZE (IDIMMES_MAX_DATA_SIZE + IDIMMES_MAX_HEADER_LENGTH + MODBUS_CRC16_SIZE) +#define IDIMMES_MIN_MES_SIZE (IDIMMES_DATA_FUNC_COM_DATA_Pos + MODBUS_CRC16_SIZE) + +#define IDIMMESG_DATA_COM_FUNC_Pos 02U +#define IDIMMESG_MAX_HEADER_LENGTH (IDIMMESG_DATA_COM_FUNC_Pos + 1) +#define IDIMMESG_MAX_DATA_SIZE IDIMMES_MAX_DATA_SIZE +#define IDIMMESG_MAX_MES_SIZE (IDIMMESG_MAX_DATA_SIZE + IDIMMESG_MAX_HEADER_LENGTH + MODBUS_CRC16_SIZE) +#define IDIMMESG_MODULE_MIN_MES_SIZE (IDIMMESG_DATA_COM_FUNC_Pos + 1 + MODBUS_CRC16_SIZE) +#define IDIMMESG_GROUP_MIN_MES_SIZE (IDIMMESG_DATA_COM_FUNC_Pos + MODBUS_CRC16_SIZE) + +#define IDIMMES_LMES_MSIZE_Pos 0U +#define IDIMMES_LMES_BSIZE_Pos (IDIMMES_LMES_MSIZE_Pos + 4U) +#define IDIMMES_LMES_IDENTIFIER_LENGTH (IDIMMES_LMES_BSIZE_Pos + 1U) +#define IDIMMES_LMES_BSIZE_256B 0U +#define IDIMMES_LMES_BSIZE_1K 1U +#define IDIMMES_LMES_BSIZE_4K 2U +#define IDIMMES_LMES_BSIZE_8K 3U +#define IDIMMES_LMES_BSIZE_16K 4U +#define IDIMMES_LMES_BSIZE_32K 5U +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDISMES_ADDR_Pos 00U +#define IDISMES_SMPS_Pos 01U +#define IDISMES_SMPS_ERROR_BIT_Pos 0U +#define IDISMES_SMPS_LONG_MES_Pos 1U +#define IDISMES_SMPS_LONG_OP_Pos 2U +#define IDISMES_ERROR_Pos 02U +#define IDISMES_DATA_Pos 03U +#define IDISMES_MAX_DATA_SIZE 256U +#define IDISMES_MIN_MES_SIZE (IDISMES_DATA_Pos + MODBUS_CRC16_SIZE) +#define IDISMES_MAX_MES_SIZE (IDISMES_DATA_Pos + IDISMES_MAX_DATA_SIZE + MODBUS_CRC16_SIZE) +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDILONGOP_STATE_COMPLETE_NO_ERR 0x00U +#define IDILONGOP_STATE_IN_PROC 0x01U +#define IDILONGOP_STATE_COMPLETE_WITH_ERR 0x02U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDILONGOP_MES_DATA_LENGTH 5U +#define IDILONGOP_STATE_Pos 0U +#define IDILONGOP_REMAIN_TIME_Pos 1U +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDISTATUS_B0S_Pos 00U +#define IDISTATUS_B0S_ST_ERROR_Pos 0U +#define IDISTATUS_B0S_ST_STATE_Pos 1U +#define IDISTATUS_B0S_ST_STATE_Msk 0x07U +#define IDISTATUS_B0S_ST_STATE_StNoInit 0x00U +#define IDISTATUS_B0S_ST_STATE_StOperate 0x01U +#define IDISTATUS_B0S_ST_STATE_StFreeze 0x02U +#define IDISTATUS_B0S_ST_STATE_StVirtual 0x03U +#define IDISTATUS_B0S_ST_STATE_StFirmwareUpd 0x04U +#define IDISTATUS_B0S_ST_STATE_StReservedMaster 0x05U +#define IDISTATUS_B0S_ST_STATE_StBroken 0x06U +#define IDISTATUS_B0S_ST_STATE_StReserved0 0x07U +#define IDISTATUS_B0S_AES_SUPPORTED_Pos 4U +#define IDISTATUS_B0S_AES_INSTALLED_Pos 5U +#define IDISTATUS_B0S_SEND_ALARM_L0_Pos 6U +#define IDISTATUS_B0S_SEND_ALARM_L1_Pos 7U + +#define IDISTATUS_B1S_Pos 01U +#define IDISTATUS_B1S_MODULE_TYPE_Pos 0U +#define IDISTATUS_B1S_MODULE_TYPE_Msk 0x03U +#define IDISTATUS_B1S_MODULE_TYPE_Master 0x00U +#define IDISTATUS_B1S_MODULE_TYPE_SpareMaster 0x01U +#define IDISTATUS_B1S_MODULE_TYPE_Slave 0x02U +#define IDISTATUS_B1S_MODULE_TYPE_Bridge 0x03U +#define IDISTATUS_B1S_BRIDGE_CONNECTED_Pos 2U +#define IDISTATUS_B1S_SELF_INIT_Pos 3U +#define IDISTATUS_B1S_TIMEOUT_LED_Pos 4U +#define IDISTATUS_B1S_NO_MMES_TIMEOUT_Pos 5U +#define IDISTATUS_B1S_CATCH_ALARM_L0_Pos 6U +#define IDISTATUS_B1S_CATCH_ALARM_L1_Pos 7U + +#define IDISTATUS_SN_Pos 02U +#define IDISTATUS_LENGTH ( IDISTATUS_SN_Pos + IDISN_FULL_LENGTH ) +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDIMMES_NOT_FAST_FUNC 0U +#define IDIMMES_MAX_FAST_FUNC_NUM 15U +#define IDIMMES_COM_START_NUM 220U +#define IDIMMES_COM_C_Init 220U +#define IDIMMES_COM_C_ShtDown 221U +#define IDIMMES_COM_C_Freeze 222U +#define IDIMMES_COM_C_Resume 223U +#define IDIMMES_COM_C_Dummy 224U +#define IDIMMES_COM_C_AssignGroup 225U +#define IDIMMES_COM_C_SetAlarmL12 226U +#define IDIMMES_COM_C_SetAlarmL 227U +#define IDIMMES_COM_C_Virtual 228U +#define IDIMMES_COM_C_SyncReadChnl 229U +#define IDIMMES_COM_C_SyncRead 230U +#define IDIMMES_COM_C_SyncDoChnl 231U +#define IDIMMES_COM_C_SyncDo 232U +#define IDIMMES_COM_C_SyncClear 233U +#define IDIMMES_COM_C_BurstReadCnt 234U +#define IDIMMES_COM_C_BurstReadTime 235U +#define IDIMMES_COM_C_SendTimeDate 236U +#define IDIMMES_COM_C_MkTimedMaster 237U +#define IDIMMES_COM_C_FmwUpd 238U +#define IDIMMES_COM_C_EndFmwUpd 239U +#define IDIMMES_COM_C_FmwWrite 240U +#define IDIMMES_COM_C_ReadDevFullSN_MS 241U +#define IDIMMES_COM_C_WriteSnIPv4IPv6 242U +#define IDIMMES_COM_C_WriteSnVerifyDates 243U +#define IDIMMES_COM_C_WriteSnAES256 244U +#define IDIMMES_COM_C_SendLongMessage 245U +#define IDIMMES_COM_C_GetLondMessage 246U +#define IDIMMES_COM_C_DummyModule 247U +#define IDIMMES_COM_C_CheckModuleLongOp 248U +#define IDIMMES_COM_C_CheckChannelLongOp 249U +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDIER_MODBUS_NUM_START 1U +#define IDIER_MODBUS_NUM_END 9U +#define IDIER_MODULE_MASTER_NUM_START 10U +#define IDIER_MODULE_MASTER_NUM_END 32U +#define IDIER_MODULE_SLAVE_NUM_START 33U +#define IDIER_MODULE_SLAVE_NUM_END 71U +#define IDIER_MODULE_NUM_START IDIER_MODULE_MASTER_NUM_START +#define IDIER_MODULE_NUM_END IDIER_MODULE_SLAVE_NUM_END +#define IDIER_DEVICE_NUM_START 72U +#define IDIER_DEVICE_NUM_END 89U + +#define IDIER_NOPE 0U +#define MODBUSER_WRONGFUNC 1U +#define MODBUSER_WRONGADDR 2U +#define MODBUSER_WRONGDATA 3U +#define MODBUSER_BROKE 4U +#define MODBUSER_LONGCOMMAND 5U +#define MODBUSER_BUSY 6U +#define MODBUSER_CANTDOFUNC 7U +#define MODBUSER_EXTMEMORYERROR 8U +#define MODBUSER_RESERVED 9U +#define IDIERMST_INVALID_ADDR_NUM 10U +#define IDIERMST_INVALID_DEV_NUM 11U +#define IDIERMST_INVALID_CHN_NUM 12U +#define IDIERMST_INVALID_FUNC_NUM 13U +#define IDIERMST_INVALID_TX_REQUEST_FORMAT 14U +#define IDIERMST_INVALID_TX_PARAM 15U +#define IDIERMST_TX_MES 16U +#define IDIERMST_RCV_TIMEOUT 17U +#define IDIERMST_MES_RX_INTEGRITY 18U +#define IDIERMST_CRC 19U +#define IDIERMST_MULTIPLE_CRC 20U +#define IDIERMST_INVALID_RX_REQUEST_FORMAT 21U +#define IDIERMST_INVALID_RX_PARAM 22U +#define IDIERMST_RESEVED_23 23U +#define IDIERMST_RESEVED_24 24U +#define IDIERMST_RESEVED_25 25U +#define IDIERMST_RESEVED_26 26U +#define IDIERMST_RESEVED_27 27U +#define IDIERMST_EXTRA_28 28U +#define IDIERMST_EXTRA_29 29U +#define IDIERMST_EXTRA_30 30U +#define IDIERMST_EXTRA_31 31U +#define IDIERMST_EXTRA_32 32U +#define IDIERSLV_RESEVED_33 33U +#define IDIERSLV_ENCRYPTION_NOT_SUPPORTED 34U +#define IDIERSLV_ENCRYPTION_NOT_INSTALLED 35U +#define IDIERSLV_JUMBO_NOT_SUPPORTED 36U +#define IDIERSLV_UNSUPPORTED_FUNC_NUM 37U +#define IDIERSLV_INVALID_RX_REQUEST_FORMAT 38U +#define IDIERSLV_INVALID_RX_PARAM 39U +#define IDIERSLV_IN_FREEZE 40U +#define IDIERSLV_RESERVED_41 41U +#define IDIERSLV_RESERVED_42 42U +#define IDIERSLV_RESERVED_43 43U +#define IDIERSLV_RESERVED_44 44U +#define IDIERSLV_RESERVED_45 45U +#define IDIERSLV_EXTRA_46 46U +#define IDIERSLV_EXTRA_47 47U +#define IDIERSLV_EXTRA_48 48U +#define IDIERSLV_EXTRA_49 49U +#define IDIERSLV_EXTRA_50 50U +#define IDIERSLV_BROKE 51U +#define IDIERSLV_NO_FIRMWARE 52U +#define IDIERSLV_NO_INIT 53U +#define IDIERSLV_OVERHEAT 54U +#define IDIERSLV_INP_VOLTAGE 55U +#define IDIERSLV_BRIDGE_OVERFLOW 56U +#define IDIERSLV_BRIDGE_NOT_CONF 57U +#define IDIERSLV_VERIF_DATE 58U +#define IDIERSLV_RTC 59U +#define IDIERSLV_LONG_OP_IN_PROC 60U +#define IDIERSLV_RESERVED_61 61U +#define IDIERSLV_RESERVED_62 62U +#define IDIERSLV_RESERVED_63 63U +#define IDIERSLV_RESERVED_64 64U +#define IDIERSLV_RESERVED_65 65U +#define IDIERSLV_RESERVED_66 66U +#define IDIERSLV_EXTRA_67 67U +#define IDIERSLV_EXTRA_68 68U +#define IDIERSLV_EXTRA_69 69U +#define IDIERSLV_EXTRA_70 70U +#define IDIERSLV_EXTRA_71 71U +#define IDIERDEV_INVALID_DEV_NUM 72U +#define IDIERDEV_INVALID_CHN_NUM 73U +#define IDIERDEV_INVALID_FUNC_NUM 74U +#define IDIERDEV_LONG_OP_IN_PROC 75U +#define IDIERDEV_RESERVED_76 76U +#define IDIERDEV_PARAM_LOW_ST_TIMEOUT 77U +#define IDIERDEV_PARAM_HIGH_ST_TIMEOUT 78U +#define IDIERDEV_PARAM_NOT_CHANGE_TIMEOUT 79U +#define IDIERDEV_RESERVED_80 80U +#define IDIERDEV_RESERVED_81 81U +#define IDIERDEV_RESERVED_82 82U +#define IDIERDEV_RESERVED_83 83U +#define IDIERDEV_RESERVED_84 84U +#define IDIERDEV_RESERVED_85 85U +#define IDIERDEV_RESERVED_86 86U +#define IDIERDEV_RESERVED_87 87U +#define IDIERDEV_RESERVED_88 88U +#define IDIERDEV_RESERVED_89 89U + +#define IDIER_MULTIPLE_CRC_AVRBUF_SIZE 16U +#define IDIER_MULTIPLE_CRC_AVRBUF_THR 5U +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +#define IDIDATE_FORMAT_DAY_Pos 0U +#define IDIDATE_FORMAT_MONTH_Pos 1U +#define IDIDATE_FORMAT_CENTURY_Pos 2U +#define IDIDATE_FORMAT_YEAR99_Pos 3U +#define IDIDATE_FORMAT_LENGTH 4U + +#define IDITIME_FORMAT_SECONDS_Pos 0U +#define IDITIME_FORMAT_MINUTES_Pos 1U +#define IDITIME_FORMAT_HOURS_Pos 2U +#define IDITIME_FORMAT_TIMEZONE_Pos 3U +#define IDITIME_FORMAT_LENGTH 4U + +#define IDITIME_FORMAT_TIMEZONE_MIN (-12) +#define IDITIME_FORMAT_TIMEZONE_MAX 14 + +#define IDIMMES_C_DATETIME_TIME_Pos 0 +#define IDIMMES_C_DATETIME_DATE_Pos (IDIMMES_C_DATETIME_TIME_Pos + IDIDATE_FORMAT_LENGTH) +#define IDIMMES_C_DATETIME_LENGTH (IDIDATE_FORMAT_LENGTH + IDITIME_FORMAT_LENGTH) +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +typedef struct { + struct { + uint8_t StError : 1; + uint8_t StState : 3; + uint8_t AesSupported : 1; + uint8_t AesInstalled : 1; + uint8_t SendAlarmL0 : 1; + uint8_t SendAlarmL1 : 1; + } B0S; + struct { + uint8_t ModuleType : 2; + uint8_t BridgeConnected : 1; + uint8_t SelfInit : 1; + uint8_t TimeoutLed : 1; + uint8_t NoMMESTimeout : 1; + uint8_t CatchAlarmL0 : 1; + uint8_t CatchAlarmL1 : 1; + } B1S; +} IDISTATUS_STATE_TYPE; +//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------s +typedef struct { + IDISTATUS_STATE_TYPE STATE; + uint8_t SN[IDISN_FULL_LENGTH]; +} IDISTATUS_SLAVE_TYPE; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //_INC_IDIBUS_DEFS_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/MODBUS_CRC.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/MODBUS_CRC.cpp new file mode 100644 index 0000000..ef339dd --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/MODBUS_CRC.cpp @@ -0,0 +1,134 @@ +//################################################################################################################################################### +#include "MODBUS_CRC.h" +//--------------------------------------------------------------------------------------------------------------------------------------------------- +// Table of CRC values for highorder byte FLASH Variant +const uint8_t MODBUS_auchCRCHi_PR[] PROGMEM = { +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, +0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, +0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40 +}; +// Table of CRC values for loworder byte +const uint8_t MODBUS_auchCRCLo_PR[] PROGMEM = { +0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, +0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, +0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, +0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, +0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, +0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, +0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, +0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, +0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, +0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, +0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, +0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, +0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, +0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, +0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, +0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, +0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, +0x40 +}; +//--------------------------------------------------------------------------------------------------------------------------------------------------- +// Table of CRC values for highorder byte RAM Variant +uint8_t MODBUS_auchCRCHi_R[] = { +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, +0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, +0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, +0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, +0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, +0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, +0x40 +}; +// Table of CRC values for loworder byte +uint8_t MODBUS_auchCRCLo_R[] = { +0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, +0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, +0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, +0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, +0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, +0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, +0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, +0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, +0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, +0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, +0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, +0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, +0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, +0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, +0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, +0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, +0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, +0x40 +}; +//--------------------------------------------------------------------------------------------------------------------------------------------------- +uint16_t MODBUS_CRC16::CRC16_TF(uint8_t *MODBUS_puchMsg, uint16_t MODBUS_usDataLen) +{ + uint8_t MODBUS_uchCRCHi = 0xFF; // high byte of CRC initialized + uint8_t MODBUS_uchCRCLo = 0xFF; // low byte of CRC initialized + uint8_t MODBUS_uIndex; + while (MODBUS_usDataLen--) + { + MODBUS_uIndex = MODBUS_uchCRCLo ^ (*MODBUS_puchMsg++); // calculate the CRC + MODBUS_uchCRCLo = MODBUS_uchCRCHi ^ pgm_read_byte(&MODBUS_auchCRCHi_PR[MODBUS_uIndex]); + MODBUS_uchCRCHi = pgm_read_byte(&MODBUS_auchCRCLo_PR[MODBUS_uIndex]); + } + return ( ((uint16_t)MODBUS_uchCRCHi << 8 ) | MODBUS_uchCRCLo ); +} +//--------------------------------------------------------------------------------------------------------------------------------------------------- +uint16_t MODBUS_CRC16::CRC16_TR(uint8_t *MODBUS_puchMsg, uint16_t MODBUS_usDataLen) +{ + uint8_t MODBUS_uchCRCHi = 0xFF; // high byte of CRC initialized + uint8_t MODBUS_uchCRCLo = 0xFF; // low byte of CRC initialized + uint8_t MODBUS_uIndex; + while (MODBUS_usDataLen--) + { + MODBUS_uIndex = MODBUS_uchCRCLo ^ (*MODBUS_puchMsg++); // calculate the CRC + MODBUS_uchCRCLo = MODBUS_uchCRCHi ^ MODBUS_auchCRCHi_R[MODBUS_uIndex]; + MODBUS_uchCRCHi = MODBUS_auchCRCLo_R[MODBUS_uIndex]; + } + return (((uint16_t)MODBUS_uchCRCHi << 8) | MODBUS_uchCRCLo); +} +//--------------------------------------------------------------------------------------------------------------------------------------------------- +uint16_t MODBUS_CRC16::CRC16_S(uint8_t *MODBUS_buf, uint16_t MODBUS_len) +{ + uint16_t MODBUS_crc = 0xFFFF; + for (uint16_t MODBUS_pos = 0; MODBUS_pos < MODBUS_len; MODBUS_pos++) + { + MODBUS_crc ^= MODBUS_buf[MODBUS_pos]; // XOR byte into least sig. byte of crc + for (uint8_t MODBUS_i = 8; MODBUS_i != 0; MODBUS_i--) // Loop over each bit + { + if ((MODBUS_crc & 0x0001) != 0) { MODBUS_crc >>= 1; MODBUS_crc ^= 0xA001; } // If the LSB is set // Shift right and XOR 0xA001 + else { MODBUS_crc >>= 1; } // Else LSB is not set // Just shift right + } + } + + return MODBUS_crc; +} +//--------------------------------------------------------------------------------------------------------------------------------------------------- +//################################################################################################################################################### diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/MODBUS_CRC.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/MODBUS_CRC.h new file mode 100644 index 0000000..703e77d --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusLib/MODBUS_CRC.h @@ -0,0 +1,20 @@ +//################################################################################################################################################### +#ifndef _MODBUS_CRC_H_ +#define _MODBUS_CRC_H_ +//--------------------------------------------------------------------------------------------------------------------------------------------------- +#include "avr/io.h" +#include +#include +//--------------------------------------------------------------------------------------------------------------------------------------------------- +#define MODBUS_CRC16_SIZE 2 +//--------------------------------------------------------------------------------------------------------------------------------------------------- +class MODBUS_CRC16 { + public : + static uint16_t CRC16_TF(uint8_t *MODBUS_puchMsg, uint16_t MODBUS_usDataLen); + static uint16_t CRC16_TR(uint8_t *MODBUS_puchMsg, uint16_t MODBUS_usDataLen); + static uint16_t CRC16_S(uint8_t *MODBUS_buf, uint16_t MODBUS_len); + private : + }; +//--------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _CRC_MODBUS_ +//################################################################################################################################################### \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1Wire.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1Wire.cpp new file mode 100644 index 0000000..ac4f5c9 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1Wire.cpp @@ -0,0 +1,157 @@ +#include "IDIBUS_1Wire.h" + +IdiBus_1Wire::IdiBus_1Wire (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress) +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].Temperature = 0; + //this->CH[I].STATUS.Enable = 0; + } +} + +IdiBus_1Wire::IdiBus_1Wire () : IdiBusSlave() +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].Temperature = 0; + //this->CH[I].STATUS.Enable = 0; + } +} + +IDIBUS_1Wire_DATA_TYPE IdiBus_1Wire::getChData(uint8_t ChNum){ + if ( ChNum < IDIBUS_1Wire_CH_COUNT ) { return this->CH[ChNum]; } + else { return this->CH[IDIBUS_1Wire_CH3_NUM]; } +} + +void IdiBus_1Wire::changeAllAutomatiocConversionStates() +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_1Wire_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x01; + uint8_t ChDataSize = 1; + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_1Wire_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_1Wire_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_1Wire_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_1Wire_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + } +} + +void IdiBus_1Wire::startAllOneShotConversions() +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_1Wire_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x02; + uint8_t ChDataSize = 0; + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_1Wire_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_1Wire_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_1Wire_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_1Wire_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + } +} + +uint8_t IdiBus_1Wire::getTemperature(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_1Wire_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_1Wire_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x03; //Get Value + uint8_t ChDataSize = 2; //int16_t + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Temperature = (int16_t) ( ((int16_t)MMES.RxData[1]<<8) | + ((int16_t)MMES.RxData[2])); + } + } + return this->CH[ChNum].MMES_Error; +} + +void IdiBus_1Wire::getAllChTemperature(void) +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_1Wire_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x03; + uint8_t ChDataSize = 2; //int16_t + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_1Wire_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_1Wire_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_1Wire_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_1Wire_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->CH[I].Temperature = (uint16_t) ( + (uint16_t)((uint16_t)MMES.RxData[DataPos] << 8) | + (uint16_t)((uint16_t)MMES.RxData[DataPos+1]) ); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} + +void IdiBus_1Wire::setAllChErr(uint8_t ErrCode) +{ + for (uint8_t I=0; ICH[I].MMES_Error = ErrCode; } +} + +/* +void IdiBus_1Wire::initAllChs(void) +{ + //uint8_t TxData[2]; + //TxData[0] = (uint8_t)(CurrentLimit >> 8); + //TxData[1] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_1Wire_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x01; + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_1Wire_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_1Wire_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + //if ( this->CH[I].MMES_Error == IDIER_NOPE ) + } + } +} +*/ diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1Wire.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1Wire.h new file mode 100644 index 0000000..18b3403 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1Wire.h @@ -0,0 +1,51 @@ +#ifndef IDIBUS_1Wire_H_ +#define IDIBUS_1Wire_H_ + +#include "IdiBusSlave.h" // Common slave defines +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_ERCODE_OneWIRE_CHANNEL_SETTINGS_ERROR 100U +#define IDIBUS_CUSTDEF_ERCODE_OneWIRE_CHANNEL_CRC_ERROR 101U +#define IDIBUS_CUSTDEF_ERCODE_OneWIRE_CHANNEL_NO_DATA 102U +#define IDIBUS_CUSTDEF_ERCODE_OneWIRE_CHANNEL_NO_SENSOR 103U +#define IDIBUS_CUSTDEF_ERCODE_OneWIRE_CHANNEL_AUTOCONVERSION_ENABLED 105U +#define IDIBUS_CUSTDEF_ERCODE_OneWIRE_CHANNEL_ONESHOT_IN_PROGRESS 106U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_1Wire_MODULE_DEVICES_LIST { // Describe devices on module + IDIBUS_1Wire_CNTRL_DEV = 0, // ADC device ID + IDIBUS_1Wire_DEVICES_NUMBER // Device count on module + }; + +enum { // Describe channel configuration for device (1Wire) + IDIBUS_1Wire_CH0_NUM = 0, // Name for 1st channel + IDIBUS_1Wire_CH1_NUM, // 2nd ... + IDIBUS_1Wire_CH2_NUM, // + IDIBUS_1Wire_CH3_NUM, // + IDIBUS_1Wire_CH_COUNT, // Module channel count + }; + +typedef struct { + int16_t Temperature; // Last voltage + uint8_t MMES_Error; // Last error +} IDIBUS_1Wire_DATA_TYPE; // Data structure for ADC channels + +class IdiBus_1Wire : public IdiBusSlave { // ADC module class + public: // Public methods + IdiBus_1Wire ( IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); // Init object with specified bus line and addr + IdiBus_1Wire (); // init without specified line and addr (default value line=NULL,addr=1) + + void startAllOneShotConversions(); + void changeAllAutomatiocConversionStates(); + uint8_t getTemperature(uint8_t ChNum); // Sends MMES and gets Ch voltage (writes to CH structure and return error code) + void getAllChTemperature(void); // Sends MMES and gets all Ch voltages (writes to CH structure) + + //void initAllChs(void); // Inits all adc channels on module + + IDIBUS_1Wire_DATA_TYPE getChData(uint8_t ChNum); // Returns data structure for ADC channel + + protected : // 'Private' methods and structures + IDIBUS_1Wire_DATA_TYPE CH[IDIBUS_1Wire_CH_COUNT]; // Data structure array + + void setAllChErr(uint8_t ErrCode); // Set error code for all channels +}; + +#endif /* IDIBUS_41Wire_H_ */ \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1xGen.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1xGen.cpp new file mode 100644 index 0000000..dbc943e --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1xGen.cpp @@ -0,0 +1,52 @@ +#include "IDIBUS_1xGen.h" + +IdiBus_1xGen::IdiBus_1xGen (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress) +{ + TMP.MMES_Error = 0; + TMP.RXlen = 0; +} + +IdiBus_1xGen::IdiBus_1xGen () : IdiBusSlave() +{ + TMP.MMES_Error = 0; + TMP.RXlen = 0; +} + +IDIBUS_1xGEN_DATA_TYPE IdiBus_1xGen::getData(void) +{ + return this->TMP; +} + +uint8_t IdiBus_1xGen::start_SPI(uint8_t *buf) { + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_1xGen_DEV; + MMES.CHNL.NUM = 0; + MMES.ComFunc = 0x01; + MMES.TxDataLength = 10; + MMES.TxData = buf; + uint8_t RequestError = this->SendRequestMMES(&MMES); + + if ( RequestError != IDIER_NOPE ) { this->TMP.MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->TMP.MMES_Error = MMES.RxData[0]; } + else { + this->TMP.MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; + } + return this->TMP.MMES_Error; +} + +uint8_t IdiBus_1xGen::reset_STM() { + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_1xGen_DEV; + MMES.CHNL.NUM = 0; + MMES.ComFunc = 0x02; + + uint8_t ChDataSize = 0; + uint8_t RequestError = this->SendRequestMMES(&MMES); + + if ( RequestError != IDIER_NOPE ) { this->TMP.MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->TMP.MMES_Error = MMES.RxData[0]; } + else { + this->TMP.MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; + } + return this->TMP.MMES_Error; +} \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1xGen.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1xGen.h new file mode 100644 index 0000000..187c847 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_1xGen.h @@ -0,0 +1,47 @@ +#ifndef IDIBUS_1XGEN_H_ +#define IDIBUS_1XGEN_H_ + +#include "IdiBusSlave.h" + +typedef struct { + uint8_t first_mode_time; + uint16_t first_mode_pwm_value; + uint8_t first_mode_f; + uint8_t first_mode_invert; + //uint8_t first_mode_R1; + + uint8_t second_mode_time; + uint16_t second_mode_pwm_value; + uint8_t second_mode_f; + uint8_t second_mode_invert; + //uint8_t second_mode_R1; +} Inputs; + +enum IDIBUS_1xGen_MODULE_DEVICES_LIST { + IDIBUS_1xGen_DEV = 0x00, + IDIBUS_1xGen_DEVICES_NUMBER +}; + +typedef struct { + uint8_t RXlen; + uint8_t RXbuf[255]; + uint8_t MMES_Error; // Last error +} IDIBUS_1xGEN_DATA_TYPE; + +class IdiBus_1xGen : public IdiBusSlave { + public: + IdiBus_1xGen (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); + IdiBus_1xGen(); + + uint8_t start_SPI(uint8_t *buf); + uint8_t reset_STM(); + + //virtual IdiBusDevice *getDevice(uint8_t Num); // !!! + + IDIBUS_1xGEN_DATA_TYPE getData(); + + protected: + IDIBUS_1xGEN_DATA_TYPE TMP; +}; + +#endif /* IDIBUS_1XGEN_H_ */ \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_2SALTMETER.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_2SALTMETER.cpp new file mode 100644 index 0000000..ebb8532 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_2SALTMETER.cpp @@ -0,0 +1,160 @@ +#include "IDIBUS_2SALTMETER.h" + +IdiBus_2SALT::IdiBus_2SALT (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress) +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].Voltage = 0; + } +} + +IdiBus_2SALT::IdiBus_2SALT () : IdiBusSlave() +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].Voltage = 0; + } +} + +IDIBUS_2SALT_DATA_TYPE IdiBus_2SALT::getChData(uint8_t ChNum){ + if ( ChNum < IDIBUS_2SALT_CH_COUNT ) { return this->CH[ChNum]; } + else { return this->CH[IDIBUS_2SALT_CH1_NUM]; } +} + +uint8_t IdiBus_2SALT::getChSaltData(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_2SALT_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_2SALT_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x03; //Get Value + uint8_t ChDataSize = 2; //uint16_t + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Voltage = (uint16_t) ( + ((uint16_t)MMES.RxData[1] << 8 ) | + ((uint16_t)MMES.RxData[2]) ); + } + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_2SALT::getAllChsSaltData(void) +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_2SALT_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x03; + uint8_t ChDataSize = 2; //uint16_t + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_2SALT_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_2SALT_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_2SALT_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_2SALT_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { + this->CH[I].Voltage = (uint16_t) ( + ((uint16_t)MMES.RxData[DataPos] << 8) | + ((uint16_t)MMES.RxData[DataPos+1]) ); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} + +void IdiBus_2SALT::setAllChErr(uint8_t ErrCode) +{ + for (uint8_t I=0; ICH[I].MMES_Error = ErrCode; } +} + +uint8_t IdiBus_2SALT::setCh(uint8_t ChNum, uint8_t state) +{ + if (ChNum >= IDIBUS_2SALT_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_2SALT_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x01; //init + MMES.TxDataLength = 1; + MMES.TxData = &state; + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_2SALT::setAllCh(uint8_t state) +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_2SALT_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x01; //init + MMES.TxDataLength = 1; + MMES.TxData = &state; + MMES.CHNL.ALLSAME = 1; + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_2SALT_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_2SALT_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + } + } +} + +uint8_t IdiBus_2SALT::startOneShot(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_2SALT_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_2SALT_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x02; //init + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_2SALT::startAllOneShot(void) +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_2SALT_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x02; //init + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_2SALT_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_2SALT_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + } + } +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_2SALTMETER.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_2SALTMETER.h new file mode 100644 index 0000000..eda373c --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_2SALTMETER.h @@ -0,0 +1,51 @@ +#ifndef IDIBUS_2SALT_H_ +#define IDIBUS_2SALT_H_ + +#include "IdiBusSlave.h" // Common slave defines +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_ERCODE_SALTMETER_POWEROFF 100U +#define IDIBUS_CUSTDEF_ERCODE_SALTMETER_CHANNEL_CAPTURE_IN_PROGRESS 101U +#define IDIBUS_CUSTDEF_ERCODE_SALTMETER_CHANNEL_NOT_SELECTED 102U +#define IDIBUS_CUSTDEF_ERCODE_SALTMETER_CHANNEL_NO_VALID_DATA 103U +#define IDIBUS_CUSTDEF_ERCODE_SALTMETER_CHANNEL_NO_STABLE_DATA 104U +#define IDIBUS_CUSTDEF_ERCODE_SALTMETER_TWI_ERROR 106U +#define IDIBUS_CUSTDEF_ERCODE_SALTMETER_TWI_BUSY 107U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_2SALT_MODULE_DEVICES_LIST { // Describe devices on module + IDIBUS_2SALT_CNTRL_DEV = 0, // SALT device ID + IDIBUS_2SALT_DEVICES_NUMBER // Device count on module + }; + +enum { // Describe channel configuration for device (SALT) + IDIBUS_2SALT_CH0_NUM = 0, // Name for 1st channel + IDIBUS_2SALT_CH1_NUM, // 2nd ... + IDIBUS_2SALT_CH_COUNT, // Channel count + }; + +typedef struct { + uint16_t Voltage; // Last returned value + uint8_t MMES_Error; // Last error +} IDIBUS_2SALT_DATA_TYPE; // Data structure for SALT channels + +class IdiBus_2SALT : public IdiBusSlave { // SALT module class + public: // Public methods + IdiBus_2SALT ( IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); // Init object with specified bus line and addr + IdiBus_2SALT(); // init without specified line and addr (default value line=NULL,addr=1) + + uint8_t getChSaltData(uint8_t ChNum); // Sends MMES and get Counts on ch (writes to CH structure and returns MMES error code) + void getAllChsSaltData(void); // Sends MMES and get Counts on ch (writes to CH structure) + + uint8_t startOneShot(uint8_t ChNum); + void startAllOneShot(void); + + uint8_t setCh(uint8_t ChNum, uint8_t state); // Inits specified counter channel on module + void setAllCh(uint8_t state); // Inits all counters on module + + IDIBUS_2SALT_DATA_TYPE getChData(uint8_t ChNum); // Returns data structure + + protected: // 'Private' methods and structures + IDIBUS_2SALT_DATA_TYPE CH[IDIBUS_2SALT_CH_COUNT]; // Data structure array + + void setAllChErr(uint8_t ErrCode); // Set error code for all channels +}; +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_3Thermo1HT.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_3Thermo1HT.cpp new file mode 100644 index 0000000..671324f --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_3Thermo1HT.cpp @@ -0,0 +1,250 @@ +#include "IDIBUS_3Thermo1HT.h" + +IdiBusDevice *IdiBus_3Thermo1HT::getDevice(uint8_t Num) +{ + switch (Num) + { + case ( IDIBUS_3Thermo1HT_THERMO_DEV ) : { return &this->THERMO_DEV; } + //case ( IDIBUS_INPV_CNTRL_DEV ) : { return &this->INPV_DEV; } + default : { return NULL; } + } +} + +IdiBus_3Thermo1HT_ThermoChannel::IdiBus_3Thermo1HT_ThermoChannel(void) : IdiBusChannel() +{ + this->Temperature = 0; + this->CJTemperature = 0; + this->MMES_Error = (1<<2); + /*Bit error list + 0 - Sensor fault + 1 - over/under voltage + 2 - no data error + 6 - TC out of range + 7 - CJ out of range + */ +} + +IdiBusChannel *IdiBus_3Thermo1HT_ThermoDevice::getChannel(uint8_t Num) +{ + if ( Num < IDIBUS_3Thermo1HT_Thermo_CH_COUNT ) { return &this->CH[Num]; } + else { return NULL; } +} + +IdiBus_3Thermo1HT_ThermoChannel IdiBus_3Thermo1HT_ThermoDevice::getChData(uint8_t ChNum){ + if ( ChNum < IDIBUS_3Thermo1HT_Thermo_CH_COUNT ) { return this->CH[ChNum]; } + else { IdiBus_3Thermo1HT_ThermoChannel NewData; return NewData; } +} + +uint8_t IdiBus_3Thermo1HT_ThermoDevice::startOneShotConversion(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_3Thermo1HT_Thermo_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + + IdiBusMMES MMES(static_cast(this->Module)->getAddress()); + MMES.DEV.NUM = IDIBUS_3Thermo1HT_THERMO_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x02; //Start one shot conversion + + uint8_t ChDataSize = 0; //None + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + } + return this->CH[ChNum].MMES_Error; +} // + +void IdiBus_3Thermo1HT_ThermoDevice::startAllOneShotConversions() +{ + IdiBusMMES MMES(static_cast(this->Module)->getAddress()); + MMES.DEV.NUM = IDIBUS_3Thermo1HT_THERMO_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x02;//Set automatic conversion + uint8_t ChDataSize = 0; //None + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_3Thermo1HT_Thermo_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_3Thermo1HT_Thermo_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_3Thermo1HT_Thermo_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_3Thermo1HT_Thermo_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + } +} + +uint8_t IdiBus_3Thermo1HT_ThermoDevice::changeAutomatiocConversionState(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_3Thermo1HT_Thermo_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + + IdiBusMMES MMES(static_cast(this->Module)->getAddress()); + MMES.DEV.NUM = IDIBUS_3Thermo1HT_THERMO_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x01; //Set automatic conversion + + uint8_t ChDataSize = 1; //uint8_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + //if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + //{ + //Ignoring return value + //} + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_3Thermo1HT_ThermoDevice::changeAllAutomatiocConversionStates(void) +{ + IdiBusMMES MMES(static_cast(this->Module)->getAddress()); + MMES.DEV.NUM = IDIBUS_3Thermo1HT_THERMO_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x01;//Set automatic conversion + uint8_t ChDataSize = 1; //uint8_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_3Thermo1HT_Thermo_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_3Thermo1HT_Thermo_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_3Thermo1HT_Thermo_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_3Thermo1HT_Thermo_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + //if ( this->CH[I].MMES_Error == IDIER_NOPE ) + //{ + //} + } + +} + +uint8_t IdiBus_3Thermo1HT_ThermoDevice::getTemperature(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_3Thermo1HT_Thermo_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(static_cast(this->Module)->getAddress()); + MMES.DEV.NUM = IDIBUS_3Thermo1HT_THERMO_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x03; //Get Value + uint8_t ChDataSize = 3; //int24_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Temperature = (int32_t) ( ((int32_t)MMES.RxData[1]<<16) | + ((int32_t)MMES.RxData[2]<<8) | + ((int32_t)MMES.RxData[3])); + } + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_3Thermo1HT_ThermoDevice::getAllChTemperature(void) +{ + IdiBusMMES MMES(static_cast(this->Module)->getAddress()); + MMES.DEV.NUM = IDIBUS_3Thermo1HT_THERMO_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x03; + uint8_t ChDataSize = 3; //int24_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_3Thermo1HT_Thermo_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_3Thermo1HT_Thermo_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_3Thermo1HT_Thermo_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_3Thermo1HT_Thermo_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->CH[I].Temperature = (int32_t) ( ((int32_t)MMES.RxData[DataPos]<<16) | + ((int32_t)MMES.RxData[DataPos+1]<<8) | + ((int32_t)MMES.RxData[DataPos+2])); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} + +uint8_t IdiBus_3Thermo1HT_ThermoDevice::getCJTemperature(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_3Thermo1HT_Thermo_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(static_cast(this->Module)->getAddress()); + MMES.DEV.NUM = IDIBUS_3Thermo1HT_THERMO_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x04; //Get Value + uint8_t ChDataSize = 2; //int16_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Temperature = (int16_t) ( ((int16_t)MMES.RxData[1]<<8) | + ((int16_t)MMES.RxData[2]) ); + } + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_3Thermo1HT_ThermoDevice::getAllChCJTemperature(void) +{ + IdiBusMMES MMES(static_cast(this->Module)->getAddress()); + MMES.DEV.NUM = IDIBUS_3Thermo1HT_THERMO_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x04; + uint8_t ChDataSize = 2; //int24_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_3Thermo1HT_Thermo_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_3Thermo1HT_Thermo_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_3Thermo1HT_Thermo_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_3Thermo1HT_Thermo_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->CH[I].Temperature = (int16_t) ( ((int16_t)MMES.RxData[DataPos]<<8) | + ((int16_t)MMES.RxData[DataPos+1]) ); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} + +void IdiBus_3Thermo1HT_ThermoDevice::setAllChErr(uint8_t ErrCode) +{ + for (uint8_t I=0; ICH[I].MMES_Error = ErrCode; } +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_3Thermo1HT.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_3Thermo1HT.h new file mode 100644 index 0000000..110b08b --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_3Thermo1HT.h @@ -0,0 +1,68 @@ +#ifndef IDIBUS_3Thermo1HT_H_ +#define IDIBUS_3Thermo1HT_H_ + +#include "IdiBusSlave.h" // Common slave defines +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_NO_SENSOR 100U +#define IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_NO_DATA 101U +#define IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_OVER_UNDER_VOLTAGE 102U +#define IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_TC_OUT_OF_RANGE 103U +#define IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_CJ_OUT_OF_RANGE 104U +#define IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_AUTOCONVERSION_ENABLED 105U +#define IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_ONESHOT_IN_PROGRESS 106U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_3Thermo1HT_MODULE_DEVICES_LIST { // Describe devices on module + IDIBUS_3Thermo1HT_THERMO_DEV = 0, // Thermocouple device ID + IDIBUS_3Thermo1HT_HEATER_DEV, // Heater device ID + IDIBUS_3Thermo1HT_DEVICES_NUMBER // Device count on module + }; + +enum { // Describe channel configuration for device (3Thermo1HT) + IDIBUS_3Thermo1HT_Thermo_CH0_NUM = 0, // Name for 1st channel + IDIBUS_3Thermo1HT_Thermo_CH1_NUM, // 2nd ... + IDIBUS_3Thermo1HT_Thermo_CH2_NUM, // + IDIBUS_3Thermo1HT_Thermo_CH_COUNT // Module channel count + }; + +class IdiBus_3Thermo1HT_ThermoChannel: public IdiBusChannel { + public: + IdiBus_3Thermo1HT_ThermoChannel(void); + int32_t Temperature; // Last temperature + int16_t CJTemperature; // Last temperature +}; + +class IdiBus_3Thermo1HT_ThermoDevice : public IdiBusDevice { + public: + IdiBus_3Thermo1HT_ThermoDevice (void *ParentModule) : IdiBusDevice (ParentModule) {} + + uint8_t startOneShotConversion(uint8_t ChNum); + uint8_t changeAutomatiocConversionState(uint8_t ChNum); + uint8_t getTemperature(uint8_t ChNum); + uint8_t getCJTemperature(uint8_t ChNum); + + void startAllOneShotConversions(); + void changeAllAutomatiocConversionStates(); + void getAllChTemperature(void); + void getAllChCJTemperature(void); + + + IdiBus_3Thermo1HT_ThermoChannel getChData(uint8_t ChNum); + + protected : + IdiBus_3Thermo1HT_ThermoChannel CH[IDIBUS_3Thermo1HT_Thermo_CH_COUNT]; + virtual IdiBusChannel *getChannel(uint8_t Num); + + void setAllChErr(uint8_t ErrCode); +}; + +class IdiBus_3Thermo1HT : public IdiBusSlave { + public: + IdiBus_3Thermo1HT (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress), THERMO_DEV(this)/*, INPV_DEV(this)*/ {} + IdiBus_3Thermo1HT() : IdiBusSlave(), THERMO_DEV(this)/*, INPV_DEV(this)*/ {} + + virtual IdiBusDevice *getDevice(uint8_t Num); + + IdiBus_3Thermo1HT_ThermoDevice THERMO_DEV; +}; + +#endif /* IDIBUS_43Thermo1HT_H_ */ \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4ADC.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4ADC.cpp new file mode 100644 index 0000000..6a97dc2 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4ADC.cpp @@ -0,0 +1,109 @@ +#include "IDIBUS_4ADC.h" + +IdiBus_4ADC::IdiBus_4ADC (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress) +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].Voltage = 0; + //this->CH[I].STATUS.Enable = 0; + } +} + +IdiBus_4ADC::IdiBus_4ADC () : IdiBusSlave() +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].Voltage = 0; + //this->CH[I].STATUS.Enable = 0; + } +} + +IDIBUS_4ADC_DATA_TYPE IdiBus_4ADC::getChData(uint8_t ChNum){ + if ( ChNum < IDIBUS_4ADC_CH_COUNT ) { return this->CH[ChNum]; } + else { return this->CH[IDIBUS_4ADC_CH4_NUM]; } +} + +uint8_t IdiBus_4ADC::getChVoltage(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_4ADC_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_4ADC_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x02; //Get Value + uint8_t ChDataSize = 2; //uint16_t + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Voltage = (uint16_t) ( ((uint16_t)MMES.RxData[1]<<8) | + ((uint16_t)MMES.RxData[2])); + } + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_4ADC::getAllAdcVoltage(void) +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_4ADC_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x02; + uint8_t ChDataSize = 2; //uint16_t + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4ADC_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4ADC_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4ADC_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4ADC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->CH[I].Voltage = (uint16_t) ( + (uint16_t)((uint16_t)MMES.RxData[DataPos] << 8) | + (uint16_t)((uint16_t)MMES.RxData[DataPos+1]) ); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} + +void IdiBus_4ADC::setAllChErr(uint8_t ErrCode) +{ + for (uint8_t I=0; ICH[I].MMES_Error = ErrCode; } +} + +void IdiBus_4ADC::initAllChs(void) +{ + //uint8_t TxData[2]; + //TxData[0] = (uint8_t)(CurrentLimit >> 8); + //TxData[1] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_4ADC_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x01; + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4ADC_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4ADC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + //if ( this->CH[I].MMES_Error == IDIER_NOPE ) + } + } +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4ADC.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4ADC.h new file mode 100644 index 0000000..6b99e61 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4ADC.h @@ -0,0 +1,46 @@ +#ifndef IDIBUS_4ADC_H_ +#define IDIBUS_4ADC_H_ + +#include "IdiBusSlave.h" // Common slave defines +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_ERCODE_ADC_NOT_INITED 100U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_4ADC_MODULE_DEVICES_LIST { // Describe devices on module + IDIBUS_4ADC_CNTRL_DEV = 0, // ADC device ID + IDIBUS_4ADC_DEVICES_NUMBER // Device count on module + }; + +enum { // Describe channel configuration for device (ADC) + IDIBUS_4ADC_CH1_NUM = 0, // Name for 1st channel + IDIBUS_4ADC_CH2_NUM, // 2nd ... + IDIBUS_4ADC_CH3_NUM, // + IDIBUS_4ADC_CH4_NUM, // + IDIBUS_4ADC_12V_NUM, // Name for 12v adc channel + IDIBUS_4ADC_24V_NUM, // Name for 24v adc channel + IDIBUS_4ADC_CH_COUNT, // Channel count + }; + +typedef struct { + uint16_t Voltage; // Last voltage + uint8_t MMES_Error; // Last error +} IDIBUS_4ADC_DATA_TYPE; // Data structure for ADC channels + +class IdiBus_4ADC : public IdiBusSlave { // ADC module class + public: // Public methods + IdiBus_4ADC ( IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); // Init object with specified bus line and addr + IdiBus_4ADC(); // init without specified line and addr (default value line=NULL,addr=1) + + uint8_t getChVoltage(uint8_t ChNum); // Sends MMES and gets Ch voltage (writes to CH structure and return error code) + void getAllAdcVoltage(void); // Sends MMES and gets all Ch voltages (writes to CH structure) + + void initAllChs(void); // Inits all adc channels on module + + IDIBUS_4ADC_DATA_TYPE getChData(uint8_t ChNum); // Returns data structure for ADC channel + + protected : // 'Private' methods and structures + IDIBUS_4ADC_DATA_TYPE CH[IDIBUS_4ADC_CH_COUNT]; // Data structure array + + void setAllChErr(uint8_t ErrCode); // Set error code for all channels +}; + +#endif /* IDIBUS_4ADC_H_ */ \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNT.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNT.cpp new file mode 100644 index 0000000..8b6d8c7 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNT.cpp @@ -0,0 +1,131 @@ +#include "IDIBUS_4CNT.h" + +IdiBus_4CNT::IdiBus_4CNT (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress) +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].Counter = 0; + //this->CH[I].STATUS.Enable = 0; + } +} + +IdiBus_4CNT::IdiBus_4CNT () : IdiBusSlave() +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].Counter = 0; + //this->CH[I].STATUS.Enable = 0; + } +} + +IDIBUS_4CNT_DATA_TYPE IdiBus_4CNT::getChData(uint8_t ChNum){ + if ( ChNum < IDIBUS_4CNT_CH_COUNT ) { return this->CH[ChNum]; } + else { return this->CH[IDIBUS_4CNT_CH4_NUM]; } +} + +uint8_t IdiBus_4CNT::getChCounts(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_4CNT_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_4CNT_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x02; //Get Value + uint8_t ChDataSize = 4; //uint32_t + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Counter = (uint32_t) ( + ((uint32_t)MMES.RxData[1] << 24) | + ((uint32_t)MMES.RxData[2] << 16) | + ((uint32_t)MMES.RxData[3] << 8 ) | + ((uint32_t)MMES.RxData[4]) ); + //this->CH[ChNum].Counter = tmp; + } + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_4CNT::getAllChsCounts(void) +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_4CNT_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x02; + uint8_t ChDataSize = 4; //uint32_t + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4CNT_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4CNT_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4CNT_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4CNT_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { + this->CH[I].Counter = (uint32_t) ( + ((uint32_t)MMES.RxData[DataPos] << 24) | + ((uint32_t)MMES.RxData[DataPos+1] << 16) | + ((uint32_t)MMES.RxData[DataPos+2] << 8 ) | + ((uint32_t)MMES.RxData[DataPos+3]) ); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} + +void IdiBus_4CNT::setAllChErr(uint8_t ErrCode) +{ + for (uint8_t I=0; ICH[I].MMES_Error = ErrCode; } +} + +uint8_t IdiBus_4CNT::initCh(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_4CNT_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_4CNT_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x01; //init + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_4CNT::initAllChs(void) +{ + //uint8_t TxData[2]; + //TxData[0] = (uint8_t)(CurrentLimit >> 8); + //TxData[1] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_4CNT_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x01; //init + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4CNT_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4CNT_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + //if ( this->CH[I].MMES_Error == IDIER_NOPE ) + } + } +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNT.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNT.h new file mode 100644 index 0000000..277dd22 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNT.h @@ -0,0 +1,44 @@ +#ifndef IDIBUS_4CNT_H_ +#define IDIBUS_4CNT_H_ + +#include "IdiBusSlave.h" // Common slave defines +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_ERCODE_COUNTER_CHANNEL_NOT_INITED 100U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_4CNT_MODULE_DEVICES_LIST { // Describe devices on module + IDIBUS_4CNT_CNTRL_DEV = 0, // COUNTER device ID + IDIBUS_4CNT_DEVICES_NUMBER // Device count on module + }; + +enum { // Describe channel configuration for device (COUNTER) + IDIBUS_4CNT_CH1_NUM = 0, // Name for 1st channel + IDIBUS_4CNT_CH2_NUM, // 2nd ... + IDIBUS_4CNT_CH3_NUM, // + IDIBUS_4CNT_CH4_NUM, // + IDIBUS_4CNT_CH_COUNT, // Channel count + }; + +typedef struct { + uint32_t Counter; // Last returned value + uint8_t MMES_Error; // Last error +} IDIBUS_4CNT_DATA_TYPE; // Data structure for COUNTER channels + +class IdiBus_4CNT : public IdiBusSlave { // COUNTER module class + public: // Public methods + IdiBus_4CNT ( IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); // Init object with specified bus line and addr + IdiBus_4CNT(); // init without specified line and addr (default value line=NULL,addr=1) + + uint8_t getChCounts(uint8_t ChNum); // Sends MMES and get Counts on ch (writes to CH structure and returns MMES error code) + void getAllChsCounts(void); // Sends MMES and get Counts on ch (writes to CH structure) + + uint8_t initCh(uint8_t ChNum); // Inits specified counter channel on module + void initAllChs(void); // Inits all counters on module + + IDIBUS_4CNT_DATA_TYPE getChData(uint8_t ChNum); // Returns data structure + + protected: // 'Private' methods and structures + IDIBUS_4CNT_DATA_TYPE CH[IDIBUS_4CNT_CH_COUNT]; // Data structure array + + void setAllChErr(uint8_t ErrCode); // Set error code for all channels +}; +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNTtoPWM.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNTtoPWM.cpp new file mode 100644 index 0000000..c6fa476 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNTtoPWM.cpp @@ -0,0 +1,158 @@ +#include "IDIBUS_4CNTtoPWM.h" + +IdiBus_4CNTtoPWM::IdiBus_4CNTtoPWM (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress) +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].PWM = 0; + //this->CH[I].STATUS.Enable = 0; + } +} + +IdiBus_4CNTtoPWM::IdiBus_4CNTtoPWM () : IdiBusSlave() +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].PWM = 0; + //this->CH[I].STATUS.Enable = 0; + } +} + +IDIBUS_4CNTtoPWM_DATA_TYPE IdiBus_4CNTtoPWM::getChData(uint8_t ChNum){ + if ( ChNum < IDIBUS_4CNTtoPWM_CH_COUNT ) { return this->CH[ChNum]; } + else { return this->CH[IDIBUS_4CNTtoPWM_CH4_NUM]; } +} + +uint8_t IdiBus_4CNTtoPWM::setChPwm(uint8_t ChNum, uint8_t pwm) +{ + if (ChNum >= IDIBUS_4CNTtoPWM_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + + uint8_t TxData[1]; + TxData[0] = pwm; + + IdiBusMMES MMES(this->Address, &TxData[0], 1); + MMES.DEV.NUM = IDIBUS_4CNTtoPWM_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x02; //Set Value + + uint8_t RequestError = this->SendRequestMMES(&MMES); + + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].PWM = pwm; + } + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_4CNTtoPWM::setAllChsPwm(void) +{ + uint8_t TxData[IDIBUS_4CNTtoPWM_CH_COUNT]; + + for (uint8_t I=0; ICH[I].PWM; + } + + IdiBusMMES MMES(this->Address, &TxData[0], IDIBUS_4CNTtoPWM_CH_COUNT); + MMES.DEV.NUM = IDIBUS_4CNTtoPWM_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x02; + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4CNTtoPWM_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4CNTtoPWM_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + //if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].TargetVoltage = TargetV[I]; } + } + } +} + +/* +void IdiBus_4CNTtoPWM::setAllChsCounts(void) +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_4CNTtoPWM_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x02; + uint8_t ChDataSize = 4; //uint32_t + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4CNTtoPWM_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4CNTtoPWM_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4CNTtoPWM_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4CNTtoPWM_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { + this->CH[I].Counter = (uint32_t) ( + ((uint32_t)MMES.RxData[DataPos] << 24) | + ((uint32_t)MMES.RxData[DataPos+1] << 16) | + ((uint32_t)MMES.RxData[DataPos+2] << 8 ) | + ((uint32_t)MMES.RxData[DataPos+3]) ); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} +*/ + +void IdiBus_4CNTtoPWM::setAllChErr(uint8_t ErrCode) +{ + for (uint8_t I=0; ICH[I].MMES_Error = ErrCode; } +} + +uint8_t IdiBus_4CNTtoPWM::initCh(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_4CNTtoPWM_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_4CNTtoPWM_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x01; //init + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_4CNTtoPWM::initAllChs(void) +{ + //uint8_t TxData[2]; + //TxData[0] = (uint8_t)(CurrentLimit >> 8); + //TxData[1] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_4CNTtoPWM_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x01; //init + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4CNTtoPWM_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4CNTtoPWM_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + //if ( this->CH[I].MMES_Error == IDIER_NOPE ) + } + } +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNTtoPWM.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNTtoPWM.h new file mode 100644 index 0000000..cac96a3 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4CNTtoPWM.h @@ -0,0 +1,46 @@ +#ifndef IDIBUS_4CNTtoPWMPWM_H_ +#define IDIBUS_4CNTtoPWMPWM_H_ + +#include "IdiBusSlave.h" // Common slave defines +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_ERCODE_COUNTER_CHANNEL_NOT_INITED 100U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_4CNTtoPWM_MODULE_DEVICES_LIST { // Describe devices on module + IDIBUS_4CNTtoPWM_CNTRL_DEV = 0, // COUNTER device ID + IDIBUS_4CNTtoPWM_DEVICES_NUMBER // Device count on module + }; + +enum { // Describe channel configuration for device (COUNTER) + IDIBUS_4CNTtoPWM_CH1_NUM = 0, // Name for 1st channel + IDIBUS_4CNTtoPWM_CH2_NUM, // 2nd ... + IDIBUS_4CNTtoPWM_CH3_NUM, // + IDIBUS_4CNTtoPWM_CH4_NUM, // + IDIBUS_4CNTtoPWM_CH_COUNT, // Channel count + }; + +typedef struct { + uint8_t PWM; // Last returned value + uint8_t MMES_Error; // Last error +} IDIBUS_4CNTtoPWM_DATA_TYPE; // Data structure for COUNTER channels + +class IdiBus_4CNTtoPWM : public IdiBusSlave { // COUNTER module class + public: // Public methods + IdiBus_4CNTtoPWM ( IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); // Init object with specified bus line and addr + IdiBus_4CNTtoPWM(); // init without specified line and addr (default value line=NULL,addr=1) + + uint8_t setChPwm(uint8_t ChNum, uint8_t pwm); // Sends MMES and get Counts on ch (writes to CH structure and returns MMES error code) + void setAllChsPwm(void); // Sends MMES and get Counts on ch (writes to CH structure) + + void setChPwmLocal(uint8_t ChNum, uint8_t pwm); + + uint8_t initCh(uint8_t ChNum); // Inits specified counter channel on module + void initAllChs(void); // Inits all counters on module + + IDIBUS_4CNTtoPWM_DATA_TYPE getChData(uint8_t ChNum); // Returns data structure + + protected: // 'Private' methods and structures + IDIBUS_4CNTtoPWM_DATA_TYPE CH[IDIBUS_4CNTtoPWM_CH_COUNT]; // Data structure array + + void setAllChErr(uint8_t ErrCode); // Set error code for all channels +}; +#endif diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4DC.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4DC.cpp new file mode 100644 index 0000000..83518fd --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4DC.cpp @@ -0,0 +1,663 @@ +//############################################################################################################################################################################################################# +#include "IDIBUS_4DC.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusDevice *IdiBus_4DC::getDevice(uint8_t Num) +{ + switch (Num) + { + case ( IDIBUS_PSU_CNTRL_DEV ) : { return &this->PSUC_DEV; } + case ( IDIBUS_INPV_CNTRL_DEV ) : { return &this->INPV_DEV; } + default : { return NULL; } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +IdiBus_4DC_PSUChannel::IdiBus_4DC_PSUChannel(void) : IdiBusChannel() +{ + this->TargetVoltage = 0; + this->CurrentLimit = 0; + this->Voltage = 0; + this->Current = 0; + this->STATUS.Enable = 0; + this->STATUS.PowerGood = 0; + this->STATUS.ERRORS.Sum = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusChannel *IdiBus_4DC_PSUCDevice::getChannel(uint8_t Num) +{ + if ( Num < IDIBUS_4DC_CH_COUNT ) { return &this->CH[Num]; } + else { return NULL; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBus_4DC_PSUChannel IdiBus_4DC_PSUCDevice::getChData(uint8_t ChNum) +{ + if ( ChNum < IDIBUS_4DC_CH_COUNT ) { return this->CH[ChNum]; } + else { IdiBus_4DC_PSUChannel NewData; return NewData; } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +IdiBus_4DC_INPVChannel::IdiBus_4DC_INPVChannel(void) : IdiBusChannel() +{ + this->InpVoltage = 0; + this->STATUS.Sum = 0; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusChannel *IdiBus_4DC_INPVCDevice::getChannel(uint8_t Num) +{ + if ( Num == 0 ) { return &this->INPV; } + else { return NULL; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBus_4DC_INPVChannel IdiBus_4DC_INPVCDevice::getChData(void) +{ + return this->INPV; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_INPVCDevice::getInputVoltage(void) +{ + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_INPV_CNTRL_DEV; + MMES.CHNL.NUM = 0; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_GET_INP_VOLTAGE; + uint8_t ChDataSize = IDIBUS_CUSTDEF_PSUINPV_MES_LENGTH; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->INPV.MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->INPV.MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->INPV.MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } +else { + this->INPV.MMES_Error = MMES.RxData[0]; + if ( this->INPV.MMES_Error == IDIER_NOPE ) + { + uint8_t *Data = &MMES.RxData[1]; + if ( (Data[IDIBUS_CUSTDEF_PSUINPV_STATE_Pos] & (1U << IDIBUS_CUSTDEF_PSUINPV_STATE_UV_Pos)) != 0 ) { this->INPV.STATUS.BF.Undervoltage = 1; } + else { this->INPV.STATUS.BF.Undervoltage = 0; } + if ( (Data[IDIBUS_CUSTDEF_PSUINPV_STATE_Pos] & (1U << IDIBUS_CUSTDEF_PSUINPV_STATE_OV_Pos)) != 0 ) { this->INPV.STATUS.BF.Overvoltage = 1; } + else { this->INPV.STATUS.BF.Overvoltage = 0; } + this->INPV.InpVoltage = (uint16_t)( (uint16_t)Data[IDIBUS_CUSTDEF_PSUINPV_VOLTAGE_Pos] << 8 ) | MMES.RxData[IDIBUS_CUSTDEF_PSUINPV_VOLTAGE_Pos + 1]; + } + } + return this->INPV.MMES_Error; +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::getChOutputVoltage(uint8_t ChNum) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_VOLTAGE; + uint8_t ChDataSize = 4; //int32_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Voltage = (int32_t) ( + (uint32_t)((uint32_t)MMES.RxData[1] << 24) | + (uint32_t)((uint32_t)MMES.RxData[2] << 16) | + (uint32_t)((uint32_t)MMES.RxData[3] << 8) | + (uint32_t)((uint32_t)MMES.RxData[4]) ); + } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::getAllChOutputVoltage(void) +{ + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_VOLTAGE; + uint8_t ChDataSize = 4; //int32_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4DC_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4DC_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->CH[I].Voltage = (int32_t) ( + (uint32_t)((uint32_t)MMES.RxData[DataPos] << 24) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+1] << 16) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+2] << 8) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+3]) ); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::getChOutputCurrent(uint8_t ChNum) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_CURRENT; + uint8_t ChDataSize = 4; //int32_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Current = (int32_t) ( + (uint32_t)((uint32_t)MMES.RxData[1] << 24) | + (uint32_t)((uint32_t)MMES.RxData[2] << 16) | + (uint32_t)((uint32_t)MMES.RxData[3] << 8) | + (uint32_t)((uint32_t)MMES.RxData[4]) ); + } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::getAllChOutputCurrent(void) +{ + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_CURRENT; + uint8_t ChDataSize = 4; //int32_t + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4DC_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4DC_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->CH[I].Current = (int32_t) ( + (uint32_t)((uint32_t)MMES.RxData[DataPos] << 24) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+1] << 16) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+2] << 8) | + (uint32_t)((uint32_t)MMES.RxData[DataPos+3]) ); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::getChStatus(uint8_t ChNum) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_STATUS; + uint8_t ChDataSize = IDIBUS_CUSTDEF_PSUCH_STBUF_SIZE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->parsePsuChState(&MMES.RxData[1], ChNum); } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::getAllChStatus(void) +{ + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_STATUS; + uint8_t ChDataSize = IDIBUS_CUSTDEF_PSUCH_STBUF_SIZE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4DC_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4DC_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->parsePsuChState(&MMES.RxData[DataPos], I); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::getChAllData(uint8_t ChNum) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_ALLDATA; + uint8_t ChDataSize = IDIBUS_CUSTDEF_PSUCH_STALLBUF_SIZE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->parsePsuChAllState(&MMES.RxData[1], ChNum); } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::getAllChAllData(void) +{ + IdiBusMMES MMES( static_cast(this->Module)->getAddress() ); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_ALLDATA; + uint8_t ChDataSize = IDIBUS_CUSTDEF_PSUCH_STALLBUF_SIZE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); return; } + else if (MMES.RxDataLength < IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + else { + uint8_t ExpDataLength = IDIBUS_4DC_CH_COUNT; // Errors + for (uint8_t I=0; IsetAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); return; } + } + uint8_t ErrorPos = 0; + uint8_t DataPos = ErrorPos + IDIBUS_4DC_CH_COUNT; + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[ErrorPos]; + ErrorPos = (uint8_t)(ErrorPos + 1); + if ( this->CH[I].MMES_Error == IDIER_NOPE ) + { + this->parsePsuChAllState(&MMES.RxData[DataPos], I); + DataPos = (uint8_t)(DataPos + ChDataSize); + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::setChState(uint8_t ChNum, uint8_t State) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + if ( State != 0 ) { State = IDIBUS_CUSTDEF_PSU_CH_STATE_ENABLE; } + else { State = IDIBUS_CUSTDEF_PSU_CH_STATE_DISABLE; } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &State, 1); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->CH[ChNum].STATUS.Enable = State; } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChState(uint8_t State) +{ + if ( State != 0 ) { State = IDIBUS_CUSTDEF_PSU_CH_STATE_ENABLE; } + else { State = IDIBUS_CUSTDEF_PSU_CH_STATE_DISABLE; } + + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &State, 1); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.CHNL.ALLSAME = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].STATUS.Enable = State; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChState(uint8_t Ch1State, uint8_t Ch2State, uint8_t Ch3State, uint8_t Ch4State) +{ + uint8_t State[IDIBUS_4DC_CH_COUNT] = { Ch1State, Ch2State, Ch3State, Ch4State }; + for (uint8_t I=0; I(this->Module)->getAddress() , &State[0], IDIBUS_4DC_CH_COUNT); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].STATUS.Enable = State[I]; } + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::setChVoltage(uint8_t ChNum, uint16_t TargetVoltage) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + if ( (TargetVoltage < IDIBUS_PSU_CH_TARG_V_MIN_mV) || (TargetVoltage > IDIBUS_PSU_CH_TARG_V_MAX_mV) ) + { + this->CH[ChNum].MMES_Error = IDIERMST_INVALID_TX_PARAM; + return IDIERMST_INVALID_TX_PARAM; + } + uint8_t TxData[2]; + TxData[0] = (uint8_t)(TargetVoltage >> 8); + TxData[1] = (uint8_t)(TargetVoltage); + + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_TARGET_VOLTAGE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->CH[ChNum].TargetVoltage = TargetVoltage; } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChVoltage(uint16_t TargetVoltage) +{ + if ( (TargetVoltage < IDIBUS_PSU_CH_TARG_V_MIN_mV) || (TargetVoltage > IDIBUS_PSU_CH_TARG_V_MAX_mV) ) { this->setAllPsuChErr(IDIERMST_INVALID_TX_PARAM); return; } + uint8_t TxData[2]; + TxData[0] = (uint8_t)(TargetVoltage >> 8); + TxData[1] = (uint8_t)(TargetVoltage); + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.CHNL.ALLSAME = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_TARGET_VOLTAGE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].TargetVoltage = TargetVoltage; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChVoltage(uint16_t TV_CH1, uint16_t TV_CH2, uint16_t TV_CH3, uint16_t TV_CH4) +{ + uint16_t TargetV[IDIBUS_4DC_CH_COUNT] = { TV_CH1, TV_CH2, TV_CH3, TV_CH4 }; + uint8_t TxData[IDIBUS_4DC_CH_COUNT * 2]; + for (uint8_t I=0, J=0; I> 8); + TxData[J+1] = (uint8_t)(TargetV[I]); + } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], IDIBUS_4DC_CH_COUNT * 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_TARGET_VOLTAGE; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].TargetVoltage = TargetV[I]; } + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::setChCurrentLimit(uint8_t ChNum, uint16_t CurrentLimit) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + if ( (CurrentLimit < IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MIN) || (CurrentLimit > IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MAX) ) + { + this->CH[ChNum].MMES_Error = IDIERMST_INVALID_TX_PARAM; + return IDIERMST_INVALID_TX_PARAM; + } + uint8_t TxData[2]; + TxData[0] = (uint8_t)(CurrentLimit >> 8); + TxData[1] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_CURRENT_LIMIT; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->CH[ChNum].CurrentLimit = CurrentLimit; } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChCurrentLimit(uint16_t CurrentLimit) +{ + if ( (CurrentLimit < IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MIN) || (CurrentLimit > IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MAX) ) { this->setAllPsuChErr(IDIERMST_INVALID_TX_PARAM); return; } + uint8_t TxData[2]; + TxData[0] = (uint8_t)(CurrentLimit >> 8); + TxData[1] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.CHNL.ALLSAME = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_CURRENT_LIMIT; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].CurrentLimit = CurrentLimit; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChCurrentLimit(uint16_t CL_CH1, uint16_t CL_CH2, uint16_t CL_CH3, uint16_t CL_CH4) +{ + uint16_t CurrentL[IDIBUS_4DC_CH_COUNT] = { CL_CH1, CL_CH2, CL_CH3, CL_CH4 }; + uint8_t TxData[IDIBUS_4DC_CH_COUNT * 2]; + for (uint8_t I=0, J=0; I> 8); + TxData[J+1] = (uint8_t)(CurrentL[I]); + } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], IDIBUS_4DC_CH_COUNT * 2); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_CURRENT_LIMIT; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].CurrentLimit = CurrentL[I]; } + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +uint8_t IdiBus_4DC_PSUCDevice::setChVoltageAndCurrentLimit(uint8_t ChNum, uint16_t TargetVoltage, uint16_t CurrentLimit) +{ + if ( ChNum >= IDIBUS_4DC_CH_COUNT ) { return IDIERMST_INVALID_CHN_NUM; } + if ( (CurrentLimit < IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MIN) || (CurrentLimit > IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MAX) || + (TargetVoltage < IDIBUS_PSU_CH_TARG_V_MIN_mV) || (TargetVoltage > IDIBUS_PSU_CH_TARG_V_MAX_mV) ) + { + this->CH[ChNum].MMES_Error = IDIERMST_INVALID_TX_PARAM; + return IDIERMST_INVALID_TX_PARAM; + } + uint8_t TxData[4]; + TxData[0] = (uint8_t)(TargetVoltage >> 8); + TxData[1] = (uint8_t)(TargetVoltage); + TxData[2] = (uint8_t)(CurrentLimit >> 8); + TxData[3] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 4); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_ALL; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength != 1 ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) { this->CH[ChNum].TargetVoltage = TargetVoltage; this->CH[ChNum].CurrentLimit = CurrentLimit; } + } + return this->CH[ChNum].MMES_Error; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChVoltageAndCurrentLimit(uint16_t TargetVoltage, uint16_t CurrentLimit) +{ + if ( (CurrentLimit < IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MIN) || (CurrentLimit > IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MAX) || + (TargetVoltage < IDIBUS_PSU_CH_TARG_V_MIN_mV) || (TargetVoltage > IDIBUS_PSU_CH_TARG_V_MAX_mV) ) { this->setAllPsuChErr(IDIERMST_INVALID_TX_PARAM); return; } + uint8_t TxData[4]; + TxData[0] = (uint8_t)(TargetVoltage >> 8); + TxData[1] = (uint8_t)(TargetVoltage); + TxData[2] = (uint8_t)(CurrentLimit >> 8); + TxData[3] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], 4); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.CHNL.ALLSAME = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_ALL; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].TargetVoltage = TargetVoltage; this->CH[I].CurrentLimit = CurrentLimit; } + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllChVoltageAndCurrentLimit(uint16_t VCH1, uint16_t CCH1, uint16_t VCH2, uint16_t CCH2, uint16_t VCH3, uint16_t CCH3, uint16_t VCH4, uint16_t CCH4) +{ + uint16_t CurrentL[IDIBUS_4DC_CH_COUNT] = { CCH1, CCH2, CCH3, CCH4 }; + uint16_t TargetV[IDIBUS_4DC_CH_COUNT] = { VCH1, VCH2, VCH3, VCH4 }; + uint8_t TxData[IDIBUS_4DC_CH_COUNT * 4]; + for (uint8_t I=0, J=0; I> 8); + TxData[J+1] = (uint8_t)(TargetV[I]); + TxData[J+2] = (uint8_t)(CurrentL[I] >> 8); + TxData[J+3] = (uint8_t)(CurrentL[I]); + } + IdiBusMMES MMES( static_cast(this->Module)->getAddress() , &TxData[0], IDIBUS_4DC_CH_COUNT * 4); + MMES.DEV.NUM = IDIBUS_PSU_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_ALL; + uint8_t RequestError = static_cast(this->Module)->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllPsuChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_4DC_CH_COUNT) { this->setAllPsuChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_4DC_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + if ( this->CH[I].MMES_Error == IDIER_NOPE ) { this->CH[I].TargetVoltage = TargetV[I]; this->CH[I].CurrentLimit = CurrentL[I]; } + } + } +} +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +void IdiBus_4DC_PSUCDevice::parsePsuChState(uint8_t *State, uint8_t ChNum) +{ + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_EN_Pos)) != 0 ) { this->CH[ChNum].STATUS.Enable = 1; } + else { this->CH[ChNum].STATUS.Enable = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_PG_Pos)) != 0 ) { this->CH[ChNum].STATUS.PowerGood = 1; } + else { this->CH[ChNum].STATUS.PowerGood = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_PERIPH_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.PeripheryError = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.PeripheryError = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OVERCURRENT_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.OvercurrentError = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.OvercurrentError = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OVERVOLTAGE_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.OvervoltageError = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.OvervoltageError = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OFFSTATELEAKAGE_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.OffStateCurrentLeakage = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.OffStateCurrentLeakage = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_MEMORY_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.MemoryError = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.MemoryError = 0; } + if ( (State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos] & (1U << IDIBUS_CUSTDEF_PSUCH_STBUF_ST_INPV_ERR_Pos)) != 0 ) { this->CH[ChNum].STATUS.ERRORS.BF.InpVoltageError = 1; } + else { this->CH[ChNum].STATUS.ERRORS.BF.InpVoltageError = 0; } + this->CH[ChNum].TargetVoltage = (uint16_t)( (uint16_t)((uint16_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_TARGET_VOLATGE_Pos] << 8) | State[IDIBUS_CUSTDEF_PSUCH_STBUF_TARGET_VOLATGE_Pos + 1] ); + this->CH[ChNum].CurrentLimit = (uint16_t)( (uint16_t)((uint16_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_CURRENT_LIMIT_Pos] << 8) | State[IDIBUS_CUSTDEF_PSUCH_STBUF_CURRENT_LIMIT_Pos + 1] ); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::parsePsuChAllState(uint8_t *State, uint8_t ChNum) +{ + this->parsePsuChState(&State[IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos], ChNum); + this->CH[ChNum].Voltage = (int32_t) ( + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos] << 24) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos + 1] << 16) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos + 2] << 8) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos + 3]) ); + this->CH[ChNum].Current = (int32_t) ( + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos] << 24) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos + 1] << 16) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos + 2] << 8) | + (uint32_t)((uint32_t)State[IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos + 3]) ); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void IdiBus_4DC_PSUCDevice::setAllPsuChErr(uint8_t ErrCode) +{ + for (uint8_t I=0; ICH[I].MMES_Error = ErrCode; } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//############################################################################################################################################################################################################# + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4DC.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4DC.h new file mode 100644 index 0000000..5806b2a --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_4DC.h @@ -0,0 +1,178 @@ +//############################################################################################################################################################################################################# +#ifndef _IDIBUS_4DC_H_ +#define _IDIBUS_4DC_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "IdiBusSlave.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_PSU_CH_STATE_DISABLE 0x00 +#define IDIBUS_CUSTDEF_PSU_CH_STATE_ENABLE 0x01 + +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE 0x01 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_VOLTAGE 0x02 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_CURRENT 0x03 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_STATUS 0x04 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_GET_ALLDATA 0x05 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_TARGET_VOLTAGE 0x06 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_CURRENT_LIMIT 0x07 +#define IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_ALL 0x08 +#define IDIBUS_CUSTDEF_FUNC_CODE_GET_INP_VOLTAGE 0x09 +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_ERCODE_INVALID_DATA 100U +#define IDIBUS_CUSTDEF_ERCODE_NO_ACCESS 101U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_PSUCH_GET_CV_MES_LENGTH 4U + +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_Pos 00U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_EN_Pos 0U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_PG_Pos 1U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_PERIPH_ERR_Pos 2U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OVERCURRENT_ERR_Pos 3U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OVERVOLTAGE_ERR_Pos 4U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_OFFSTATELEAKAGE_ERR_Pos 5U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_MEMORY_ERR_Pos 6U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_ST_INPV_ERR_Pos 7U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_TARGET_VOLATGE_Pos 01U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_CURRENT_LIMIT_Pos 03U +#define IDIBUS_CUSTDEF_PSUCH_STBUF_SIZE 05U + +#define IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos IDIBUS_CUSTDEF_PSUCH_STBUF_SIZE +#define IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos (IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_VOLTAGE_Pos + 4) +#define IDIBUS_CUSTDEF_PSUCH_STALLBUF_SIZE (IDIBUS_CUSTDEF_PSUCH_STBUF_OUTPUT_CURRENT_Pos + 4) +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_PSUINPV_STATE_Pos 00U +#define IDIBUS_CUSTDEF_PSUINPV_STATE_UV_Pos 0U +#define IDIBUS_CUSTDEF_PSUINPV_STATE_OV_Pos 1U +#define IDIBUS_CUSTDEF_PSUINPV_VOLTAGE_Pos 01U +#define IDIBUS_CUSTDEF_PSUINPV_MES_LENGTH (IDIBUS_CUSTDEF_PSUINPV_VOLTAGE_Pos + 2) +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_PSU_CH_TARG_V_MIN_mV 1500UL +#define IDIBUS_PSU_CH_TARG_V_MAX_mV 48000UL +#define IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MAX 10200UL +#define IDIBUS_PSU_CH_AVERAGE_CURRENT_LIMIT_MIN 100UL +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define PSU_INV_UNDERVOLTAGE_ERR_THR 10000U +#define PSU_INV_OVERVOLTAGE_ERR_THR 50000U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_MODULE_DEVICES_LIST { + IDIBUS_PSU_CNTRL_DEV = 0x00, + IDIBUS_INPV_CNTRL_DEV, + IDIBUS_DEVICES_NUMBER +}; +enum { + IDIBUS_4DC_CH1_NUM = 0, + IDIBUS_4DC_CH2_NUM, + IDIBUS_4DC_CH3_NUM, + IDIBUS_4DC_CH4_NUM, + IDIBUS_4DC_CH_COUNT + }; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +class IdiBus_4DC_PSUChannel : public IdiBusChannel { + public: + IdiBus_4DC_PSUChannel(void); + int32_t Voltage; + int32_t Current; + uint16_t TargetVoltage; + uint16_t CurrentLimit; + struct { + uint8_t Enable; + uint8_t PowerGood; + union { + uint8_t Sum; + struct { + uint8_t PeripheryError : 1; + uint8_t OvercurrentError : 1; + uint8_t OvervoltageError : 1; + uint8_t OffStateCurrentLeakage : 1; + uint8_t MemoryError : 1; + uint8_t InpVoltageError : 1; + uint8_t Reserved : 2; + } BF; + } ERRORS; + } STATUS; +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBus_4DC_PSUCDevice : public IdiBusDevice { + public : + IdiBus_4DC_PSUCDevice(void *ParentModule) : IdiBusDevice (ParentModule) {} + + uint8_t getChStatus(uint8_t ChNum); + void getAllChStatus(void); + + uint8_t getChOutputVoltage(uint8_t ChNum); + void getAllChOutputVoltage(void); + + uint8_t getChOutputCurrent(uint8_t ChNum); + void getAllChOutputCurrent(void); + + uint8_t getChAllData(uint8_t ChNum); + void getAllChAllData(void); + + uint8_t setChState(uint8_t ChNum, uint8_t State); + void setAllChState(uint8_t State); + void setAllChState(uint8_t Ch1State, uint8_t Ch2State, uint8_t Ch3State, uint8_t Ch4State); + + uint8_t setChVoltage(uint8_t ChNum, uint16_t TargetVoltage); + void setAllChVoltage(uint16_t TargetVoltage); + void setAllChVoltage(uint16_t TV_CH1, uint16_t TV_CH2, uint16_t TV_CH3, uint16_t TV_CH4); + + uint8_t setChCurrentLimit(uint8_t ChNum, uint16_t CurrentLimit); + void setAllChCurrentLimit(uint16_t CurrentLimit); + void setAllChCurrentLimit(uint16_t CL_CH1, uint16_t CL_CH2, uint16_t CL_CH3, uint16_t CL_CH4); + + uint8_t setChVoltageAndCurrentLimit(uint8_t ChNum, uint16_t TargetVoltage, uint16_t CurrentLimit); + void setAllChVoltageAndCurrentLimit(uint16_t TargetVoltage, uint16_t CurrentLimit); + void setAllChVoltageAndCurrentLimit(uint16_t VCH1, uint16_t CCH1, uint16_t VCH2, uint16_t CCH2, uint16_t VCH3, uint16_t CCH3, uint16_t VCH4, uint16_t CCH4); + + IdiBus_4DC_PSUChannel getChData(uint8_t ChNum); + protected : + IdiBus_4DC_PSUChannel CH[IDIBUS_4DC_CH_COUNT]; + virtual IdiBusChannel *getChannel(uint8_t Num); + void parsePsuChState(uint8_t *State, uint8_t ChNum); + void parsePsuChAllState(uint8_t *State, uint8_t ChNum); + void setAllPsuChErr(uint8_t ErrCode); + +}; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +class IdiBus_4DC_INPVChannel : public IdiBusChannel { + public: + IdiBus_4DC_INPVChannel(void); + uint16_t InpVoltage; + union { + uint8_t Sum; + struct { + uint8_t Undervoltage : 1; + uint8_t Overvoltage : 1; + uint8_t Reserved : 6; + } BF; + } STATUS; +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +class IdiBus_4DC_INPVCDevice : public IdiBusDevice { + public : + IdiBus_4DC_INPVCDevice (void *ParentModule) : IdiBusDevice (ParentModule) {} + uint8_t getInputVoltage(void); + IdiBus_4DC_INPVChannel getChData(void); + protected : + IdiBus_4DC_INPVChannel INPV; + virtual IdiBusChannel *getChannel(uint8_t Num); +}; +//============================================================================================================================================================================================================= +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//============================================================================================================================================================================================================= +class IdiBus_4DC : public IdiBusSlave { + public: + IdiBus_4DC (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress), PSUC_DEV(this), INPV_DEV(this) {} + IdiBus_4DC() : IdiBusSlave(), PSUC_DEV(this), INPV_DEV(this) {} + + virtual IdiBusDevice *getDevice(uint8_t Num); + + IdiBus_4DC_PSUCDevice PSUC_DEV; + IdiBus_4DC_INPVCDevice INPV_DEV; +}; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#endif //#define _IDIBUS_4DC_H_ +//############################################################################################################################################################################################################# diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_CO2.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_CO2.cpp new file mode 100644 index 0000000..a57b693 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_CO2.cpp @@ -0,0 +1,81 @@ +#include "IDIBUS_CO2.h" + +IdiBus_CO2::IdiBus_CO2 (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress) +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].Value = 0; + //this->CH[I].STATUS.Enable = 0; + } +} + +IdiBus_CO2::IdiBus_CO2 () : IdiBusSlave() +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].Value = 0; + //this->CH[I].STATUS.Enable = 0; + } +} + +IDIBUS_CO2_DATA_TYPE IdiBus_CO2::getChData(uint8_t ChNum){ + if ( ChNum < IDIBUS_CO2_CH_COUNT ) { return this->CH[ChNum]; } + else { return this->CH[IDIBUS_CO2_CH0_NUM]; } +} + +uint8_t IdiBus_CO2::getCO2(uint8_t ChNum) +{ + if (ChNum >= IDIBUS_CO2_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_CO2_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x01; //Get Value + uint8_t ChDataSize = 4; //uint32_t + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + this->CH[ChNum].Value = (uint32_t) ( ((uint32_t)MMES.RxData[1]<<24) | + ((uint32_t)MMES.RxData[2]<<16) | + ((uint32_t)MMES.RxData[3]<<8) | + ((uint32_t)MMES.RxData[4]) ); + } + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_CO2::setAllChErr(uint8_t ErrCode) +{ + for (uint8_t I=0; ICH[I].MMES_Error = ErrCode; } +} + +/* +void IdiBus_CO2::initAllChs(void) +{ + //uint8_t TxData[2]; + //TxData[0] = (uint8_t)(CurrentLimit >> 8); + //TxData[1] = (uint8_t)(CurrentLimit); + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_CO2_CNTRL_DEV; + MMES.DEV.ALLCH = 1; + MMES.ComFunc = 0x01; + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->setAllChErr(RequestError); } + else if (MMES.RxDataLength != IDIBUS_CO2_CH_COUNT) { this->setAllChErr(IDIERMST_INVALID_RX_REQUEST_FORMAT); } + else + { + for (uint8_t I = 0; I < IDIBUS_CO2_CH_COUNT; I++) + { + this->CH[I].MMES_Error = MMES.RxData[I]; + //if ( this->CH[I].MMES_Error == IDIER_NOPE ) + } + } +} +*/ diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_CO2.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_CO2.h new file mode 100644 index 0000000..f3d5595 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_CO2.h @@ -0,0 +1,41 @@ +#ifndef IDIBUS_CO2_H_ +#define IDIBUS_CO2_H_ + +#include "IdiBusSlave.h" // Common slave defines +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_CUSTDEF_ERCODE_CO2_CRC_ERROR 100U +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_CO2_MODULE_DEVICES_LIST { // Describe devices on module + IDIBUS_CO2_CNTRL_DEV = 0, // ADC device ID + IDIBUS_CO2_DEVICES_NUMBER // Device count on module + }; + +enum { // Describe channel configuration for device (CO2) + IDIBUS_CO2_CH0_NUM = 0, // Name for 1st channel + IDIBUS_CO2_CH_COUNT, // Module channel count + }; + +typedef struct { + uint32_t Value; // Last voltage + uint8_t MMES_Error; // Last error +} IDIBUS_CO2_DATA_TYPE; // Data structure for ADC channels + +class IdiBus_CO2 : public IdiBusSlave { // ADC module class + public: // Public methods + IdiBus_CO2 ( IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); // Init object with specified bus line and addr + IdiBus_CO2 (); // init without specified line and addr (default value line=NULL,addr=1) + + uint8_t getCO2(uint8_t ChNum); // Sends MMES and gets Ch voltage (writes to CH structure and return error code) + //void getAllChTemperature(void); // Sends MMES and gets all Ch voltages (writes to CH structure) + + //void initAllChs(void); // Inits all adc channels on module + + IDIBUS_CO2_DATA_TYPE getChData(uint8_t ChNum); // Returns data structure for ADC channel + + protected : // 'Private' methods and structures + IDIBUS_CO2_DATA_TYPE CH[IDIBUS_CO2_CH_COUNT]; // Data structure array + + void setAllChErr(uint8_t ErrCode); // Set error code for all channels +}; + +#endif /* IDIBUS_4CO2_H_ */ \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_NEXTION.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_NEXTION.cpp new file mode 100644 index 0000000..d92682c --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_NEXTION.cpp @@ -0,0 +1,52 @@ +#include "IDIBUS_NEXTION.h" + +IdiBus_NEXTION::IdiBus_NEXTION (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress) +{ + BRIDGE.MMES_Error = 0; + BRIDGE.RXlen = 0; +} + +IdiBus_NEXTION::IdiBus_NEXTION () : IdiBusSlave() +{ + BRIDGE.MMES_Error = 0; + BRIDGE.RXlen = 0; +} + +IDIBUS_NEXTION_DATA_TYPE IdiBus_NEXTION::getData(void) +{ + return this->BRIDGE; +} + +uint8_t IdiBus_NEXTION::getBuf() +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_NEXTION_CNTRL_DEV; + MMES.CHNL.NUM = 0; + MMES.ComFunc = 0x02; //Get Buf + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->BRIDGE.MMES_Error = RequestError; } + else { + this->BRIDGE.MMES_Error = MMES.RxData[0]; + this->BRIDGE.RXlen = MMES.RxDataLength-1; + memcpy(this->BRIDGE.RXbuf,&MMES.RxData[1],this->BRIDGE.RXlen); + } + return this->BRIDGE.MMES_Error; +} + +uint8_t IdiBus_NEXTION::sendBuf(uint8_t *buf, uint8_t len) +{ + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_NEXTION_CNTRL_DEV; + MMES.CHNL.NUM = 0; + MMES.ComFunc = 0x01; //Send Buf + MMES.TxDataLength = len; + MMES.TxData = buf; + uint8_t RequestError = this->SendRequestMMES(&MMES); + + if ( RequestError != IDIER_NOPE ) { this->BRIDGE.MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->BRIDGE.MMES_Error = MMES.RxData[0]; } + else { + this->BRIDGE.MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; + } + return this->BRIDGE.MMES_Error; +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_NEXTION.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_NEXTION.h new file mode 100644 index 0000000..79498e3 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_NEXTION.h @@ -0,0 +1,31 @@ +#ifndef IDIBUS_NEXTION_H_ +#define IDIBUS_NEXTION_H_ + +#include "IdiBusSlave.h" // Common slave defines +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +enum IDIBUS_NEXTION_MODULE_DEVICES_LIST { // Describe devices on module + IDIBUS_NEXTION_CNTRL_DEV = 0, // NEXTION device ID + IDIBUS_NEXTION_DEVICES_NUMBER // Device count on module + }; + +typedef struct { + uint8_t RXlen; + uint8_t RXbuf[255]; + uint8_t MMES_Error; // Last error +} IDIBUS_NEXTION_DATA_TYPE; + +class IdiBus_NEXTION : public IdiBusSlave { // NEXTION module class + public: // Public methods + IdiBus_NEXTION ( IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); // Init object with specified bus line and addr + IdiBus_NEXTION(); // init without specified line and addr (default value line=NULL,addr=1) + + uint8_t sendBuf(uint8_t *buf, uint8_t len); // Sends MMES and gets Ch voltage (writes to CH structure and return error code) + uint8_t getBuf(); + + IDIBUS_NEXTION_DATA_TYPE getData(void); + + protected : // 'Private' methods and structures + IDIBUS_NEXTION_DATA_TYPE BRIDGE; +}; + +#endif /* IDIBUS_NEXTION_H_ */ \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_Speedster.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_Speedster.cpp new file mode 100644 index 0000000..4eafeed --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_Speedster.cpp @@ -0,0 +1,81 @@ +#include "IDIBUS_Speedster.h" + +IdiBus_Test::IdiBus_Test (IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress) : IdiBusSlave(SlaveLine, SlaveAddress) +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].state = 0x1040FF0A; //Start seed + for (uint16_t i = 0; i < 256; i++){ + this->CH[I].RNG[i] = 0; + this->CH[I].DATA[i] = 0; + } + //this->CH[I].STATUS.Enable = 0; + } +} + +IdiBus_Test::IdiBus_Test () : IdiBusSlave() +{ + for (uint8_t I=0; ICH[I].MMES_Error = 0; + this->CH[I].state = 0x1040FF0A; //Start seed + for (uint16_t i = 0; i < 256; i++){ + this->CH[I].RNG[i] = 0; + this->CH[I].DATA[i] = 0; + } + //this->CH[I].STATUS.Enable = 0; + } +} + +IDIBUS_Test_DATA_TYPE IdiBus_Test::getChData(uint8_t ChNum){ + if ( ChNum < IDIBUS_Test_CH_COUNT ) { return this->CH[ChNum]; } + else { return this->CH[IDIBUS_Test_CH_COUNT-1]; } +} + +uint8_t IdiBus_Test::sendPacket(uint8_t ChNum) +{ + //Generate random sequence + this->CH[ChNum].state = this->xorshift32(this->CH[ChNum].state,this->CH[ChNum].RNG); + + if (ChNum >= IDIBUS_Test_CH_COUNT) { return IDIERMST_INVALID_CHN_NUM; } + IdiBusMMES MMES(this->Address); + MMES.DEV.NUM = IDIBUS_Test_CNTRL_DEV; + MMES.CHNL.NUM = ChNum; + MMES.ComFunc = 0x01; //Send packet + MMES.TxDataLength = 256; + MMES.TxData = this->CH[ChNum].RNG; + uint16_t ChDataSize = 256; //uint8_t[256] + uint8_t RequestError = this->SendRequestMMES(&MMES); + if ( RequestError != IDIER_NOPE ) { this->CH[ChNum].MMES_Error = RequestError; } + else if ( MMES.RxDataLength == 1 ) { this->CH[ChNum].MMES_Error = MMES.RxData[0]; } + else if ( MMES.RxDataLength != (ChDataSize + 1) ) { this->CH[ChNum].MMES_Error = IDIERMST_INVALID_RX_REQUEST_FORMAT; } + else { + this->CH[ChNum].MMES_Error = MMES.RxData[0]; + if ( this->CH[ChNum].MMES_Error == IDIER_NOPE ) + { + for (uint16_t i = 0; i < 256; i++) + this->CH[ChNum].DATA[i] = MMES.RxData[i+1]; + } + } + return this->CH[ChNum].MMES_Error; + +} + +void IdiBus_Test::setAllChErr(uint8_t ErrCode) +{ + for (uint8_t I=0; ICH[I].MMES_Error = ErrCode; } +} + +uint32_t IdiBus_Test::xorshift32(uint32_t state,uint8_t *data) { + for (uint8_t i = 0; i < 256/4; i++){ + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + data[i*4+0] = (uint8_t)state; + data[i*4+1] = (uint8_t)(state>>8); + data[i*4+2] = (uint8_t)(state>>16); + data[i*4+3] = (uint8_t)(state>>24); + } + return state; +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_Speedster.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_Speedster.h new file mode 100644 index 0000000..6d521cb --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/IdiBusSlaves/IDIBUS_Speedster.h @@ -0,0 +1,38 @@ +#ifndef IDIBUS_Test_H_ +#define IDIBUS_Test_H_ + +#include "IdiBusSlave.h" // Common slave defines +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#define IDIBUS_Test_CH_COUNT 1 + +enum IDIBUS_Test_MODULE_DEVICES_LIST { // Describe devices on module + IDIBUS_Test_CNTRL_DEV = 0, // ADC device ID + IDIBUS_Test_DEVICES_NUMBER // Device count on module + }; + +typedef struct { + uint8_t RNG[256]; + uint8_t DATA[256]; + uint8_t MMES_Error; // Last error + uint32_t state; +} IDIBUS_Test_DATA_TYPE; // Data structure for ADC channels + +class IdiBus_Test : public IdiBusSlave { // ADC module class + public: // Pulic methods + IdiBus_Test ( IdiBusSerialLine *SlaveLine, uint8_t SlaveAddress); // Init object with specified bus line and addr + IdiBus_Test (); // init without specified line and addr (default value line=NULL,addr=1) + + uint8_t sendPacket(uint8_t ChNum); // Sends MMES and gets Ch voltage (writes to CH structure and return error code) + //void getAllChTemperature(void); // Sends MMES and gets all Ch voltages (writes to CH structure) + + //void initAllChs(void); // Inits all adc channels on module + + IDIBUS_Test_DATA_TYPE getChData(uint8_t ChNum); // Returns data structure for ADC channel + + protected : // 'Private' methods and structures + IDIBUS_Test_DATA_TYPE CH[IDIBUS_Test_CH_COUNT]; // Data structure array + uint32_t xorshift32(uint32_t state,uint8_t *data); + void setAllChErr(uint8_t ErrCode); // Set error code for all channels +}; + +#endif /* IDIBUS_41Wire_H_ */ \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/MBOARD_POWER.c b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/MBOARD_POWER.c new file mode 100644 index 0000000..15d8808 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/MBOARD_POWER.c @@ -0,0 +1,66 @@ +//###################################################################################################################################################################################################### +// MBOARD_POWER.C +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +//#include "MBOARD_POWER.h" + +uint8_t MBOARD_POWER_SET(uint8_t juction, uint8_t set) // power channel ON/OFF +{ +Serial3.begin(115200,SERIAL_8N1); // usart3 for 328pb on MBoard +uint8_t string[2]; +if((juction==MBOARD_POWER_J89_05V)&&(set==MBOARD_POWER_ON)) + { + Serial3.print("5+"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J89_05V)&&(set==MBOARD_POWER_OFF)) + { + Serial3.print("5-"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J89_24V)&&(set==MBOARD_POWER_ON)) + { + Serial3.print("J+"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J89_24V)&&(set==MBOARD_POWER_OFF)) + { + Serial3.print("J-"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J67_24V)&&(set==MBOARD_POWER_ON)) + { + Serial3.print("R+"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J67_24V)&&(set==MBOARD_POWER_OFF)) + { + Serial3.print("R-"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } +while(Serial3.available()>0) string[0]=Serial3.read(); +return MBOARD_POWER_ERR; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +void MBOARD_POWER_OFF_ON(void) // , +{ +MBOARD_POWER_SET(MBOARD_POWER_J89_05V, MBOARD_POWER_OFF); +MBOARD_POWER_SET(MBOARD_POWER_J89_24V, MBOARD_POWER_OFF); +MBOARD_POWER_SET(MBOARD_POWER_J67_24V, MBOARD_POWER_OFF); +delay(1000);wdt_reset(); +MBOARD_POWER_SET(MBOARD_POWER_J89_05V, MBOARD_POWER_ON); +delay(500);wdt_reset(); +MBOARD_POWER_SET(MBOARD_POWER_J89_24V, MBOARD_POWER_ON); +delay(500);wdt_reset(); +MBOARD_POWER_SET(MBOARD_POWER_J67_24V, MBOARD_POWER_ON); +delay(1000);wdt_reset(); +return; +} +//###################################################################################################################################################################################################### + + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/MBOARD_POWER.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/MBOARD_POWER.h new file mode 100644 index 0000000..5443da9 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/MBOARD_POWER.h @@ -0,0 +1,29 @@ +//###################################################################################################################################################################################################### +// MBOARD_POWER.H +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +//#include "IdiBusLib/IdiBusSlave.h" +#include +#include +#include +#include +#include +//#include "../ArduinoCore/include/core/HardwareSerial.h" + +#ifndef _MBOARD_POWER_H_ +#define _MBOARD_POWER_H_ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +#define MBOARD_POWER_J89_05V 0x01 +#define MBOARD_POWER_J89_24V 0x02 +#define MBOARD_POWER_J67_24V 0x03 +#define MBOARD_POWER_ON 0x01 +#define MBOARD_POWER_OFF 0x00 +#define MBOARD_POWER_OK 0x00 +#define MBOARD_POWER_ERR 0x01 + +#define SERIAL_8N1 0x06 +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +uint8_t MBOARD_POWER_SET(uint8_t juction, uint8_t set); +void MBOARD_POWER_OFF_ON(void); +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +#endif //_MBOARD_POWER_H_ +//###################################################################################################################################################################################################### \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/PID.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/PID.cpp new file mode 100644 index 0000000..e53216f --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/PID.cpp @@ -0,0 +1,27 @@ +#include "PID.h" + +PID::PID () +{ + lastCalculationTime = 0; + lastValue = 0; + integratedI = 0.; +} + + +uint8_t PID::calculatePID(int32_t value){ + uint32_t time = millis(); + + int32_t error = Target - value; + int16_t errorConstrained = constrain(error,-2550,2550); + + integratedI = constrain(integratedI + ((float)errorConstrained)*I,-255.,255.); + + float speed = (lastValue - value) / (((float)(time-lastCalculationTime))/1000.); + lastCalculationTime = time; + lastValue = value; + + float calculation = ((float)error)*P + integratedI + speed*D; + + return (uint8_t)(constrain(calculation,0.,255.)); +} + diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/PID.h b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/PID.h new file mode 100644 index 0000000..16f5e78 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/PID.h @@ -0,0 +1,25 @@ +#ifndef PID_H_ +#define PID_H_ + +#include "Arduino.h" + +class PID { + public: + PID(); + + int32_t Target; + float P; + float I; + float D; + + uint8_t calculatePID(int32_t value); + + private: + uint32_t lastCalculationTime; + int32_t lastValue; + float integratedI; + }; + + + +#endif /* PID_H_ */ \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/Sketch.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/Sketch.cpp new file mode 100644 index 0000000..2f8ff3d --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/Sketch.cpp @@ -0,0 +1,311 @@ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#ifdef F_CPU +#undef F_CPU +#endif +#define F_CPU 16000000UL +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +#include "IdiBusSerialLine.h" +#include "IDIBUS_4DC.h" +#include "IDIBUS_4ADC.h" +#include "IDIBUS_4CNT.h" +#include "IDIBUS_1Wire.h" +#include "IDIBUS_3Thermo1HT.h" +#include "IDIBUS_Speedster.h" +#include "IDIBUS_1xGen.h" +#include "MBOARD_POWER.h" +#include + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//IDIBUS MASTER V0.26 beta +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSerialLine Serial_Line0; +IdiBusSerialLine Serial_Line1; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void setup() +{ + MBOARD_POWER_OFF_ON(); + delay(50); // Power on delay for external periphery + + //Arduino Variant + IDIBUS_SERIAL_INIT_TYPEDEF L0Init; + L0Init.USART_NUMBER = IDIBUS_SERIAL_USART2; // select USART + L0Init.TIMER_NUMBER = IDIBUS_TIMER_1; // select timer + L0Init.CONFIG = IDIBUS_SERIAL_8N2; // 8 bit, 2 stop + L0Init.RS485_DIR_PIN = 6; // direction pin in-out + L0Init.BAUDRATE_DIPSW_S0_PIN = 9; // speed selector pins + L0Init.BAUDRATE_DIPSW_S1_PIN = 8; + L0Init.BAUDRATE_DIPSW_S2_PIN = 7; + Serial_Line0.Init(&L0Init); // Init line with with config above + Serial_Line0.UpdateBaudrateFromDipSwitch(); // speed setup + Serial_Line0.Start(); // run! + + // Standard pinout variant + IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF L1Init; + L1Init.USART_NUMBER = IDIBUS_SERIAL_USART1; + L1Init.TIMER_NUMBER = IDIBUS_TIMER_3; + L1Init.CONFIG = IDIBUS_SERIAL_8N2; + L1Init.RS485_DIR_GPIO.PORT = &PORTL; + L1Init.RS485_DIR_GPIO.PIN_NUM = 6; + L1Init.BAUDRATE_DIPSW.S0.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S0.PIN_NUM = 1; + L1Init.BAUDRATE_DIPSW.S1.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S1.PIN_NUM = 0; + L1Init.BAUDRATE_DIPSW.S2.PORT = &PORTL; + L1Init.BAUDRATE_DIPSW.S2.PIN_NUM = 7; + Serial_Line1.Init(&L1Init); + Serial_Line1.UpdateBaudrateFromDipSwitch(); + Serial_Line1.Start(); + + //Serial.begin(115200,SERIAL_8N2); // usart0 for debug + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + // Enable power out 24V on main board (to slaves) + //#define BAUD 16000000UL/16/250000UL-1 // BAUD speed = 250000 bod + //UBRR3 = (uint16_t)(BAUD); // USART BAUD RATE INIT + //UCSR3B = (1<> 8) & 0xFF), (uint8_t)(Settings.first_mode_pwm_value & 0xFF), + Settings.first_mode_f, Settings.first_mode_invert, + Settings.second_mode_time, + (uint8_t)((Settings.second_mode_pwm_value >> 8) & 0xFF), (uint8_t)(Settings.second_mode_pwm_value & 0xFF), + Settings.second_mode_f, Settings.second_mode_invert}; + + TEMP.start_SPI(TxData); + //TEMP.reset_STM(); + + Serial_Line1.UpdateBaudrateFromDipSwitch(); + Serial_Line0.UpdateBaudrateFromDipSwitch(); +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +/* +struct Statistic{ + uint32_t Ok; + uint32_t Lost; + uint32_t Broken; + uint32_t Total; +}; + +Statistic stats[6]; +uint8_t PacketCounter; +IdiBus_Test IDITEST[6]; +*/ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void loop() +{ + +/* + PacketCounter = 0; + const uint8_t baseAddr = 80; + const uint8_t num = 4; + for (uint8_t addr = 0; addr < num; addr++){ + if ((addr&1) == 0) + IDITEST[addr] = IdiBus_Test(&Serial_Line0,baseAddr+(addr>>1)); + else + IDITEST[addr] = IdiBus_Test(&Serial_Line1,baseAddr+(addr>>1)); + stats[addr].Ok = 0; + stats[addr].Lost = 0; + stats[addr].Broken = 0; + stats[addr].Total = 0; + } + + for (uint8_t addr = 0; addr < num;) { + ErrorCode = IDITEST[addr].c_Init(); + delay(1000); + if (ErrorCode != IDIER_NOPE) { + Serial.print("[ERROR] Unable to init module "); + Serial.print(1<<((addr>>1)+5)); + Serial.print(" | Line "); + Serial.print(addr&1); + Serial.print(". Check the connection! \n"); + delay(1000); + } else + addr++; + } + Serial.write("[INFO] Modules inited successfully\n"); + + while(1) { + for (uint8_t id = 0; id < num; id++){ + ErrorCode = IDITEST[id].sendPacket(0); + + Statistic *stat = &stats[id]; + stat->Total++; + + if (ErrorCode == IDIERMST_RCV_TIMEOUT) { + stat->Lost++; + } else if (ErrorCode != IDIER_NOPE) { + stat->Broken++; + } else { + IDIBUS_Test_DATA_TYPE data = IDITEST[id].getChData(0); + + uint8_t fail = 0; + + for (uint16_t i = 0; i < 256; i++){ + if (data.DATA[i] != data.RNG[i]) { + fail = 1; + break; + } + } + + if (fail == 1) + stat->Broken++; + else + stat->Ok++; + } + } + + PacketCounter++; + if (PacketCounter == 8) { + for (uint8_t id = 0; id < num; id++){ + Serial.print("[INFO] Module #"); + Serial.print(baseAddr+(id>>1)); + Serial.print(" Line:"); + Serial.print(id&1); + Serial.print(" | "); + Serial.print(stats[id].Ok); + Serial.print(" | "); + Serial.print(stats[id].Lost); + Serial.print(" | "); + Serial.print(stats[id].Broken); + Serial.print(" | "); + Serial.println(stats[id].Total); + } + PacketCounter = 0; + Serial_Line0.UpdateBaudrateFromDipSwitch(); + Serial_Line1.UpdateBaudrateFromDipSwitch(); + } + } + */ +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + /* + Egor code for loop function + + IdiBus_4DC IDB4DC(&Serial_Line1, 122); + + ErrorCode = IDB4DC.c_Init(); + delay(1000); + ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 0, 10); + ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 2, 10); + + uint8_t TxData; + IdiBusMMESG Group1(IDIBUS_GROUP_10_ADDR, &TxData, 1); + Group1.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + + while (1) + { + Serial.write((uint8_t*)"echo", sizeof("echo")-1); + + TxData = 0; + Serial_Line1.sendMMESG(&Group1); + delay(2000); + TxData = 1; + Serial_Line1.sendMMESG(&Group1); + delay(2000); + }*/ + +/* + ErrorCode[0] = IDB4DC.c_Init(); + delay(1000); + ErrorCode[1] = IDB4DC.c_WriteSnIPv4IPv6(0xAABBCCDD, 0xA1A2A3A4, 0xA5A6A7A8, 0xB1B2B3B4, 0xB5B6B7B8); + do { ErrorCode[2] = IDB4DC.c_CheckModuleLongOp(); } + while ( (LopData = IDB4DC.getModuleLongOpData()).State == IDILONGOP_STATE_IN_PROC ); + + ErrorCode[3] = IDB4DC.INPV_DEV.getInputVoltage(); + INPV_Data = IDB4DC.INPV_DEV.getChData(); + + IDB4DC.PSUC_DEV.setAllChVoltage(5000, 6000, 7000, 8000); + IDB4DC.PSUC_DEV.setAllChState(1); + while (1) + { + IDB4DC.PSUC_DEV.setAllChState(0, 1, 0, 1); + delay(2000); + IDB4DC.PSUC_DEV.setAllChState(1, 0, 1, 0); + delay(2000); + } +*/ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +uint8_t MBOARD_POWER_SET(uint8_t juction, uint8_t set) // power channel ON/OFF +{ + Serial3.begin(115200,SERIAL_8N1); // usart3 for 328pb on MBoard + uint8_t string[2]; + if((juction==MBOARD_POWER_J89_05V)&&(set==MBOARD_POWER_ON)) + { + Serial3.print("5+"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J89_05V)&&(set==MBOARD_POWER_OFF)) + { + Serial3.print("5-"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J89_24V)&&(set==MBOARD_POWER_ON)) + { + Serial3.print("J+"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J89_24V)&&(set==MBOARD_POWER_OFF)) + { + Serial3.print("J-"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J67_24V)&&(set==MBOARD_POWER_ON)) + { + Serial3.print("R+"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + else if((juction==MBOARD_POWER_J67_24V)&&(set==MBOARD_POWER_OFF)) + { + Serial3.print("R-"); delay(10); + Serial3.readBytes(string, 2); + if((string[0]=='O')&&(string[1]=='K')) return MBOARD_POWER_OK; + } + while(Serial3.available()>0) string[0]=Serial3.read(); + return MBOARD_POWER_ERR; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +void MBOARD_POWER_OFF_ON(void) // выключение, пауза и последовательное включение всех питаний +{ + MBOARD_POWER_SET(MBOARD_POWER_J89_05V, MBOARD_POWER_OFF); + MBOARD_POWER_SET(MBOARD_POWER_J89_24V, MBOARD_POWER_OFF); + MBOARD_POWER_SET(MBOARD_POWER_J67_24V, MBOARD_POWER_OFF); + delay(1000);wdt_reset(); + MBOARD_POWER_SET(MBOARD_POWER_J89_05V, MBOARD_POWER_ON); + delay(500);wdt_reset(); + MBOARD_POWER_SET(MBOARD_POWER_J89_24V, MBOARD_POWER_ON); + delay(500);wdt_reset(); + MBOARD_POWER_SET(MBOARD_POWER_J67_24V, MBOARD_POWER_ON); + delay(1000);wdt_reset(); + return; +} \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchBack.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchBack.cpp new file mode 100644 index 0000000..a303319 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchBack.cpp @@ -0,0 +1,299 @@ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#ifdef F_CPU +#undef F_CPU +#endif +#define F_CPU 16000000UL +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +#include "IdiBusSerialLine.h" +#include "IDIBUS_4DC.h" +#include "IDIBUS_4ADC.h" +#include "IDIBUS_4CNT.h" +#include "IDIBUS_1Wire.h" +#include "IDIBUS_3Thermo1HT.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +//IDIBUS MASTER V0.26 beta + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSerialLine Serial_Line0; +IdiBusSerialLine Serial_Line1; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void setup() +{ + delay(50); // Power on delay for external periphery + + //Arduino Variant + IDIBUS_SERIAL_INIT_TYPEDEF L0Init; + L0Init.USART_NUMBER = IDIBUS_SERIAL_USART2; // select USART + L0Init.TIMER_NUMBER = IDIBUS_TIMER_1; // select timer + L0Init.CONFIG = IDIBUS_SERIAL_8N2; // 8 bit, 2 stop + L0Init.RS485_DIR_PIN = 6; // direction pin in-out + L0Init.BAUDRATE_DIPSW_S0_PIN = 9; // speed selector pins + L0Init.BAUDRATE_DIPSW_S1_PIN = 8; + L0Init.BAUDRATE_DIPSW_S2_PIN = 7; + Serial_Line0.Init(&L0Init); // Init line with with config above + Serial_Line0.UpdateBaudrateFromDipSwitch(); // speed setup + Serial_Line0.Start(); // run! + + // Standard pinout variant + IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF L1Init; + L1Init.USART_NUMBER = IDIBUS_SERIAL_USART1; + L1Init.TIMER_NUMBER = IDIBUS_TIMER_3; + L1Init.CONFIG = IDIBUS_SERIAL_8N2; + L1Init.RS485_DIR_GPIO.PORT = &PORTL; + L1Init.RS485_DIR_GPIO.PIN_NUM = 6; + L1Init.BAUDRATE_DIPSW.S0.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S0.PIN_NUM = 1; + L1Init.BAUDRATE_DIPSW.S1.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S1.PIN_NUM = 0; + L1Init.BAUDRATE_DIPSW.S2.PORT = &PORTL; + L1Init.BAUDRATE_DIPSW.S2.PIN_NUM = 7; + Serial_Line1.Init(&L1Init); + Serial_Line1.UpdateBaudrateFromDipSwitch(); + Serial_Line1.Start(); + + Serial.begin(19200,SERIAL_8N2); // usart0 for debug + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + // Enable power out 24V on main board (to slaves) + #define BAUD 16000000UL/16/250000UL-1 // BAUD speed = 250000 bod + UBRR3 = (uint16_t)(BAUD); // USART BAUD RATE INIT + UCSR3B = (1<0) Serial.write('+'); + else Serial.write('-'); + Serial.write('0'+(temperature/1000)%10); + Serial.write('0'+(temperature/100)%10); + Serial.write('.'); + Serial.write('0'+(temperature/10)%10); + Serial.write('0'+(temperature)%10); + Serial.write(' '); + } + else + { + Serial.write('T'); + Serial.write('1'+ch_num); + if (ErrorCode[3] == IDIBUS_CUSTDEF_ERCODE_OneWIRE_CHANNEL_CRC_ERROR) Serial.write(": ERR-CRC "); + else if (ErrorCode[3] == IDIBUS_CUSTDEF_ERCODE_OneWIRE_CHANNEL_NO_DATA) Serial.write(": ERR-DAT "); + else if (ErrorCode[3] == IDIBUS_CUSTDEF_ERCODE_OneWIRE_CHANNEL_NO_SENSOR) Serial.write(": ERR-SEN "); + else { + Serial.write(": ERR_"); + Serial.write('0'+(ErrorCode[3]/100)%10); + Serial.write('0'+(ErrorCode[3]/10)%10); + Serial.write('0'+(ErrorCode[3]/1)%10); + Serial.write(" "); + } + } + } + Serial.write('\n'); // Send new line char to serial + + if (GROUP_READ) IDB3TH1HT.THERMO_DEV.getAllChTemperature(); // read CNT counts, all channels + Serial.write(" 3TH1HT : "); + for (int ch_num = 0; ch_num < IDIBUS_3Thermo1HT_Thermo_CH_COUNT; ch_num++) + { + if (!GROUP_READ) ErrorCode[3] = IDB3TH1HT.THERMO_DEV.getTemperature(ch_num); // read CNT count, single channel, you can check ErrorCode[3] + else ErrorCode[3] = IDB3TH1HT.THERMO_DEV.getChData(ch_num).MMES_Error; // or IDB4CNT.getChData(CH_number).MMES_Error for group read + + if ( ErrorCode[3] == IDIER_NOPE ) // Check error code for single channel read + {temperature = IDB3TH1HT.THERMO_DEV.getChData(ch_num).Temperature>>7; + Serial.write('T'); + Serial.write('1'+ch_num); + Serial.write(':'); + if (temperature>0) Serial.write('+'); + else Serial.write('-'); + Serial.write('0'+(temperature/1000)%10); + Serial.write('0'+(temperature/100)%10); + Serial.write('0'+(temperature/10)%10); + Serial.write('0'+(temperature)%10); + Serial.write(' '); + } + else { + Serial.write('T'); + Serial.write('1'+ch_num); + if (ErrorCode[3] == IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_NO_DATA) Serial.write(": ERR-nDATA "); + else if (ErrorCode[3] == IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_NO_SENSOR) Serial.write(": ERR-nSENS "); + else if (ErrorCode[3] == IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_CJ_OUT_OF_RANGE) Serial.write(": ERR-CJOoR "); + else if (ErrorCode[3] == IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_TC_OUT_OF_RANGE) Serial.write(": ERR-TCOoR "); + else if (ErrorCode[3] == IDIBUS_CUSTDEF_ERCODE_THERMO_CHANNEL_OVER_UNDER_VOLTAGE) Serial.write(": ERR-O/U V "); + else { + Serial.write(": ERR_"); + Serial.write('0'+(ErrorCode[3]/100)%10); + Serial.write('0'+(ErrorCode[3]/10)%10); + Serial.write('0'+(ErrorCode[3]/1)%10); + Serial.write(" "); + } + } + } + Serial.write('\n'); // Send new line char to serial + + Serial_Line0.UpdateBaudrateFromDipSwitch(); // Update master speed (DEBUG only) + delay(100); + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + /* + Egor code for loop function + + IdiBus_4DC IDB4DC(&Serial_Line1, 122); + + //ErrorCode = IDB4DC.c_Init(10); + ErrorCode = IDB4DC.c_Init(); + delay(1000); + ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 0, 10); + ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 2, 10); + + uint8_t TxData; + IdiBusMMESG Group1(IDIBUS_GROUP_10_ADDR, &TxData, 1); + Group1.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + + while (1) + { + Serial.write((uint8_t*)"echo", sizeof("echo")-1); + + TxData = 0; + Serial_Line1.sendMMESG(&Group1); + delay(2000); + TxData = 1; + Serial_Line1.sendMMESG(&Group1); + delay(2000); + }*/ +/* + ErrorCode[0] = IDB4DC.c_Init(); + delay(1000); + ErrorCode[1] = IDB4DC.c_WriteSnIPv4IPv6(0xAABBCCDD, 0xA1A2A3A4, 0xA5A6A7A8, 0xB1B2B3B4, 0xB5B6B7B8); + do { ErrorCode[2] = IDB4DC.c_CheckModuleLongOp(); } + while ( (LopData = IDB4DC.getModuleLongOpData()).State == IDILONGOP_STATE_IN_PROC ); + + ErrorCode[3] = IDB4DC.INPV_DEV.getInputVoltage(); + INPV_Data = IDB4DC.INPV_DEV.getChData(); + + IDB4DC.PSUC_DEV.setAllChVoltage(5000, 6000, 7000, 8000); + IDB4DC.PSUC_DEV.setAllChState(1); + while (1) + { + IDB4DC.PSUC_DEV.setAllChState(0, 1, 0, 1); + delay(2000); + IDB4DC.PSUC_DEV.setAllChState(1, 0, 1, 0); + delay(2000); + } +*/ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchCO2.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchCO2.cpp new file mode 100644 index 0000000..3283761 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchCO2.cpp @@ -0,0 +1,216 @@ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#ifdef F_CPU +#undef F_CPU +#endif +#define F_CPU 16000000UL +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +#include "IdiBusSerialLine.h" +#include "IDIBUS_3Thermo1HT.h" +#include "IDIBUS_4CNTtoPWM.h" +#include "IDIBUS_CO2.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include "PID.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +//IDIBUS MASTER V0.26 beta + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSerialLine Serial_Line0; +IdiBusSerialLine Serial_Line1; + //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +int32_t BeautyThemperature(int32_t temp) { + int16_t numberPart = temp >> 7; //separate numeric part + uint8_t decimalPart = (temp&0x7F); //from decimal + + + #define decimalSize 100 + + uint16_t decimalConvertedPart = 0; + for (uint8_t i = 0; i < 7; i++){ //calculating decimal part with static point + if ((decimalPart>>(6-i)) & 1) + decimalConvertedPart += decimalSize>>(1+i); + } + + //decimalConvertedPart /= decimalSize/10000; + + //long number = ((long)numberPart)*10000+decimalConvertedPart; //combine decimal and numeric part + return (int32_t)numberPart*decimalSize+decimalConvertedPart; +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +const int32_t TargetCO2 = 50000U; +const int32_t TargetTemp = 3600U; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +PID CO2_PID; +PID TEMP_PID; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void setup() +{ + delay(50); // Power on delay for external periphery + + CO2_PID = PID(); + TEMP_PID = PID(); + + //PIDs configuration + CO2_PID.P = .085; //For 50 000 ppm only + CO2_PID.I = .00015; + CO2_PID.D = .605; //Probably needs 645 + //CO2_PID.P = .059; + //CO2_PID.I = .00016; + //CO2_PID.D = .645; + CO2_PID.Target = TargetCO2; + + TEMP_PID.P = 2.1; + TEMP_PID.I = .0006; + TEMP_PID.D = 2.; + TEMP_PID.Target = TargetTemp; + + //Arduino Variant + IDIBUS_SERIAL_INIT_TYPEDEF L0Init; + L0Init.USART_NUMBER = IDIBUS_SERIAL_USART2; // select USART + L0Init.TIMER_NUMBER = IDIBUS_TIMER_1; // select timer + L0Init.CONFIG = IDIBUS_SERIAL_8N2; // 8 bit, 2 stop + L0Init.RS485_DIR_PIN = 6; // direction pin in-out + L0Init.BAUDRATE_DIPSW_S0_PIN = 9; // speed selector pins + L0Init.BAUDRATE_DIPSW_S1_PIN = 8; + L0Init.BAUDRATE_DIPSW_S2_PIN = 7; + Serial_Line0.Init(&L0Init); // Init line with with config above + Serial_Line0.UpdateBaudrateFromDipSwitch(); // speed setup + Serial_Line0.Start(); // run! + + // Standard pinout variant + IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF L1Init; + L1Init.USART_NUMBER = IDIBUS_SERIAL_USART1; + L1Init.TIMER_NUMBER = IDIBUS_TIMER_3; + L1Init.CONFIG = IDIBUS_SERIAL_8N2; + L1Init.RS485_DIR_GPIO.PORT = &PORTL; + L1Init.RS485_DIR_GPIO.PIN_NUM = 6; + L1Init.BAUDRATE_DIPSW.S0.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S0.PIN_NUM = 1; + L1Init.BAUDRATE_DIPSW.S1.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S1.PIN_NUM = 0; + L1Init.BAUDRATE_DIPSW.S2.PORT = &PORTL; + L1Init.BAUDRATE_DIPSW.S2.PIN_NUM = 7; + Serial_Line1.Init(&L1Init); + Serial_Line1.UpdateBaudrateFromDipSwitch(); + Serial_Line1.Start(); + + Serial.begin(19200,SERIAL_8N2); // usart0 for debug + + //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + // Enable power out 24V on main board (to slaves) + Serial3.begin(250000); + Serial3.write("R+",2); + delay(500); // Power on delay for external periphery +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +volatile uint8_t ErrorCode[10]; // buffer for error codes +IdiBusLongOpData LopData; // Long operation data (not used in current example) +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBus_3Thermo1HT IDB3TH1HT (&Serial_Line1, 16+4); // Create 3ThermoCouple+1Heater module object with slave Address=20 +IdiBus_4CNTtoPWM IdiPWM (&Serial_Line1, 16+1); +IdiBus_CO2 IdiCO2 (&Serial_Line1, 16+2); +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void loop() +{ + ErrorCode[1] = IdiPWM.c_Init(); + ErrorCode[2] = IdiCO2.c_Init(); + ErrorCode[3] = IDB3TH1HT.c_Init(); + + delay(1000); //Wait to startup modules + + ErrorCode[1] = IdiPWM.initCh(0); + ErrorCode[1] = IdiPWM.initCh(1); + + + while (1) + { // read all data + + //IDB3TH1HT.THERMO_DEV.getAllChTemperature(); // read CNT counts, all channels + IDB3TH1HT.THERMO_DEV.getTemperature(2); + IdiCO2.getCO2(0); + + uint32_t CO2 = IdiCO2.getChData(0).Value; + + + Serial.write((char *)&CO2,4); + while(!Serial.availableForWrite()); + + //uint32_t calc = CO2_PID.calculatePID(CO2); + //Serial.write((char *)&calc,4); + + + int32_t temperature = BeautyThemperature(IDB3TH1HT.THERMO_DEV.getChData(2).Temperature); + Serial.write((char *)&temperature,4); + + //while(!Serial.availableForWrite()); + + //temperature = BeautyThemperature(IDB3TH1HT.THERMO_DEV.getChData(1).Temperature); + //Serial.write((char *)&temperature,4); + + IdiPWM.setChPwm(0,CO2_PID.calculatePID(CO2)); + IdiPWM.setChPwm(1,TEMP_PID.calculatePID(constrain(temperature,0,100000))); + + //while(Serial.available() == 0); + // + //delay(10); + // + //uint8_t val = Serial.read(); + //IdiPWM.setChPwm(0,val); + //while(!Serial.available()); + //val = Serial.read(); + //IdiPWM.setChPwm(1,val); + //while(!Serial.available()); + //Serial.read(); + + delay(1500); + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +/* +Egor code for loop function + +IdiBus_4DC IDB4DC(&Serial_Line1, 122); + +//ErrorCode = IDB4DC.c_Init(10); +ErrorCode = IDB4DC.c_Init(); +delay(1000); +ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 0, 10); +ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 2, 10); + +uint8_t TxData; +IdiBusMMESG Group1(IDIBUS_GROUP_10_ADDR, &TxData, 1); +Group1.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + +while (1) +{ +Serial.write((uint8_t*)"echo", sizeof("echo")-1); + +TxData = 0; +Serial_Line1.sendMMESG(&Group1); +delay(2000); +TxData = 1; +Serial_Line1.sendMMESG(&Group1); +delay(2000); +}*/ +/* +ErrorCode[0] = IDB4DC.c_Init(); +delay(1000); +ErrorCode[1] = IDB4DC.c_WriteSnIPv4IPv6(0xAABBCCDD, 0xA1A2A3A4, 0xA5A6A7A8, 0xB1B2B3B4, 0xB5B6B7B8); +do { ErrorCode[2] = IDB4DC.c_CheckModuleLongOp(); } +while ( (LopData = IDB4DC.getModuleLongOpData()).State == IDILONGOP_STATE_IN_PROC ); + +ErrorCode[3] = IDB4DC.INPV_DEV.getInputVoltage(); +INPV_Data = IDB4DC.INPV_DEV.getChData(); + +IDB4DC.PSUC_DEV.setAllChVoltage(5000, 6000, 7000, 8000); +IDB4DC.PSUC_DEV.setAllChState(1); +while (1) +{ +IDB4DC.PSUC_DEV.setAllChState(0, 1, 0, 1); +delay(2000); +IDB4DC.PSUC_DEV.setAllChState(1, 0, 1, 0); +delay(2000); +} +*/ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchSalt.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchSalt.cpp new file mode 100644 index 0000000..e337ad2 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/SketchSalt.cpp @@ -0,0 +1,296 @@ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#ifdef F_CPU +#undef F_CPU +#endif +#define F_CPU 16000000UL +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +#include +#include "IdiBusSerialLine.h" +#include "IDIBUS_4DC.h" +#include "IDIBUS_4ADC.h" +#include "IDIBUS_4CNT.h" +#include "IDIBUS_1Wire.h" +#include "IDIBUS_2SALTMETER.h" +#include "IDIBUS_3Thermo1HT.h" +#include "IDIBUS_Speedster.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +//IDIBUS MASTER V0.26 beta + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSerialLine Serial_Line0; +IdiBusSerialLine Serial_Line1; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void setup() +{ + delay(50); // Power on delay for external periphery + + //Arduino Variant + IDIBUS_SERIAL_INIT_TYPEDEF L0Init; + L0Init.USART_NUMBER = IDIBUS_SERIAL_USART2; // select USART + L0Init.TIMER_NUMBER = IDIBUS_TIMER_1; // select timer + L0Init.CONFIG = IDIBUS_SERIAL_8N2; // 8 bit, 2 stop + L0Init.RS485_DIR_PIN = 6; // direction pin in-out + L0Init.BAUDRATE_DIPSW_S0_PIN = 9; // speed selector pins + L0Init.BAUDRATE_DIPSW_S1_PIN = 8; + L0Init.BAUDRATE_DIPSW_S2_PIN = 7; + Serial_Line0.Init(&L0Init); // Init line with with config above + Serial_Line0.UpdateBaudrateFromDipSwitch(); // speed setup + Serial_Line0.Start(); // run! + + // Standard pinout variant + IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF L1Init; + L1Init.USART_NUMBER = IDIBUS_SERIAL_USART1; + L1Init.TIMER_NUMBER = IDIBUS_TIMER_3; + L1Init.CONFIG = IDIBUS_SERIAL_8N2; + L1Init.RS485_DIR_GPIO.PORT = &PORTL; + L1Init.RS485_DIR_GPIO.PIN_NUM = 6; + L1Init.BAUDRATE_DIPSW.S0.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S0.PIN_NUM = 1; + L1Init.BAUDRATE_DIPSW.S1.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S1.PIN_NUM = 0; + L1Init.BAUDRATE_DIPSW.S2.PORT = &PORTL; + L1Init.BAUDRATE_DIPSW.S2.PIN_NUM = 7; + Serial_Line1.Init(&L1Init); + Serial_Line1.UpdateBaudrateFromDipSwitch(); + Serial_Line1.Start(); + + Serial.begin(115200,SERIAL_8N2); // usart0 for debug + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + // Enable power out 24V on main board (to slaves) + #define BAUD 16000000UL/16/250000UL-1 // BAUD speed = 250000 bod + UBRR3 = (uint16_t)(BAUD); // USART BAUD RATE INIT + UCSR3B = (1< +#include "IdiBusSerialLine.h" +#include "IDIBUS_4DC.h" +#include "IDIBUS_4ADC.h" +#include "IDIBUS_4CNT.h" +#include "IDIBUS_1Wire.h" +#include "IDIBUS_3Thermo1HT.h" +#include "IDIBUS_Speedster.h" +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +//IDIBUS MASTER V0.26 beta + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IdiBusSerialLine Serial_Line0; +IdiBusSerialLine Serial_Line1; +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void setup() +{ + delay(50); // Power on delay for external periphery + + //Arduino Variant + IDIBUS_SERIAL_INIT_TYPEDEF L0Init; + L0Init.USART_NUMBER = IDIBUS_SERIAL_USART2; // select USART + L0Init.TIMER_NUMBER = IDIBUS_TIMER_1; // select timer + L0Init.CONFIG = IDIBUS_SERIAL_8N2; // 8 bit, 2 stop + L0Init.RS485_DIR_PIN = 6; // direction pin in-out + L0Init.BAUDRATE_DIPSW_S0_PIN = 9; // speed selector pins + L0Init.BAUDRATE_DIPSW_S1_PIN = 8; + L0Init.BAUDRATE_DIPSW_S2_PIN = 7; + Serial_Line0.Init(&L0Init); // Init line with with config above + Serial_Line0.UpdateBaudrateFromDipSwitch(); // speed setup + Serial_Line0.Start(); // run! + + // Standard pinout variant + IDIBUS_SERIAL_ALTERNATIVE_INIT_TYPEDEF L1Init; + L1Init.USART_NUMBER = IDIBUS_SERIAL_USART1; + L1Init.TIMER_NUMBER = IDIBUS_TIMER_3; + L1Init.CONFIG = IDIBUS_SERIAL_8N2; + L1Init.RS485_DIR_GPIO.PORT = &PORTL; + L1Init.RS485_DIR_GPIO.PIN_NUM = 6; + L1Init.BAUDRATE_DIPSW.S0.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S0.PIN_NUM = 1; + L1Init.BAUDRATE_DIPSW.S1.PORT = &PORTD; + L1Init.BAUDRATE_DIPSW.S1.PIN_NUM = 0; + L1Init.BAUDRATE_DIPSW.S2.PORT = &PORTL; + L1Init.BAUDRATE_DIPSW.S2.PIN_NUM = 7; + Serial_Line1.Init(&L1Init); + Serial_Line1.UpdateBaudrateFromDipSwitch(); + Serial_Line1.Start(); + + Serial.begin(115200,SERIAL_8N2); // usart0 for debug + +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + // Enable power out 24V on main board (to slaves) + #define BAUD 16000000UL/16/250000UL-1 // BAUD speed = 250000 bod + UBRR3 = (uint16_t)(BAUD); // USART BAUD RATE INIT + UCSR3B = (1<>1))); + else + IDITEST[addr] = IdiBus_Test(&Serial_Line1,1<<(5+(addr>>1))); + stats[addr].Ok = 0; + stats[addr].Lost = 0; + stats[addr].Broken = 0; + stats[addr].Total = 0; + } + + + for (uint8_t addr = 0; addr < 6;) { + ErrorCode = IDITEST[addr].c_Init(); + delay(1000); + if (ErrorCode != IDIER_NOPE) { + Serial.print("[ERROR] Unable to init module "); + Serial.print(1<<((addr>>1)+5)); + Serial.print(" | Line "); + Serial.print(addr&1); + Serial.print(". Check the connection! \n"); + delay(1000); + } else + addr++; + } + + Serial.write("[INFO] Modules inited successfully\n"); + + while(1) { + for (uint8_t id = 0; id < 6; id++){ + ErrorCode = IDITEST[id].sendPacket(0); + + Statistic *stat = &stats[id]; + stat->Total++; + + if (ErrorCode == IDIERMST_RCV_TIMEOUT) { + stat->Lost++; + } else if (ErrorCode != IDIER_NOPE) { + stat->Broken++; + } else { + IDIBUS_Test_DATA_TYPE data = IDITEST[id].getChData(0); + + uint8_t fail = 0; + + for (uint16_t i = 0; i < 256; i++){ + if (data.DATA[i] != data.RNG[i]) { + fail = 1; + break; + } + } + + if (fail == 1) + stat->Broken++; + else + stat->Ok++; + } + } + + PacketCounter++; + if (PacketCounter == 16) { + for (uint8_t id = 0; id < 6; id++){ + Serial.print("[INFO] Module #"); + Serial.print(1<<(5+(id>>1))); + Serial.print(" Line:"); + Serial.print(id&1); + Serial.print(" | "); + Serial.print(stats[id].Ok); + Serial.print(" | "); + Serial.print(stats[id].Lost); + Serial.print(" | "); + Serial.print(stats[id].Broken); + Serial.print(" | "); + Serial.println(stats[id].Total); + } + PacketCounter = 0; + Serial_Line0.UpdateBaudrateFromDipSwitch(); + Serial_Line1.UpdateBaudrateFromDipSwitch(); + } + } +} +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + /* + Egor code for loop function + + IdiBus_4DC IDB4DC(&Serial_Line1, 122); + + //ErrorCode = IDB4DC.c_Init(10); + ErrorCode = IDB4DC.c_Init(); + delay(1000); + ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 0, 10); + ErrorCode = IDB4DC.c_AssignGroup(IDIBUS_PSU_CNTRL_DEV, 2, 10); + + uint8_t TxData; + IdiBusMMESG Group1(IDIBUS_GROUP_10_ADDR, &TxData, 1); + Group1.ComFunc = IDIBUS_CUSTDEF_FUNC_CODE_PSU_CH_SET_STATE; + + while (1) + { + Serial.write((uint8_t*)"echo", sizeof("echo")-1); + + TxData = 0; + Serial_Line1.sendMMESG(&Group1); + delay(2000); + TxData = 1; + Serial_Line1.sendMMESG(&Group1); + delay(2000); + }*/ +/* + ErrorCode[0] = IDB4DC.c_Init(); + delay(1000); + ErrorCode[1] = IDB4DC.c_WriteSnIPv4IPv6(0xAABBCCDD, 0xA1A2A3A4, 0xA5A6A7A8, 0xB1B2B3B4, 0xB5B6B7B8); + do { ErrorCode[2] = IDB4DC.c_CheckModuleLongOp(); } + while ( (LopData = IDB4DC.getModuleLongOpData()).State == IDILONGOP_STATE_IN_PROC ); + + ErrorCode[3] = IDB4DC.INPV_DEV.getInputVoltage(); + INPV_Data = IDB4DC.INPV_DEV.getChData(); + + IDB4DC.PSUC_DEV.setAllChVoltage(5000, 6000, 7000, 8000); + IDB4DC.PSUC_DEV.setAllChState(1); + while (1) + { + IDB4DC.PSUC_DEV.setAllChState(0, 1, 0, 1); + delay(2000); + IDB4DC.PSUC_DEV.setAllChState(1, 0, 1, 0); + delay(2000); + } +*/ +//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/idiBus_Master.componentinfo.xml b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/idiBus_Master.componentinfo.xml new file mode 100644 index 0000000..627f641 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/idiBus_Master.componentinfo.xml @@ -0,0 +1,86 @@ + + + + + + + Device + Startup + + + Atmel + 1.6.0 + C:/Program Files (x86)\Atmel\Studio\7.0\Packs + + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.6.364\include\ + + include + C + + + include/ + + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.6.364\include\avr\iom2560.h + + header + C + MkwPezikXVtYA90mpLpFfA== + + include/avr/iom2560.h + + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.6.364\templates\main.c + template + source + C Exe + KjvOcFWd++tbnsEMfVPd/w== + + templates/main.c + Main file (.c) + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.6.364\templates\main.cpp + template + source + C Exe + mkKaE95TOoATsuBGv6jmxg== + + templates/main.cpp + Main file (.cpp) + + + + C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.6.364\gcc\dev\atmega2560 + + libraryPrefix + GCC + + + gcc/dev/atmega2560 + + + + + ATmega_DFP + C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.6.364/Atmel.ATmega_DFP.pdsc + 1.6.364 + true + ATmega2560 + + + + Resolved + Fixed + true + + + \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/idiBus_Master.cppproj b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/idiBus_Master.cppproj new file mode 100644 index 0000000..104a127 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IDIBUS_MASTER/IdiBus_Master/idiBus_Master.cppproj @@ -0,0 +1,421 @@ + + + + 2.0 + 7.0 + com.Atmel.AVRGCC8.CPP + dce6c7e3-ee26-4d79-826b-08594b9ad897 + atmega2560 + none + Executable + CPP + $(MSBuildProjectName) + Sketch + .elf + $(MSBuildProjectDirectory)\$(Configuration) + IdiBus_Master + idiBus_Master + C:\Program Files (x86)\Arduino + Native + true + false + true + true + 0x20000000 + + true + exception_table + 2 + 0 + idiBus_Master + 0 + + + + + + + + + + + + + + com.atmel.avrdbg.tool.ispmk2 + 0000B809060C + 0x1E9801 + + + + + + + + com.atmel.avrdbg.tool.simulator + + + Simulator + + ISP + + + + + + + + custom + + + Custom Programming Tool + + 125000 + + + + 125000 + + ISP + + com.atmel.avrdbg.tool.ispmk2 + 0000B809060C + AVRISP mkII + + + + + 0 + 200000 + + ISP + + com.atmel.avrdbg.tool.atmelice + J41800094359 + Atmel-ICE + + + + + 125000 + + ISP + + com.atmel.avrdbg.tool.stk500 + + + STK500 + + + + + + -mmcu=atmega2560 -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\gcc\dev\atmega2560" + True + True + True + True + True + False + True + True + + + NDEBUG + F_CPU=16000000L + ARDUINO=108013 + ARDUINO_AVR_MEGA2560 + ARDUINO_ARCH_AVR + USB_VID=0x2341 + USB_PID=0x0010 + USB_MANUFACTURER="\"Arduino LLC\"" + + + + + %24(ProjectDir)\..\ArduinoCore\include\core + %24(ProjectDir)\..\ArduinoCore\include\variants\mega + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Optimize for size (-Os) + -fno-threadsafe-statics + True + True + Default (-g2) + True + -std=gnu99 -std=gnu11 + True + True + + + NDEBUG + F_CPU=16000000L + ARDUINO=108013 + ARDUINO_AVR_MEGA2560 + ARDUINO_ARCH_AVR + USB_VID=0x2341 + USB_PID=0x0010 + USB_MANUFACTURER="\"Arduino LLC\"" + + + + + %24(ProjectDir)\..\ArduinoCore\include\core + %24(ProjectDir)\..\ArduinoCore\include\variants\mega + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Optimize for size (-Os) + -fno-threadsafe-statics + True + True + Default (-g2) + True + -std=gnu++11 + -Os + + + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Default (-Wa,-g) + + + + + + + -mmcu=atmega2560 -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\gcc\dev\atmega2560" + True + True + True + True + True + False + True + True + + + DEBUG + F_CPU=16000000L + ARDUINO=108013 + ARDUINO_AVR_MEGA2560 + ARDUINO_ARCH_AVR + USB_VID=0x2341 + USB_PID=0x0010 + USB_MANUFACTURER="\"Arduino LLC\"" + + + + + %24(ProjectDir)\..\ArduinoCore\include\core + %24(ProjectDir)\..\ArduinoCore\include\variants\mega + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Optimize for size (-Os) + -fno-threadsafe-statics + True + True + Maximum (-g3) + True + True + True + -std=gnu99 -std=gnu11 + True + True + + + DEBUG + F_CPU=16000000L + ARDUINO=108013 + ARDUINO_AVR_MEGA2560 + ARDUINO_ARCH_AVR + USB_VID=0x2341 + USB_PID=0x0010 + USB_MANUFACTURER="\"Arduino LLC\"" + + + + + %24(ProjectDir)\..\ArduinoCore\include\core + %24(ProjectDir)\..\ArduinoCore\include\variants\mega + ../IdiBusLib + ../IdiBusSlaves + ../IdiBusComInterrupts + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Optimize for size (-Os) + -fno-threadsafe-statics + True + True + Maximum (-g3) + True + True + True + -std=gnu++11 + -Os + + + %24(PackRepoDir)\atmel\ATmega_DFP\1.6.364\include\ + + + Default (-Wa,-g) + + + + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + + + + + ArduinoCore + d2221125-fc2c-43ae-a08a-d2054a122da5 + True + + + + + + + + + \ No newline at end of file diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IdiBusMaster.pdf b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/IdiBusMaster.pdf new file mode 100644 index 0000000000000000000000000000000000000000..60ceb7f5dcc9a847401ecbedbcfefd78c9f84bf0 GIT binary patch literal 316534 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

U9>68ZpGK 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 literal 0 HcmV?d00001 diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/Sketch — копия.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/Sketch — копия.cpp new file mode 100644 index 0000000..95c2b6e --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/Sketch — копия.cpp @@ -0,0 +1,9 @@ +void setup() { + // put your setup code here, to run once: + +} + +void loop() { + // put your main code here, to run repeatedly: + +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/Sketch.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/Sketch.cpp new file mode 100644 index 0000000..95c2b6e --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/Sketch.cpp @@ -0,0 +1,9 @@ +void setup() { + // put your setup code here, to run once: + +} + +void loop() { + // put your main code here, to run repeatedly: + +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/SketchCO2.cpp b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/SketchCO2.cpp new file mode 100644 index 0000000..95c2b6e --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/IdiBus_Master/SketchCO2.cpp @@ -0,0 +1,9 @@ +void setup() { + // put your setup code here, to run once: + +} + +void loop() { + // put your main code here, to run repeatedly: + +} diff --git a/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/v0.26 b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/v0.26 new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/idiBusMaster/IdiBus_Master_v0.26/idiBus_MasterLib/v0.26 @@ -0,0 +1 @@ +.