├── .gitattributes ├── .github └── workflows │ ├── build-for-release.yml │ └── non-release-build.yml ├── .gitignore ├── ADDING_SENSORS.md ├── Binaries ├── OpenLog_Artemis-V10-v110.bin ├── OpenLog_Artemis-V10-v111.bin ├── OpenLog_Artemis-V10-v14.bin ├── OpenLog_Artemis-V10-v15.bin ├── OpenLog_Artemis-V10-v16.bin ├── OpenLog_Artemis-V10-v17.bin ├── OpenLog_Artemis-V10-v18.bin ├── OpenLog_Artemis-V10-v19.bin ├── OpenLog_Artemis-V10-v20.bin ├── OpenLog_Artemis-V10-v21.bin ├── OpenLog_Artemis-V10-v210-NoPowerLossProtection.bin ├── OpenLog_Artemis-V10-v210.bin ├── OpenLog_Artemis-V10-v22.bin ├── OpenLog_Artemis-V10-v23-NoPowerLossProtection.bin ├── OpenLog_Artemis-V10-v23.bin ├── OpenLog_Artemis-V10-v24-NoPowerLossProtection.bin ├── OpenLog_Artemis-V10-v24.bin ├── OpenLog_Artemis-V10-v25-NoPowerLossProtection.bin ├── OpenLog_Artemis-V10-v25.bin ├── OpenLog_Artemis-V10-v26-NoPowerLossProtection.bin ├── OpenLog_Artemis-V10-v26.bin ├── OpenLog_Artemis-V10-v27-NoPowerLossProtection.bin ├── OpenLog_Artemis-V10-v27.bin ├── OpenLog_Artemis-V10-v28-NoPowerLossProtection.bin ├── OpenLog_Artemis-V10-v28.bin ├── OpenLog_Artemis-V10-v29-NoPowerLossProtection.bin ├── OpenLog_Artemis-V10-v29.bin ├── OpenLog_Artemis-X04-v110.bin ├── OpenLog_Artemis-X04-v111.bin ├── OpenLog_Artemis-X04-v13.bin ├── OpenLog_Artemis-X04-v14.bin ├── OpenLog_Artemis-X04-v16.bin ├── OpenLog_Artemis-X04-v17.bin ├── OpenLog_Artemis-X04-v18.bin ├── OpenLog_Artemis-X04-v19.bin ├── OpenLog_Artemis-X04-v20.bin ├── OpenLog_Artemis-X04-v21.bin ├── OpenLog_Artemis-X04-v210.bin ├── OpenLog_Artemis-X04-v22.bin ├── OpenLog_Artemis-X04-v23.bin ├── OpenLog_Artemis-X04-v24.bin ├── OpenLog_Artemis-X04-v25.bin ├── OpenLog_Artemis-X04-v26.bin ├── OpenLog_Artemis-X04-v27.bin ├── OpenLog_Artemis-X04-v28.bin └── OpenLog_Artemis-X04-v29.bin ├── CHANGELOG.md ├── COMPILE_BINARY.md ├── CONTRIBUTING.md ├── Dockerfile ├── Extras ├── UartPower3.zip └── spi.diff ├── Firmware ├── OpenLog_Artemis │ ├── OpenLog_Artemis.ino │ ├── Sensors.h │ ├── Sensors.ino │ ├── autoDetect.ino │ ├── logging.ino │ ├── lowerPower.ino │ ├── menuAnalogLogging.ino │ ├── menuAttachedDevices.ino │ ├── menuDebug.ino │ ├── menuIMU.ino │ ├── menuMain.ino │ ├── menuPower.ino │ ├── menuSerialLogging.ino │ ├── menuTerminal.ino │ ├── menuTimeStamp.ino │ ├── nvm.ino │ ├── productionTest.ino │ ├── settings.h │ ├── support.ino │ ├── timeStamp.ino │ ├── zmodem.h │ ├── zmodem.ino │ ├── zmodem_config.h │ ├── zmodem_crc16.cpp │ ├── zmodem_fixes.h │ ├── zmodem_rz.cpp │ ├── zmodem_sz.cpp │ ├── zmodem_zm.cpp │ └── zmodem_zm.h └── Test Sketches │ ├── GNSS_Data_Logging │ └── GNSS_Data_Logging.ino │ ├── IMU_DMP_MultipleSensors │ └── IMU_DMP_MultipleSensors.ino │ ├── IMU_DMP_Quat6 │ └── IMU_DMP_Quat6.ino │ ├── IMU_DMP_Quat9 │ └── IMU_DMP_Quat9.ino │ ├── OLA_IMU_Basics │ └── OLA_IMU_Basics.ino │ ├── Sensor_Autodetect │ ├── AutoDetectWithMux │ │ ├── AutoDetectWithMux.ino │ │ ├── Sensors.ino │ │ ├── autoDetect.ino │ │ ├── extras.ino │ │ ├── menuAttachedDevices.ino │ │ ├── settings.h │ │ └── settings.ino │ ├── I2CScanner │ │ └── I2CScanner.ino │ └── I2C_Detector │ │ └── I2C_Detector.ino │ └── TIM_TM2_Data_Logging │ └── TIM_TM2_Data_Logging.ino ├── Hardware ├── New_Parts.lbr ├── Production │ ├── SparkFun_Artemis_OpenLog-Panel.GBL │ ├── SparkFun_Artemis_OpenLog-Panel.GBO │ ├── SparkFun_Artemis_OpenLog-Panel.GBP │ ├── SparkFun_Artemis_OpenLog-Panel.GBS │ ├── SparkFun_Artemis_OpenLog-Panel.GKO │ ├── SparkFun_Artemis_OpenLog-Panel.GL2 │ ├── SparkFun_Artemis_OpenLog-Panel.GL3 │ ├── SparkFun_Artemis_OpenLog-Panel.GTL │ ├── SparkFun_Artemis_OpenLog-Panel.GTO │ ├── SparkFun_Artemis_OpenLog-Panel.GTP │ ├── SparkFun_Artemis_OpenLog-Panel.GTS │ ├── SparkFun_Artemis_OpenLog-Panel.TXT │ ├── SparkFun_Artemis_OpenLog-Panel.brd │ ├── SparkFun_Artemis_OpenLog-Panel.zip │ ├── SparkFun_Artemis_OpenLog.dru │ └── ordering_instructions.txt ├── SparkFun_Artemis_OpenLog-Dimensions.pdf ├── SparkFun_Artemis_OpenLog-Schematic.pdf ├── SparkFun_Artemis_OpenLog.brd ├── SparkFun_Artemis_OpenLog.sch └── SparkFun_Artemis_OpenLog.zip ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── README.md ├── SENSOR_UNITS.md ├── UPGRADE.md └── img └── Contributing.JPG /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/build-for-release.yml: -------------------------------------------------------------------------------- 1 | # Workflow that builds the firmware, and adds the binary to the ./Binaries folder, ready for release. 2 | 3 | name: build-for-release 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Allows you to run this workflow manually from the Actions tab 8 | workflow_dispatch: 9 | branches: 10 | 11 | env: 12 | FILENAME_PREFIX: OpenLog_Artemis 13 | 14 | jobs: 15 | build: 16 | 17 | name: Build 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@main 23 | 24 | - name: Extract branch name 25 | run: echo "BRANCH=${{github.ref_name}}" >> $GITHUB_ENV 26 | 27 | - name: Get firmware version 1 28 | run: | 29 | echo "firmwareMajor=$(grep -Po "(?<=FIRMWARE_VERSION_MAJOR = )([0-9])*(?=;$)" ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino)" >> "$GITHUB_ENV" 30 | echo "firmwareMinor=$(grep -Po "(?<=FIRMWARE_VERSION_MINOR = )([0-9])*(?=;$)" ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino)" >> "$GITHUB_ENV" 31 | 32 | - name: Get firmware version 2 33 | run: | 34 | echo "firmwareMajorMinor=-V10-v${{ env.firmwareMajor }}${{ env.firmwareMinor }}" >> "$GITHUB_ENV" 35 | echo "firmwareMajorMinorX04=-X04-v${{ env.firmwareMajor }}${{ env.firmwareMinor }}" >> "$GITHUB_ENV" 36 | 37 | - name: Setup Arduino CLI 38 | uses: arduino/setup-arduino-cli@v1 39 | 40 | - name: Start config file 41 | run: arduino-cli config init --additional-urls "https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/main/package_sparkfun_apollo3_index.json" 42 | 43 | - name: Update index 44 | run: arduino-cli core update-index 45 | 46 | - name: Install platform 47 | run: arduino-cli core install "Sparkfun:apollo3@2.2.1" 48 | 49 | - name: Get Known Libraries 50 | run: arduino-cli lib install 51 | "SdFat@2.2.2" 52 | "SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library" 53 | "SparkFun I2C Mux Arduino Library" 54 | "SparkFun CCS811 Arduino Library" 55 | "SparkFun VL53L1X 4m Laser Distance Sensor" 56 | "SparkFun BME280" 57 | "SparkFun LPS25HB Pressure Sensor Library" 58 | "SparkFun VEML6075 Arduino Library" 59 | "SparkFun PHT MS8607 Arduino Library" 60 | "SparkFun MCP9600 Thermocouple Library" 61 | "SparkFun SGP30 Arduino Library" 62 | "SparkFun VCNL4040 Proximity Sensor Library" 63 | "SparkFun MS5637 Barometric Pressure Library" 64 | "SparkFun High Precision Temperature Sensor TMP117 Qwiic" 65 | "SparkFun u-blox GNSS Arduino Library" 66 | "SparkFun 6DoF ISM330DHCX" 67 | "SparkFun Qwiic Scale NAU7802 Arduino Library" 68 | "SparkFun SCD30 Arduino Library" 69 | "SparkFun Qwiic Humidity AHT20" 70 | "SparkFun SHTC3 Humidity and Temperature Sensor Library" 71 | "SparkFun ADS122C04 ADC Arduino Library" 72 | "SparkFun MicroPressure Library" 73 | "SparkFun Particle Sensor Panasonic SN-GCJA5" 74 | "SparkFun SGP40 Arduino Library" 75 | "SparkFun Qwiic Button and Qwiic Switch Library" 76 | "SparkFun Bio Sensor Hub Library" 77 | "SparkFun MMC5983MA Magnetometer Arduino Library" 78 | "SparkFun ADS1015 Arduino Library" 79 | "SparkFun KX13X Arduino Library" 80 | "SparkFun SDP3x Arduino Library" 81 | "SparkFun LPS28DFW Arduino Library" 82 | "SparkFun VEML7700 Arduino Library" 83 | "SparkFun TMP102 Breakout" 84 | 85 | - name: Enable external libs 86 | run: arduino-cli config set library.enable_unsafe_install true 87 | 88 | - name: Get Libraries 89 | run: arduino-cli lib install --git-url 90 | https://github.com/bluerobotics/BlueRobotics_MS5837_Library.git 91 | 92 | - name: Enable ICM20948 DMP 93 | run: sed -i 's|//#define ICM_20948_USE_DMP|#define ICM_20948_USE_DMP|g' /home/runner/Arduino/libraries/SparkFun_9DoF_IMU_Breakout_-_ICM_20948_-_Arduino_Library/src/util/ICM_20948_C.h 94 | 95 | - name: Patch Apollo3 Core 96 | run: | 97 | cd ./Extras 98 | unzip UartPower3.zip 99 | cp HardwareSerial.h /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/arduino/mbed-bridge/core-extend/HardwareSerial.h 100 | cp HardwareSerial.cpp /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/arduino/mbed-bridge/core-implement/HardwareSerial.cpp 101 | cp UnbufferedSerial.h /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/mbed-os/drivers/UnbufferedSerial.h 102 | cp serial_api.c /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/mbed-os/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c 103 | cp libmbed-os.a /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/variants/SFE_ARTEMIS_ATP/mbed/libmbed-os.a 104 | cp SPI.cpp /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/libraries/SPI/src/SPI.cpp 105 | rm *.h 106 | rm *.cpp 107 | rm *.a 108 | rm *.c 109 | rm *.odt 110 | 111 | - name: Compile Sketch 112 | run: arduino-cli compile -v -e -b SparkFun:apollo3:sfe_artemis_atp ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino 113 | 114 | - name: Rename binary 115 | run: | 116 | cd ./Firmware/${{ env.FILENAME_PREFIX }}/build/SparkFun.apollo3.sfe_artemis_atp/ 117 | mv ${{ env.FILENAME_PREFIX }}.ino.bin ${{ env.FILENAME_PREFIX }}${{ env.firmwareMajorMinor }}.bin 118 | echo "targetBinary=./Firmware/${{ env.FILENAME_PREFIX }}/build/SparkFun.apollo3.sfe_artemis_atp/${{ env.FILENAME_PREFIX }}${{ env.firmwareMajorMinor }}.bin" >> "$GITHUB_ENV" 119 | rm *.axf 120 | rm *.hex 121 | rm *.map 122 | 123 | - name: Move binary 124 | run: mv ${{ env.targetBinary }} ./Binaries 125 | 126 | - name: Enable Power Loss Protection 127 | run: sed -i 's|//#define noPowerLossProtection|#define noPowerLossProtection|g' ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino 128 | 129 | - name: Compile Sketch 130 | run: arduino-cli compile -v -e -b SparkFun:apollo3:sfe_artemis_atp ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino 131 | 132 | - name: Rename binary 133 | run: | 134 | cd ./Firmware/${{ env.FILENAME_PREFIX }}/build/SparkFun.apollo3.sfe_artemis_atp/ 135 | mv ${{ env.FILENAME_PREFIX }}.ino.bin ${{ env.FILENAME_PREFIX }}${{ env.firmwareMajorMinor }}-NoPowerLossProtection.bin 136 | echo "targetBinary=./Firmware/${{ env.FILENAME_PREFIX }}/build/SparkFun.apollo3.sfe_artemis_atp/${{ env.FILENAME_PREFIX }}${{ env.firmwareMajorMinor }}-NoPowerLossProtection.bin" >> "$GITHUB_ENV" 137 | rm *.axf 138 | rm *.hex 139 | rm *.map 140 | 141 | - name: Move binary 142 | run: mv ${{ env.targetBinary }} ./Binaries 143 | 144 | - name: Disable Power Loss Protection 145 | run: sed -i 's|#define noPowerLossProtection|//#define noPowerLossProtection|g' ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino 146 | 147 | - name: X04 Hardware 148 | run: | 149 | sed -i 's|#define HARDWARE_VERSION_MAJOR 1|#define HARDWARE_VERSION_MAJOR 0|g' ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino 150 | sed -i 's|#define HARDWARE_VERSION_MINOR 0|#define HARDWARE_VERSION_MINOR 4|g' ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino 151 | 152 | - name: Compile Sketch 153 | run: arduino-cli compile -v -e -b SparkFun:apollo3:sfe_artemis_atp ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino 154 | 155 | - name: Rename binary 156 | run: | 157 | cd ./Firmware/${{ env.FILENAME_PREFIX }}/build/SparkFun.apollo3.sfe_artemis_atp/ 158 | mv ${{ env.FILENAME_PREFIX }}.ino.bin ${{ env.FILENAME_PREFIX }}${{ env.firmwareMajorMinorX04 }}.bin 159 | echo "targetBinary=./Firmware/${{ env.FILENAME_PREFIX }}/build/SparkFun.apollo3.sfe_artemis_atp/${{ env.FILENAME_PREFIX }}${{ env.firmwareMajorMinorX04 }}.bin" >> "$GITHUB_ENV" 160 | rm *.axf 161 | rm *.hex 162 | rm *.map 163 | 164 | - name: Move binary 165 | run: mv ${{ env.targetBinary }} ./Binaries 166 | 167 | - name: V01 Hardware 168 | run: | 169 | sed -i 's|#define HARDWARE_VERSION_MAJOR 0|#define HARDWARE_VERSION_MAJOR 1|g' ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino 170 | sed -i 's|#define HARDWARE_VERSION_MINOR 4|#define HARDWARE_VERSION_MINOR 0|g' ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino 171 | 172 | - uses: actions-js/push@master 173 | with: 174 | github_token: ${{ secrets.GITHUB_TOKEN }} 175 | branch: ${{ env.BRANCH }} 176 | directory: './Binaries' 177 | message: 'Pushing new firmware binary' 178 | -------------------------------------------------------------------------------- /.github/workflows/non-release-build.yml: -------------------------------------------------------------------------------- 1 | # Workflow that builds the firmware, but doesn't add to a release. 2 | 3 | name: non-release-build 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Allows you to run this workflow manually from the Actions tab 8 | workflow_dispatch: 9 | branches: 10 | 11 | env: 12 | FILENAME_PREFIX: OpenLog_Artemis 13 | 14 | jobs: 15 | build: 16 | 17 | name: Build 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@main 23 | 24 | - name: Get firmware version 1 25 | run: | 26 | echo "firmwareMajor=$(grep -Po "(?<=FIRMWARE_VERSION_MAJOR = )([0-9])*(?=;$)" ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino)" >> "$GITHUB_ENV" 27 | echo "firmwareMinor=$(grep -Po "(?<=FIRMWARE_VERSION_MINOR = )([0-9])*(?=;$)" ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino)" >> "$GITHUB_ENV" 28 | 29 | - name: Get firmware version 2 30 | run: echo "firmwareMajorMinor=-V10-v${{ env.firmwareMajor }}${{ env.firmwareMinor }}" >> "$GITHUB_ENV" 31 | 32 | - name: Setup Arduino CLI 33 | uses: arduino/setup-arduino-cli@v1 34 | 35 | - name: Start config file 36 | run: arduino-cli config init --additional-urls "https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/main/package_sparkfun_apollo3_index.json" 37 | 38 | - name: Update index 39 | run: arduino-cli core update-index 40 | 41 | - name: Install platform 42 | run: arduino-cli core install "Sparkfun:apollo3@2.2.1" 43 | 44 | - name: Get Known Libraries 45 | run: arduino-cli lib install 46 | "SdFat@2.2.2" 47 | "SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library" 48 | "SparkFun I2C Mux Arduino Library" 49 | "SparkFun CCS811 Arduino Library" 50 | "SparkFun VL53L1X 4m Laser Distance Sensor" 51 | "SparkFun BME280" 52 | "SparkFun LPS25HB Pressure Sensor Library" 53 | "SparkFun VEML6075 Arduino Library" 54 | "SparkFun PHT MS8607 Arduino Library" 55 | "SparkFun MCP9600 Thermocouple Library" 56 | "SparkFun SGP30 Arduino Library" 57 | "SparkFun VCNL4040 Proximity Sensor Library" 58 | "SparkFun MS5637 Barometric Pressure Library" 59 | "SparkFun High Precision Temperature Sensor TMP117 Qwiic" 60 | "SparkFun u-blox GNSS Arduino Library" 61 | "SparkFun 6DoF ISM330DHCX" 62 | "SparkFun Qwiic Scale NAU7802 Arduino Library" 63 | "SparkFun SCD30 Arduino Library" 64 | "SparkFun Qwiic Humidity AHT20" 65 | "SparkFun SHTC3 Humidity and Temperature Sensor Library" 66 | "SparkFun ADS122C04 ADC Arduino Library" 67 | "SparkFun MicroPressure Library" 68 | "SparkFun Particle Sensor Panasonic SN-GCJA5" 69 | "SparkFun SGP40 Arduino Library" 70 | "SparkFun Qwiic Button and Qwiic Switch Library" 71 | "SparkFun Bio Sensor Hub Library" 72 | "SparkFun MMC5983MA Magnetometer Arduino Library" 73 | "SparkFun ADS1015 Arduino Library" 74 | "SparkFun KX13X Arduino Library" 75 | "SparkFun SDP3x Arduino Library" 76 | "SparkFun LPS28DFW Arduino Library" 77 | "SparkFun VEML7700 Arduino Library" 78 | "SparkFun TMP102 Breakout" 79 | 80 | - name: Enable external libs 81 | run: arduino-cli config set library.enable_unsafe_install true 82 | 83 | - name: Get Libraries 84 | run: arduino-cli lib install --git-url 85 | https://github.com/bluerobotics/BlueRobotics_MS5837_Library.git 86 | 87 | - name: Enable ICM20948 DMP 88 | run: sed -i 's|//#define ICM_20948_USE_DMP|#define ICM_20948_USE_DMP|g' /home/runner/Arduino/libraries/SparkFun_9DoF_IMU_Breakout_-_ICM_20948_-_Arduino_Library/src/util/ICM_20948_C.h 89 | 90 | - name: Patch Apollo3 Core 91 | run: | 92 | cd ./Extras 93 | unzip UartPower3.zip 94 | cp HardwareSerial.h /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/arduino/mbed-bridge/core-extend/HardwareSerial.h 95 | cp HardwareSerial.cpp /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/arduino/mbed-bridge/core-implement/HardwareSerial.cpp 96 | cp UnbufferedSerial.h /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/mbed-os/drivers/UnbufferedSerial.h 97 | cp serial_api.c /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/mbed-os/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c 98 | cp libmbed-os.a /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/variants/SFE_ARTEMIS_ATP/mbed/libmbed-os.a 99 | cp SPI.cpp /home/runner/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/libraries/SPI/src/SPI.cpp 100 | 101 | - name: Compile Sketch 102 | run: arduino-cli compile -v -e -b SparkFun:apollo3:sfe_artemis_atp ./Firmware/${{ env.FILENAME_PREFIX }}/${{ env.FILENAME_PREFIX }}.ino 103 | 104 | - name: Rename binary 105 | run: | 106 | cd ./Firmware/${{ env.FILENAME_PREFIX }}/build/SparkFun.apollo3.sfe_artemis_atp/ 107 | mv ${{ env.FILENAME_PREFIX }}.ino.bin ${{ env.FILENAME_PREFIX }}${{ env.firmwareMajorMinor }}.bin 108 | echo "targetBinary=./Firmware/${{ env.FILENAME_PREFIX }}/build/SparkFun.apollo3.sfe_artemis_atp/${{ env.FILENAME_PREFIX }}${{ env.firmwareMajorMinor }}.bin" >> "$GITHUB_ENV" 109 | 110 | - name: Upload binary to action 111 | uses: actions/upload-artifact@v4 112 | with: 113 | name: ${{ env.FILENAME_PREFIX }}${{ env.firmwareMajorMinor }}.bin 114 | path: ${{ env.targetBinary }} 115 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | #Eagle Backup files 6 | *.s#? 7 | *.b#? 8 | *.l#? 9 | *.lck 10 | 11 | # Folder config file 12 | Desktop.ini 13 | 14 | # Recycle Bin used on file shares 15 | $RECYCLE.BIN/ 16 | 17 | # Windows Installer files 18 | *.cab 19 | *.msi 20 | *.msm 21 | *.msp 22 | 23 | # ========================= 24 | # Operating System Files 25 | # ========================= 26 | 27 | # OSX 28 | # ========================= 29 | 30 | .DS_Store 31 | .AppleDouble 32 | .LSOverride 33 | 34 | # Icon must ends with two \r. 35 | Icon 36 | 37 | # Thumbnails 38 | ._* 39 | 40 | # Files that might appear on external disk 41 | .Spotlight-V100 42 | .Trashes 43 | -------------------------------------------------------------------------------- /ADDING_SENSORS.md: -------------------------------------------------------------------------------- 1 | # OpenLog Artemis : How To Add A New Sensor 2 | 3 | These are _abbreviated_ instructions on how to add a new sensor to the OLA firmware. It's more of an aide-memoire really... Sorry about that. 4 | 5 | Caveat: this is _currently_ how a new sensor is added, for version v1.n of the OLA firmware using v1.2.n of the Apollo3 boards (the OLA code is compiled using the SparkFun RedBoard Artemis ATP (All The Pins) board). This will change, dramatically, when we upgrade to v2 of Apollo3 and integrate BLE support. 6 | 7 | ## Use The Release Candidate Branch 8 | 9 | First up, please target any commits at the _**release_candidate**_ branch, so they can be tested before being merged into the _main_ branch. 10 | 11 | - https://github.com/sparkfun/OpenLog_Artemis/tree/release_candidate 12 | 13 | ## OpenLog_Artemis.ino 14 | 15 | - [Add the new sensor to the comments at the start of the file](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-7d096a133c17fd6db382abb9a3c6ea7b42ec505961876cecf404a55be5945347R71) 16 | 17 | - [#include the library .h file remembering to include the library manager helper link](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-7d096a133c17fd6db382abb9a3c6ea7b42ec505961876cecf404a55be5945347R203) 18 | 19 | ## Sensors.ino 20 | 21 | ### gatherDeviceValues 22 | 23 | - This is where the sensor readings are actually read. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-fba25af49a58a7a24fb75cb34321e25dd4a94a9d3515ac051fcaa4502e444f7fR725-R798) 24 | 25 | ### printHelperText 26 | 27 | - [Add helper text for the sensor readings](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-fba25af49a58a7a24fb75cb34321e25dd4a94a9d3515ac051fcaa4502e444f7fR1132-R1165) 28 | 29 | ## autoDetect.ino 30 | 31 | ### addDevice 32 | 33 | - This code is called to add the discovered device to the linked list of active devices. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR234-R239). The class name comes from the library. The config struct is defined in settings.h. 34 | 35 | ### beginQwiicDevices 36 | 37 | - This is the code that is called to start (begin) the device. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR453-R461). Update _qwiicPowerOnDelayMillis_ if this device needs extra time to get its act together on power-up. 38 | 39 | ### configureDevice 40 | 41 | - If the sensor needs to be configured before use, that gets done here. [Add a case for the new sensor, even if it doesn't need to be configured.](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR705-R707) 42 | 43 | ### getConfigFunctionPtr 44 | 45 | - [Add a pointer to the sensor menu function (defined in menuAttachedDevices.ino)](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR795-R797) 46 | 47 | ### swap 48 | 49 | - [Add the device's I2C address(es) here - just for reference (we don't use these #defines any longer)](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR929) 50 | 51 | ### testDevice 52 | 53 | - This is the code used to detect the sensor. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR987-R994). Provide some indication of how robust the detection is. Confidence would be high if the .begin writes and reads unique data to/from the sensor. Confidence is low if .begin only uses the standard _isConnected_ I2C address test. 54 | 55 | ### getDeviceName 56 | 57 | - This is where the sensor name is defined as text. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-68cc245ab0d3c1bed2bfc22b403edc3ed73d347a35a21179b3a6ec27a458803bR1423-R1425). Keep it brief and follow the same format as the other sensors: usually _TYPE_ (PRESSURE, TEMPERATURE etc.) followed by the abbreviated manufacturer's part number 58 | 59 | ## menuAttachedDevices.ino 60 | 61 | ### menuAttachedDevices 62 | 63 | - This is the code which lists all the attached devices as a menu. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-6174875faf8039f2627c16aaf48e4db57f5a2c8c883061ac97202d74e9a46ef8R309-R311) 64 | 65 | ### menuConfigure_ 66 | 67 | - [Add a new menuConfigure_ for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-6174875faf8039f2627c16aaf48e4db57f5a2c8c883061ac97202d74e9a46ef8R2026-R2141) 68 | - Boolean settings are simple to toggle. [Make them exclusive if you need to](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-6174875faf8039f2627c16aaf48e4db57f5a2c8c883061ac97202d74e9a46ef8R1942-R1948) 69 | - _int64_t_ values are requested using _getNumber_ (defined in support.ino) 70 | - _double_ values are requested using _getDouble_ (defined in support.ino) 71 | 72 | ## nvm.ino 73 | 74 | ### recordDeviceSettingsToFile 75 | 76 | - This function gets called to write the device settings to file. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-629ae89c3c660583493d544d3a7902728f4a8eefb65800c3acb64aea37d5d88dR611-R629). Include all of the sensor settings. 77 | 78 | ### parseDeviceLine 79 | 80 | - This function gets called when the device settings are read back from file. [Add a case for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-629ae89c3c660583493d544d3a7902728f4a8eefb65800c3acb64aea37d5d88dR1116-R1150) 81 | 82 | ## settings.h 83 | 84 | ### enum 85 | 86 | - [Add the device to the enumerated sensors](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-c853eddd04f78093fed5ec20b822c3c224bfa5f268738ce4c479b45667f86fe9R25). Insert the new one above _DEVICE_TOTAL_DEVICES_ 87 | 88 | ### settings struct 89 | 90 | - [Add a settings struct for the new sensor](https://github.com/sparkfun/OpenLog_Artemis/commit/2a26acd279fa93cfe84f1bc518c0e7a041b3bc44#diff-c853eddd04f78093fed5ec20b822c3c224bfa5f268738ce4c479b45667f86fe9R265-R281). Include both _log_ and _powerOnDelayMillis_ 91 | 92 | ## README.md 93 | 94 | - Add the new sensor to the list in [README.md](./README.md). Include a link to the product page 95 | - Update the OLA product page on Sparkle - add the new sensor to the list 96 | 97 | ## CHANGELOG.md 98 | 99 | - Update [CHANGELOG.md](./CHANGELOG.md). Start a new version if you need to. Add the new sensor to the change notes 100 | 101 | ## SENSOR_UNITS.md 102 | 103 | - Update [SENSOR_UNITS.md](./SENSOR_UNITS.md). Add the new sensor to the appropriate section at the start of the document. Add a unit table for the sensor at the end of the document. 104 | -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v110.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v110.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v111.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v111.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v14.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v14.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v15.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v15.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v16.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v16.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v17.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v17.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v18.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v18.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v19.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v19.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v20.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v20.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v21.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v21.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v210-NoPowerLossProtection.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v210-NoPowerLossProtection.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v210.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v210.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v22.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v22.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v23-NoPowerLossProtection.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v23-NoPowerLossProtection.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v23.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v23.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v24-NoPowerLossProtection.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v24-NoPowerLossProtection.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v24.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v24.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v25-NoPowerLossProtection.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v25-NoPowerLossProtection.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v25.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v25.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v26-NoPowerLossProtection.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v26-NoPowerLossProtection.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v26.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v26.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v27-NoPowerLossProtection.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v27-NoPowerLossProtection.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v27.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v27.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v28-NoPowerLossProtection.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v28-NoPowerLossProtection.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v28.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v28.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v29-NoPowerLossProtection.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v29-NoPowerLossProtection.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-V10-v29.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-V10-v29.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v110.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v110.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v111.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v111.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v13.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v13.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v14.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v14.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v16.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v16.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v17.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v17.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v18.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v18.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v19.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v19.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v20.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v20.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v21.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v21.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v210.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v210.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v22.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v22.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v23.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v23.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v24.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v24.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v25.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v25.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v26.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v26.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v27.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v27.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v28.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v28.bin -------------------------------------------------------------------------------- /Binaries/OpenLog_Artemis-X04-v29.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Binaries/OpenLog_Artemis-X04-v29.bin -------------------------------------------------------------------------------- /COMPILE_BINARY.md: -------------------------------------------------------------------------------- 1 | # OpenLog Artemis : How To Compile The OLA Firmware Binary 2 | 3 | These are _abbreviated_ instructions on how to compile the OLA firmware. It's more of an aide-memoire really... Sorry about that. 4 | 5 | ## Install Arduino IDE 6 | 7 | Tested version: 1.8.19 8 | 9 | (IDE version 2 has not been tested) 10 | 11 | ## Add Apollo3 To The Additional Boards Manager URLs 12 | 13 | Open `File \ Preferences` 14 | 15 | Click the File icon to the right of the `Additional Boards Manager URLs` text box 16 | 17 | Add: 18 | 19 | ``` 20 | https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/main/package_sparkfun_apollo3_index.json 21 | ``` 22 | 23 | Click OK 24 | 25 | Click OK 26 | 27 | Close and re-open the IDE 28 | 29 | ## Install the Apollo3 Board Package 30 | 31 | Open `Tools \ Board \ Boards Manager` 32 | 33 | Enter `Apollo3` in the search box 34 | 35 | Install the SparkFun Apollo3 Boards. Tested version: 2.2.1 36 | 37 | ## Install All The Required Libraries 38 | 39 | Copy and paste the following into an empty sketch. Click on each link in turn to install the libraries via the Library Manager: 40 | 41 | ``` 42 | // SdFat by Bill Greiman (Tested version: 2.2.0): http://librarymanager/All#SdFat_exFAT 43 | // http://librarymanager/All#SparkFun_ICM_20948_IMU 44 | // http://librarymanager/All#SparkFun_I2C_Mux 45 | // http://librarymanager/All#SparkFun_CCS811 46 | // http://librarymanager/All#SparkFun_VL53L1X 47 | // http://librarymanager/All#SparkFun_BME280 48 | // http://librarymanager/All#SparkFun_LPS25HB 49 | // http://librarymanager/All#SparkFun_VEML6075 50 | // http://librarymanager/All#SparkFun_PHT_MS8607 51 | // http://librarymanager/All#SparkFun_MCP9600 52 | // http://librarymanager/All#SparkFun_SGP30 53 | // http://librarymanager/All#SparkFun_VCNL4040 54 | // http://librarymanager/All#SparkFun_MS5637 55 | // http://librarymanager/All#SparkFun_TMP102 56 | // http://librarymanager/All#SparkFun_TMP117 57 | // http://librarymanager/All#SparkFun_u-blox_GNSS 58 | // http://librarymanager/All#SparkFun_NAU7802 59 | // http://librarymanager/All#SparkFun_SCD30 60 | // http://librarymanager/All#Qwiic_Humidity_AHT20 61 | // http://librarymanager/All#SparkFun_SHTC3 62 | // http://librarymanager/All#SparkFun_ADS122C04 63 | // http://librarymanager/All#SparkFun_MicroPressure 64 | // http://librarymanager/All#SparkFun_Particle_Sensor_SN-GCJA5 65 | // http://librarymanager/All#SparkFun_SGP40 66 | // http://librarymanager/All#SparkFun_SDP3x 67 | // http://librarymanager/All#SparkFun_Qwiic_Button_Switch 68 | // http://librarymanager/All#SparkFun_Bio_Sensor 69 | // http://librarymanager/All#SparkFun_6DoF_ISM330DHCX 70 | // http://librarymanager/All#SparkFun_MMC5983MA 71 | // http://librarymanager/All#SparkFun_ADS1015 72 | // http://librarymanager/All#SparkFun_KX13X 73 | // http://librarymanager/All#SparkFun_LPS28DFW_Arduino_Library 74 | // http://librarymanager/All#SparkFun_VEML7700 75 | ``` 76 | 77 | ### Blue Robotics MS5837 78 | 79 | Please manually download and install the latest version of the Blue Robotics MS5837 library from: 80 | 81 | https://github.com/bluerobotics/BlueRobotics_MS5837_Library/archive/refs/heads/master.zip 82 | 83 | (Version 1.1.1 - available through the Arduino Library Manager - is not the latest version...) 84 | 85 | ## Download the OLA Firmware Zip 86 | 87 | Open this link in a web browser to download a complete Zip of the OLA firmware repo: 88 | 89 | https://github.com/sparkfun/OpenLog_Artemis/archive/refs/heads/main.zip 90 | 91 | Unzip it (Extract All files) 92 | 93 | ## Copy the OLA Source Code 94 | 95 | Navigate to the `Firmware` sub-folder 96 | 97 | Copy the entire `OpenLog_Artemis` folder from the Zip file into your `Arduino` folder. This contains the source code for the firmware. The result should be: 98 | 99 | ``` 100 | C:\Users\\Documents\Arduino\OpenLog_Artemis 101 | ``` 102 | 103 | ## Patch the Apollo3 Core 104 | 105 | The Apollo3 core (2.2.1) requires patching - using code kindly provided by Paulvha. For more information, open [this link](https://github.com/sparkfun/OpenLog_Artemis/issues/117#issuecomment-1085881142) in a web browser. 106 | 107 | Navigate to the `Extras` folder in the Zip file. Copy the `UartPower3.zip` file. Paste it into the Apollo3 board package folder. On Windows machines, this is (usually): 108 | 109 | ``` 110 | C:\Users\\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3 111 | ``` 112 | 113 | On Linux machines, this is (usually): 114 | ``` 115 | /home//.arduino15/packages/SparkFun/hardware/apollo3/ 116 | ``` 117 | 118 | Unzip it (Extract All files) 119 | 120 | **Close the Arduino IDE** 121 | 122 | Follow the instructions contained in `uart_power_3.odt` 123 | 124 | In summary: replace the following five files with the ones from `UartPower3.zip` : 125 | 126 | ``` 127 | C:\Users\\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\cores\arduino\mbed-bridge\core-extend\HardwareSerial.h 128 | C:\Users\\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\cores\arduino\mbed-bridge\core-implement\HardwareSerial.cpp 129 | C:\Users\\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\cores\mbed-os\drivers\UnbufferedSerial.h 130 | C:\Users\\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\cores\mbed-os\targets\TARGET_Ambiq_Micro\TARGET_Apollo3\device\serial_api.c 131 | C:\Users\\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\variants\SFE_ARTEMIS_ATP\mbed\libmbed-os.a 132 | ``` 133 | 134 | ## Update Apollo3 SPI.cpp 135 | 136 | Open the following file: 137 | 138 | ``` 139 | C:\Users\\AppData\Local\Arduino15\packages\SparkFun\hardware\apollo3\2.2.1\libraries\SPI\src\SPI.cpp 140 | ``` 141 | 142 | Search for `::end` 143 | 144 | Replace `::end` with: 145 | 146 | ``` 147 | void arduino::MbedSPI::end() { 148 | if (dev) { 149 | delete dev; 150 | dev = NULL; 151 | } 152 | } 153 | ``` 154 | 155 | Save the updated file 156 | 157 | The extra code prevents badness when the Artemis goes into deep sleep 158 | 159 | ## Enable ICM29048 DMP Support 160 | 161 | Open the following file: 162 | 163 | ``` 164 | C:\Users\\Documents\Arduino\libraries\SparkFun_ICM-20948_ArduinoLibrary\src\util\ICM_20948_C.h 165 | ``` 166 | 167 | Uncomment the following line (29): 168 | 169 | ``` 170 | #define ICM_20948_USE_DMP // Uncomment this line to enable DMP support. You can of course use ICM_20948_USE_DMP as a compiler flag too 171 | ``` 172 | 173 | Save the updated file 174 | 175 | ## Compile / Upload the Code 176 | 177 | Re-open the Arduino IDE 178 | 179 | Open the main OLA Firmware .ino: 180 | 181 | ``` 182 | C:\Users\\Documents\Arduino\OpenLog_Artemis\OpenLog_Artemis.ino 183 | ``` 184 | 185 | Open the `Tools \ Board` menu. Select `SparkFun Apollo3 \ RedBoard Artemis ATP` 186 | 187 | If you have the OLA connected via USB, you can click the `Upload` (Right-Arrow) icon to compile the code and upload it onto the OLA 188 | 189 | (The compilation takes a long time. Go make a cup of tea...) 190 | 191 | If you want to be able to swap between firmware versions more quickly, use the `Sketch \ Export compiled Binary` to create a binary which 192 | you can upload with the `Artemis Firmware Upload GUI`. See [UPGRADE.md](./UPGRADE.md) for more details. 193 | 194 | ## Board Versions 195 | 196 | If you are compiling for the Red (SparkFun) OLA: leave the hardware version defines as: 197 | 198 | ``` 199 | #define HARDWARE_VERSION_MAJOR 1 200 | #define HARDWARE_VERSION_MINOR 0 201 | ``` 202 | 203 | If you have an original Black (SparkX) OLA - way to go! Change those lines to: 204 | 205 | ``` 206 | #define HARDWARE_VERSION_MAJOR 0 207 | #define HARDWARE_VERSION_MINOR 4 208 | ``` 209 | 210 | ## No Power Loss Protection 211 | 212 | To disable the sleep-on-power-loss functionality, uncomment this line: 213 | 214 | ``` 215 | #define noPowerLossProtection // Uncomment this line to disable the sleep-on-power-loss functionality 216 | ``` 217 | 218 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # OpenLog Artemis : How to Contribute 2 | 3 | Thank you so *much* for offering to help out. We truly appreciate it. 4 | 5 | If you'd like to contribute, start by searching through the [issues](https://github.com/sparkfun/OpenLog_Artemis/issues) and [pull requests](https://github.com/sparkfun/OpenLog_Artemis/pulls) to see whether someone else has raised a similar idea or question. Please check the [closed issues](https://github.com/sparkfun/OpenLog_Artemis/issues?q=is%3Aissue+is%3Aclosed) 6 | and [closed pull requests](https://github.com/sparkfun/OpenLog_Artemis/pulls?q=is%3Apr+is%3Aclosed) too - you may find that your issue or feature has already been discussed. 7 | 8 | If you decide to add a feature or support for a new sensor to OpenLog Artemis, please create a PR and follow these best practices: 9 | 10 | * Change as little as possible. Do not sumbit a PR that changes 100 lines of whitespace. Break up into multiple PRs if necessary. 11 | * If you add a new feature, please document how it works in the PR. 12 | * Please submit your PR using the [release-candidate branch](https://github.com/sparkfun/OpenLog_Artemis/tree/release_candidate). That way, we can merge and test your PR quickly without changing the _master_ branch 13 | 14 | ![Contributing.JPG](./img/Contributing.JPG) 15 | 16 | ## Style guide 17 | 18 | Please read and follow the [Arduino API style guide](https://www.arduino.cc/en/Reference/APIStyleGuide). Also read and consider the [Arduino style guide](https://www.arduino.cc/en/Reference/StyleGuide). 19 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | ENV DEBIAN_FRONTEND=noninteractive 4 | 5 | RUN apt-get update && apt-get install -y curl git unzip && apt-get clean 6 | 7 | RUN curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/local/bin sh 8 | 9 | RUN arduino-cli config init 10 | 11 | RUN arduino-cli config add board_manager.additional_urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/main/package_sparkfun_apollo3_index.json 12 | 13 | RUN arduino-cli core update-index 14 | RUN arduino-cli core install "Sparkfun:apollo3@2.2.1" 15 | 16 | RUN arduino-cli lib update-index 17 | 18 | # RUN arduino-cli lib install "SparkFun Qwiic Power Switch Arduino Library" 19 | RUN arduino-cli lib install "SdFat@2.2.0" 20 | RUN arduino-cli lib install "SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library" 21 | RUN arduino-cli lib install "SparkFun I2C Mux Arduino Library" 22 | RUN arduino-cli lib install "SparkFun CCS811 Arduino Library" 23 | RUN arduino-cli lib install "SparkFun VL53L1X 4m Laser Distance Sensor" 24 | RUN arduino-cli lib install "SparkFun BME280" 25 | RUN arduino-cli lib install "SparkFun LPS25HB Pressure Sensor Library" 26 | RUN arduino-cli lib install "SparkFun VEML6075 Arduino Library" 27 | RUN arduino-cli lib install "SparkFun PHT MS8607 Arduino Library" 28 | RUN arduino-cli lib install "SparkFun MCP9600 Thermocouple Library" 29 | RUN arduino-cli lib install "SparkFun SGP30 Arduino Library" 30 | RUN arduino-cli lib install "SparkFun VCNL4040 Proximity Sensor Library" 31 | RUN arduino-cli lib install "SparkFun MS5637 Barometric Pressure Library" 32 | RUN arduino-cli lib install "SparkFun High Precision Temperature Sensor TMP117 Qwiic" 33 | RUN arduino-cli lib install "SparkFun u-blox GNSS Arduino Library" 34 | RUN arduino-cli lib install "SparkFun 6DoF ISM330DHCX" 35 | RUN arduino-cli lib install "SparkFun Qwiic Scale NAU7802 Arduino Library" 36 | RUN arduino-cli lib install "SparkFun SCD30 Arduino Library" 37 | RUN arduino-cli lib install "SparkFun Qwiic Humidity AHT20" 38 | RUN arduino-cli lib install "SparkFun SHTC3 Humidity and Temperature Sensor Library" 39 | RUN arduino-cli lib install "SparkFun ADS122C04 ADC Arduino Library" 40 | RUN arduino-cli lib install "SparkFun MicroPressure Library" 41 | RUN arduino-cli lib install "SparkFun Particle Sensor Panasonic SN-GCJA5" 42 | RUN arduino-cli lib install "SparkFun SGP40 Arduino Library" 43 | RUN arduino-cli lib install "SparkFun Qwiic Button and Qwiic Switch Library" 44 | RUN arduino-cli lib install "SparkFun Bio Sensor Hub Library" 45 | RUN arduino-cli lib install "SparkFun MMC5983MA Magnetometer Arduino Library" 46 | RUN arduino-cli lib install "SparkFun ADS1015 Arduino Library" 47 | RUN arduino-cli lib install "SparkFun KX13X Arduino Library" 48 | RUN arduino-cli lib install "SparkFun SDP3x Arduino Library" 49 | RUN arduino-cli lib install "SparkFun LPS28DFW Arduino Library" 50 | RUN arduino-cli lib install "SparkFun VEML7700 Arduino Library" 51 | 52 | # Add BlueRobotics_MS5837_Library from git 53 | WORKDIR /root/Arduino/libraries 54 | RUN curl -L https://github.com/bluerobotics/BlueRobotics_MS5837_Library/archive/refs/heads/master.zip -o ms5837.zip 55 | RUN unzip ms5837.zip 56 | 57 | WORKDIR /work 58 | 59 | ADD . . 60 | 61 | # Patch Apollo Core 62 | WORKDIR /work/Extras 63 | RUN unzip UartPower3.zip 64 | RUN cp HardwareSerial.h /root/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/arduino/mbed-bridge/core-extend/HardwareSerial.h 65 | RUN cp HardwareSerial.cpp /root/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/arduino/mbed-bridge/core-implement/HardwareSerial.cpp 66 | RUN cp UnbufferedSerial.h /root/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/mbed-os/drivers/UnbufferedSerial.h 67 | RUN cp serial_api.c /root/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/cores/mbed-os/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c 68 | RUN cp libmbed-os.a /root/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/variants/SFE_ARTEMIS_ATP/mbed/libmbed-os.a 69 | 70 | WORKDIR /root/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/libraries/SPI/src 71 | RUN patch -p1 < /work/Extras/spi.diff 72 | 73 | # Enable DMP on ICM 20948 74 | RUN sed -i 's|//#define ICM|#define ICM|g' /root/Arduino/libraries/SparkFun_9DoF_IMU_Breakout_-_ICM_20948_-_Arduino_Library/src/util/ICM_20948_C.h 75 | 76 | # Enable debug symbols 77 | # echo "compiler.c.extra_flags=-MMD -g3" >> /root/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/platform.local.txt 78 | # echo "compiler.cxx.extra_flags=-MMD -g3" >> /root/.arduino15/packages/SparkFun/hardware/apollo3/2.2.1/platform.local.txt 79 | 80 | WORKDIR /work/Firmware/OpenLog_Artemis 81 | 82 | CMD arduino-cli compile --build-cache-path /tmp/cache -v -e -b SparkFun:apollo3:sfe_artemis_atp 83 | -------------------------------------------------------------------------------- /Extras/UartPower3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Extras/UartPower3.zip -------------------------------------------------------------------------------- /Extras/spi.diff: -------------------------------------------------------------------------------- 1 | diff -u old/SPI.cpp new/SPI.cpp 2 | --- old/SPI.cpp 2023-09-14 12:53:54.000000000 +0200 3 | +++ new/SPI.cpp 2023-09-18 18:45:48.141504930 +0200 4 | @@ -86,6 +86,7 @@ 5 | void arduino::MbedSPI::end() { 6 | if (dev) { 7 | delete dev; 8 | + dev = NULL; 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/Sensors.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #pragma once 4 | 5 | // Flags for output destinations 6 | 7 | #define OL_OUTPUT_SERIAL 0x1 8 | #define OL_OUTPUT_SDCARD 0x2 9 | 10 | void printHelperText(uint8_t); 11 | void getData(char *buffer, size_t lenBuffer); 12 | uint8_t getByteChoice(int numberOfSeconds, bool updateDZSERIAL = false); 13 | void menuMain(bool alwaysOpen = false); 14 | void beginSD(bool silent = false); 15 | void beginIMU(bool silent = false); 16 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/logging.ino: -------------------------------------------------------------------------------- 1 | //Print a message both to terminal and to log 2 | void msg(const char * message) 3 | { 4 | SerialPrintln(message); 5 | if (online.microSD) 6 | sensorDataFile.println(message); 7 | } 8 | 9 | //Returns next available log file name 10 | //Checks the spots in EEPROM for the next available LOG# file name 11 | //Updates EEPROM and then appends to the new log file. 12 | char* findNextAvailableLog(int &newFileNumber, const char *fileLeader) 13 | { 14 | //This will contain the file for SD writing 15 | #if SD_FAT_TYPE == 1 16 | File32 newFile; 17 | #elif SD_FAT_TYPE == 2 18 | ExFile newFile; 19 | #elif SD_FAT_TYPE == 3 20 | FsFile newFile; 21 | #else // SD_FAT_TYPE == 0 22 | File newFile; 23 | #endif // SD_FAT_TYPE 24 | 25 | if (newFileNumber < 2) //If the settings have been reset, let's warn the user that this could take a while! 26 | { 27 | SerialPrintln(F("Finding the next available log file.")); 28 | SerialPrintln(F("This could take a long time if the SD card contains many existing log files.")); 29 | } 30 | 31 | if (newFileNumber > 0) 32 | newFileNumber--; //Check if last log file was empty. Reuse it if it is. 33 | 34 | //Search for next available log spot 35 | static char newFileName[40]; 36 | while (1) 37 | { 38 | char newFileNumberStr[6]; 39 | if (newFileNumber < 10) 40 | sprintf(newFileNumberStr, "0000%d", newFileNumber); 41 | else if (newFileNumber < 100) 42 | sprintf(newFileNumberStr, "000%d", newFileNumber); 43 | else if (newFileNumber < 1000) 44 | sprintf(newFileNumberStr, "00%d", newFileNumber); 45 | else if (newFileNumber < 10000) 46 | sprintf(newFileNumberStr, "0%d", newFileNumber); 47 | else 48 | sprintf(newFileNumberStr, "%d", newFileNumber); 49 | sprintf(newFileName, "%s%s.TXT", fileLeader, newFileNumberStr); //Splice the new file number into this file name. Max no. is 99999. 50 | 51 | if (sd.exists(newFileName) == false) break; //File name not found so we will use it. 52 | 53 | //File exists so open and see if it is empty. If so, use it. 54 | newFile.open(newFileName, O_READ); 55 | if (newFile.fileSize() == 0) break; // File is empty so we will use it. Note: we need to make the user aware that this can happen! 56 | 57 | newFile.close(); // Close this existing file we just opened. 58 | 59 | newFileNumber++; //Try the next number 60 | if (newFileNumber >= 100000) break; // Have we hit the maximum number of files? 61 | } 62 | 63 | newFile.close(); //Close this new file we just opened 64 | 65 | newFileNumber++; //Increment so the next power up uses the next file # 66 | 67 | if (newFileNumber >= 100000) // Have we hit the maximum number of files? 68 | { 69 | SerialPrint(F("***** WARNING! File number limit reached! (Overwriting ")); 70 | SerialPrint(newFileName); 71 | SerialPrintln(F(") *****")); 72 | newFileNumber = 100000; // This will overwrite Log99999.TXT next time thanks to the newFileNumber-- above 73 | } 74 | else 75 | { 76 | SerialPrint(F("Logging to: ")); 77 | SerialPrintln(newFileName); 78 | } 79 | 80 | //Record new file number to EEPROM and to config file 81 | //This works because newFileNumber is a pointer to settings.newFileNumber 82 | recordSystemSettings(); 83 | 84 | return (newFileName); 85 | } 86 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/menuAnalogLogging.ino: -------------------------------------------------------------------------------- 1 | void menuAnalogLogging() 2 | { 3 | while (1) 4 | { 5 | #if(HARDWARE_VERSION_MAJOR == 0) 6 | SerialPrintln(F("")); 7 | SerialPrintln(F("Note: VIN logging is only supported on V10+ hardware. X04 will show 0.0V.")); 8 | #endif 9 | SerialPrintln(F("")); 10 | SerialPrintln(F("Menu: Configure Analog Logging")); 11 | 12 | if (settings.identifyBioSensorHubs == false) 13 | { 14 | SerialPrint(F("1) Log analog pin 11 (2V Max): ")); 15 | if (settings.logA11 == true) SerialPrintln(F("Enabled. (Triggering is disabled)")); 16 | else SerialPrintln(F("Disabled")); 17 | } 18 | 19 | SerialPrint(F("2) Log analog pin 12 (TX) (2V Max): ")); 20 | if (settings.useTxRxPinsForTerminal == true) SerialPrintln(F("Disabled. (TX and RX pins are being used for the Terminal)")); 21 | else if (settings.logA12 == true) SerialPrintln(F("Enabled. (Serial output is disabled)")); 22 | else SerialPrintln(F("Disabled")); 23 | 24 | SerialPrint(F("3) Log analog pin 13 (RX) (2V Max): ")); 25 | if (settings.useTxRxPinsForTerminal == true) SerialPrintln(F("Disabled. (TX and RX pins are being used for the Terminal)")); 26 | else if (settings.logA13 == true) SerialPrintln(F("Enabled. (Serial logging is disabled)")); 27 | else SerialPrintln(F("Disabled")); 28 | 29 | if (settings.identifyBioSensorHubs == false) 30 | { 31 | SerialPrint(F("4) Log analog pin 32 (2V Max): ")); 32 | if (settings.logA32 == true) SerialPrintln(F("Enabled. (Stop logging is disabled)")); 33 | else SerialPrintln(F("Disabled")); 34 | } 35 | 36 | SerialPrint(F("5) Log output type: ")); 37 | if (settings.logAnalogVoltages == true) SerialPrintln(F("Calculated Voltage")); 38 | else SerialPrintln(F("Raw ADC reading")); 39 | 40 | SerialPrint(F("6) Log VIN (battery) voltage (6V Max): ")); 41 | if (settings.logVIN == true) SerialPrintln(F("Enabled")); 42 | else SerialPrintln(F("Disabled")); 43 | 44 | SerialPrintln(F("x) Exit")); 45 | 46 | byte incoming = getByteChoice(menuTimeout); //Timeout after x seconds 47 | 48 | if (incoming == '1') 49 | { 50 | if (settings.identifyBioSensorHubs == false) 51 | { 52 | if(settings.logA11 == false) 53 | { 54 | settings.logA11 = true; 55 | // Disable triggering 56 | settings.useGPIO11ForTrigger = false; 57 | detachInterrupt(PIN_TRIGGER); // Disable the interrupt 58 | pinMode(PIN_TRIGGER, INPUT); // Remove the pull-up 59 | pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured 60 | triggerEdgeSeen = false; // Make sure the flag is clear 61 | } 62 | else 63 | settings.logA11 = false; 64 | } 65 | else 66 | { 67 | SerialPrintln(F("")); 68 | SerialPrintln(F("Analog logging on pin 11 is not possible. Bio Sensor Hubs (Pulse Oximeters) are enabled.")); 69 | SerialPrintln(F("")); 70 | } 71 | } 72 | else if (incoming == '2') 73 | { 74 | if(settings.logA12 == false) 75 | { 76 | if (settings.useTxRxPinsForTerminal == true) 77 | { 78 | SerialPrintln(F("")); 79 | SerialPrintln(F("Analog logging on pin 12 is not possible. TX and RX pins are being used for the Terminal.")); 80 | SerialPrintln(F("")); 81 | } 82 | else 83 | { 84 | online.serialOutput = false; // Disable serial output 85 | settings.outputSerial = false; 86 | settings.logA12 = true; 87 | } 88 | } 89 | else 90 | settings.logA12 = false; 91 | } 92 | else if (incoming == '3') 93 | { 94 | if(settings.logA13 == false) 95 | { 96 | if (settings.useTxRxPinsForTerminal == true) 97 | { 98 | SerialPrintln(F("")); 99 | SerialPrintln(F("Analog logging on pin 13 is not possible. TX and RX pins are being used for the Terminal.")); 100 | SerialPrintln(F("")); 101 | } 102 | else 103 | { 104 | online.serialLogging = false; //Disable serial logging 105 | settings.logSerial = false; 106 | settings.logA13 = true; 107 | } 108 | } 109 | else 110 | settings.logA13 = false; 111 | } 112 | else if (incoming == '4') 113 | { 114 | if (settings.identifyBioSensorHubs == false) 115 | { 116 | if(settings.logA32 == false) 117 | { 118 | settings.logA32 = true; 119 | // Disable stop logging 120 | settings.useGPIO32ForStopLogging = false; 121 | detachInterrupt(PIN_STOP_LOGGING); // Disable the interrupt 122 | pinMode(PIN_STOP_LOGGING, INPUT); // Remove the pull-up 123 | pin_config(PinName(PIN_STOP_LOGGING), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured 124 | } 125 | else 126 | settings.logA32 = false; 127 | } 128 | else 129 | { 130 | SerialPrintln(F("")); 131 | SerialPrintln(F("Analog logging on pin 32 is not possible. Bio Sensor Hubs (Pulse Oximeters) are enabled.")); 132 | SerialPrintln(F("")); 133 | } 134 | } 135 | else if (incoming == '5') 136 | settings.logAnalogVoltages ^= 1; 137 | else if (incoming == '6') 138 | { 139 | settings.logVIN ^= 1; 140 | } 141 | else if (incoming == 'x') 142 | return; 143 | else if (incoming == STATUS_GETBYTE_TIMEOUT) 144 | return; 145 | else 146 | printUnknown(incoming); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/menuDebug.ino: -------------------------------------------------------------------------------- 1 | void menuDebug() 2 | { 3 | while (1) 4 | { 5 | SerialPrintln(F("")); 6 | SerialPrintln(F("Menu: Configure Debug Settings")); 7 | 8 | SerialPrint(F("1) Debug Messages: ")); 9 | if (settings.printDebugMessages == true) SerialPrintln(F("Enabled")); 10 | else SerialPrintln(F("Disabled")); 11 | 12 | SerialPrint(F("2) Reset on Zero Device Count: ")); 13 | if (settings.resetOnZeroDeviceCount == true) SerialPrintln(F("Enabled")); 14 | else SerialPrintln(F("Disabled")); 15 | 16 | SerialPrint(F("3) GNSS Debug Messages: ")); 17 | if (settings.printGNSSDebugMessages == true) SerialPrintln(F("Enabled")); 18 | else SerialPrintln(F("Disabled")); 19 | 20 | SerialPrint(F("4) Only Open Main Menu With Printable Char: ")); 21 | if (settings.openMenuWithPrintable == true) SerialPrintln(F("Yes")); 22 | else SerialPrintln(F("No")); 23 | 24 | SerialPrintln(F("5) Reboot the logger")); 25 | 26 | SerialPrintln(F("x) Exit")); 27 | 28 | byte incoming = getByteChoice(menuTimeout); //Timeout after x seconds 29 | 30 | if (incoming == '1') 31 | { 32 | settings.printDebugMessages ^= 1; 33 | } 34 | else if (incoming == '2') 35 | { 36 | if (settings.resetOnZeroDeviceCount == false) 37 | { 38 | SerialPrintln(F("")); 39 | SerialPrintln(F("Enabling resetOnZeroDeviceCount will cause the OLA to completely reset if no devices are found on the Qwiic bus.")); 40 | SerialPrintln(F("Do not enable this option if you are only logging IMU or Serial data.")); 41 | SerialPrintln(F("Are you sure? Press 'y' to confirm: ")); 42 | byte bContinue = getByteChoice(menuTimeout); 43 | if (bContinue == 'y') 44 | { 45 | settings.resetOnZeroDeviceCount ^= 1; 46 | } 47 | else 48 | SerialPrintln(F("\"resetOnZeroDeviceCount\" aborted")); 49 | } 50 | else 51 | { 52 | settings.resetOnZeroDeviceCount ^= 1; 53 | } 54 | } 55 | else if (incoming == '3') 56 | { 57 | settings.printGNSSDebugMessages ^= 1; 58 | } 59 | else if (incoming == '4') 60 | { 61 | settings.openMenuWithPrintable ^= 1; 62 | } 63 | else if (incoming == '5') 64 | { 65 | SerialPrint(F("Are you sure? Press 'y' to confirm: ")); 66 | byte bContinue = getByteChoice(menuTimeout); 67 | if (bContinue == 'y') 68 | { 69 | SerialPrintln(F("y")); 70 | resetArtemis(); 71 | } 72 | } 73 | else if (incoming == 'x') 74 | break; 75 | else if (incoming == STATUS_GETBYTE_TIMEOUT) 76 | break; 77 | else 78 | printUnknown(incoming); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/menuMain.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "Sensors.h" 4 | 5 | //Display the options 6 | //If user doesn't respond within a few seconds, return to main loop 7 | void menuMain(bool alwaysOpen) 8 | { 9 | bool restartIMU = false; 10 | 11 | if (settings.openMenuWithPrintable) // If settings.openMenuWithPrintable is true, eat the first character. Return if < 9 (Tab) 12 | { 13 | if ((settings.useTxRxPinsForTerminal == true) && (Serial1.available())) 14 | { 15 | uint8_t firstChar = Serial1.read(); 16 | if (firstChar < 9) 17 | return; 18 | } 19 | else if (Serial.available()) 20 | { 21 | uint8_t firstChar = Serial.read(); 22 | if (firstChar < 9) 23 | return; 24 | } 25 | else if (!alwaysOpen) 26 | return; 27 | } 28 | 29 | while (1) 30 | { 31 | SerialPrintln(F("")); 32 | SerialPrintln(F("Menu: Main Menu")); 33 | 34 | SerialPrintln(F("1) Configure Terminal Output")); 35 | 36 | SerialPrintln(F("2) Configure Time Stamp")); 37 | 38 | if (online.IMU) 39 | SerialPrintln(F("3) Configure IMU Logging")); 40 | 41 | if (settings.useTxRxPinsForTerminal == false) 42 | SerialPrintln(F("4) Configure Serial Logging")); 43 | 44 | SerialPrintln(F("5) Configure Analog Logging")); 45 | 46 | SerialPrintln(F("6) Detect / Configure Attached Devices")); 47 | 48 | SerialPrintln(F("7) Configure Power Options")); 49 | 50 | SerialPrintln(F("h) Print Sensor Helper Text (and return to logging)")); 51 | 52 | if (online.microSD) 53 | SerialPrintln(F("s) SD Card File Transfer")); 54 | 55 | SerialPrintln(F("r) Reset all settings to default")); 56 | 57 | SerialPrintln(F("q) Quit: Close log files and power down")); 58 | 59 | //SerialPrintln(F("d) Debug Menu")); 60 | 61 | SerialPrintln(F("x) Return to logging")); 62 | 63 | byte incoming = getByteChoice(menuTimeout, true); //Get byte choice and set DSERIAL & ZSERIAL 64 | 65 | if (incoming == '1') 66 | menuLogRate(); 67 | else if (incoming == '2') 68 | menuTimeStamp(); 69 | else if ((incoming == '3') && (online.IMU)) 70 | restartIMU = menuIMU(); 71 | else if ((incoming == '4') && (settings.useTxRxPinsForTerminal == false)) 72 | menuSerialLogging(); 73 | else if (incoming == '5') 74 | menuAnalogLogging(); 75 | else if (incoming == '6') 76 | menuAttachedDevices(); 77 | else if (incoming == '7') 78 | menuPower(); 79 | else if (incoming == 'h') 80 | { 81 | printHelperText(OL_OUTPUT_SERIAL); //printHelperText to terminal only 82 | break; //return to logging 83 | } 84 | else if (incoming == 'd') 85 | { 86 | menuDebug(); 87 | } 88 | else if (incoming == 's') 89 | { 90 | if (online.microSD) 91 | { 92 | //Close log files before showing sdCardMenu 93 | if (online.dataLogging == true) 94 | { 95 | sensorDataFile.sync(); 96 | updateDataFileAccess(&sensorDataFile); // Update the file access time & date 97 | sensorDataFile.close(); 98 | } 99 | if (online.serialLogging == true) 100 | { 101 | if (incomingBufferSpot > 0) 102 | { 103 | //Write the remainder of the buffer 104 | digitalWrite(PIN_STAT_LED, HIGH); //Toggle stat LED to indicating log recording 105 | serialDataFile.write(incomingBuffer, incomingBufferSpot); //Record the buffer to the card 106 | digitalWrite(PIN_STAT_LED, LOW); 107 | 108 | incomingBufferSpot = 0; 109 | 110 | lastSeriaLogSyncTime = rtcMillis(); //Reset the last sync time to now 111 | } 112 | 113 | serialDataFile.sync(); 114 | updateDataFileAccess(&serialDataFile); // Update the file access time & date 115 | serialDataFile.close(); 116 | } 117 | 118 | SerialPrintln(F("")); 119 | SerialPrintln(F("")); 120 | sdCardMenu(sdCardMenuTimeout); // Located in zmodem.ino 121 | SerialPrintln(F("")); 122 | SerialPrintln(F("")); 123 | 124 | if (online.dataLogging == true) 125 | { 126 | // Check if the current datafile was deleted 127 | if (sd.exists(sensorDataFileName) == false) 128 | strcpy(sensorDataFileName, findNextAvailableLog(settings.nextDataLogNumber, "dataLog")); 129 | beginDataLogging(); //180ms 130 | if (settings.showHelperText == true) 131 | printHelperText(OL_OUTPUT_SERIAL | OL_OUTPUT_SDCARD); //printHelperText to terminal and sensor file 132 | } 133 | if (online.serialLogging == true) 134 | { 135 | // Check if the current serial file was deleted 136 | if (sd.exists(serialDataFileName) == false) 137 | strcpy(serialDataFileName, findNextAvailableLog(settings.nextSerialLogNumber, "serialLog")); 138 | beginSerialLogging(); 139 | } 140 | } 141 | } 142 | else if (incoming == 'r') 143 | { 144 | SerialPrintln(F("\r\nResetting to factory defaults. Press 'y' to confirm: ")); 145 | byte bContinue = getByteChoice(menuTimeout); 146 | if (bContinue == 'y') 147 | { 148 | EEPROM.erase(); 149 | if (sd.exists("OLA_settings.txt")) 150 | sd.remove("OLA_settings.txt"); 151 | if (sd.exists("OLA_deviceSettings.txt")) 152 | sd.remove("OLA_deviceSettings.txt"); 153 | 154 | SerialPrint(F("Settings erased. Please reset OpenLog Artemis and open a terminal at ")); 155 | Serial.print((String)settings.serialTerminalBaudRate); 156 | if (settings.useTxRxPinsForTerminal == true) 157 | Serial1.print((String)settings.serialTerminalBaudRate); 158 | SerialPrintln(F("bps...")); 159 | while (1); 160 | } 161 | else 162 | SerialPrintln(F("Reset aborted")); 163 | } 164 | else if (incoming == 'q') 165 | { 166 | SerialPrintln(F("\r\nQuit? Press 'y' to confirm:")); 167 | byte bContinue = getByteChoice(menuTimeout); 168 | if (bContinue == 'y') 169 | { 170 | //Save files before going to sleep 171 | if (online.dataLogging == true) 172 | { 173 | sensorDataFile.sync(); 174 | updateDataFileAccess(&sensorDataFile); // Update the file access time & date 175 | sensorDataFile.close(); //No need to close files. https://forum.arduino.cc/index.php?topic=149504.msg1125098#msg1125098 176 | } 177 | if (online.serialLogging == true) 178 | { 179 | if (incomingBufferSpot > 0) 180 | { 181 | //Write the remainder of the buffer 182 | digitalWrite(PIN_STAT_LED, HIGH); //Toggle stat LED to indicating log recording 183 | serialDataFile.write(incomingBuffer, incomingBufferSpot); //Record the buffer to the card 184 | digitalWrite(PIN_STAT_LED, LOW); 185 | 186 | incomingBufferSpot = 0; 187 | 188 | lastSeriaLogSyncTime = rtcMillis(); //Reset the last sync time to now 189 | } 190 | 191 | serialDataFile.sync(); 192 | updateDataFileAccess(&serialDataFile); // Update the file access time & date 193 | serialDataFile.close(); 194 | } 195 | SerialPrint(F("Log files are closed. Please reset OpenLog Artemis and open a terminal at ")); 196 | Serial.print((String)settings.serialTerminalBaudRate); 197 | if (settings.useTxRxPinsForTerminal == true) 198 | Serial1.print((String)settings.serialTerminalBaudRate); 199 | SerialPrintln(F("bps...")); 200 | delay(sdPowerDownDelay); // Give the SD card time to shut down 201 | powerDownOLA(); 202 | } 203 | else 204 | SerialPrintln(F("Quit aborted")); 205 | } 206 | else if (incoming == 'x') 207 | break; 208 | else if (incoming == STATUS_GETBYTE_TIMEOUT) 209 | break; 210 | else 211 | printUnknown(incoming); 212 | } 213 | 214 | recordSystemSettings(); //Once all menus have exited, record the new settings to EEPROM and config file 215 | 216 | recordDeviceSettingsToFile(); //Record the current devices settings to device config file 217 | 218 | configureQwiicDevices(); //Reconfigure the qwiic devices in case any settings have changed 219 | 220 | if (restartIMU == true) 221 | beginIMU(); // Restart the IMU if required 222 | 223 | while (Serial.available()) Serial.read(); //Empty buffer of any newline chars 224 | 225 | if (settings.useTxRxPinsForTerminal == true) 226 | while (Serial1.available()) Serial1.read(); //Empty buffer of any newline chars 227 | 228 | //Reset measurements 229 | measurementCount = 0; 230 | totalCharactersPrinted = 0; 231 | //If we are sleeping between readings then we cannot rely on millis() as it is powered down 232 | //Use RTC instead 233 | measurementStartTime = rtcMillis(); 234 | 235 | //Edge case: after 10Hz reading, user sets the log rate above 2s mark. We never go to sleep because 236 | //takeReading is not true. And since we don't wake up, takeReading never gets set to true. 237 | //So we force it here. 238 | takeReading = true; 239 | } 240 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/menuPower.ino: -------------------------------------------------------------------------------- 1 | void menuPower() 2 | { 3 | while (1) 4 | { 5 | SerialPrintln(F("")); 6 | SerialPrintln(F("Menu: Configure Power Options")); 7 | 8 | SerialPrint(F("1) Turn off Qwiic bus power between readings (>2s): ")); 9 | if (settings.powerDownQwiicBusBetweenReads == true) SerialPrintln(F("Yes")); 10 | else SerialPrintln(F("No")); 11 | 12 | SerialPrint(F("2) Use pin 32 to Stop Logging: ")); 13 | if (settings.useGPIO32ForStopLogging == true) SerialPrintln(F("Yes")); 14 | else SerialPrintln(F("No")); 15 | 16 | #if(HARDWARE_VERSION_MAJOR >= 1) 17 | SerialPrint(F("3) Power LED During Sleep: ")); 18 | if (settings.enablePwrLedDuringSleep == true) SerialPrintln(F("Enabled")); 19 | else SerialPrintln(F("Disabled")); 20 | 21 | SerialPrint(F("4) Low Battery Voltage Detection: ")); 22 | if (settings.enableLowBatteryDetection == true) SerialPrintln(F("Enabled")); 23 | else SerialPrintln(F("Disabled")); 24 | 25 | SerialPrint(F("5) Low Battery Threshold (V): ")); 26 | char tempStr[16]; 27 | olaftoa(settings.lowBatteryThreshold, tempStr, 2, sizeof(tempStr) / sizeof(char)); 28 | SerialPrintf2("%s\r\n", tempStr); 29 | 30 | SerialPrint(F("6) VIN measurement correction factor: ")); 31 | olaftoa(settings.vinCorrectionFactor, tempStr, 3, sizeof(tempStr) / sizeof(char)); 32 | SerialPrintf2("%s\r\n", tempStr); 33 | #endif 34 | 35 | SerialPrint(F("7) Serial Tx and Rx pins during sleep are: ")); 36 | if (settings.serialTxRxDuringSleep == true) SerialPrintln(F("Enabled")); 37 | else SerialPrintln(F("Disabled")); 38 | 39 | SerialPrintln(F("x) Exit")); 40 | 41 | byte incoming = getByteChoice(menuTimeout); //Timeout after x seconds 42 | 43 | if (incoming == '1') 44 | { 45 | settings.powerDownQwiicBusBetweenReads ^= 1; 46 | } 47 | else if (incoming == '2') 48 | { 49 | if (settings.identifyBioSensorHubs == false) 50 | { 51 | if (settings.useGPIO32ForStopLogging == true) 52 | { 53 | // Disable stop logging 54 | settings.useGPIO32ForStopLogging = false; 55 | detachInterrupt(PIN_STOP_LOGGING); // Disable the interrupt 56 | pinMode(PIN_STOP_LOGGING, INPUT); // Remove the pull-up 57 | pin_config(PinName(PIN_STOP_LOGGING), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured 58 | stopLoggingSeen = false; // Make sure the flag is clear 59 | } 60 | else 61 | { 62 | // Enable stop logging 63 | settings.useGPIO32ForStopLogging = true; 64 | pinMode(PIN_STOP_LOGGING, INPUT_PULLUP); 65 | pin_config(PinName(PIN_STOP_LOGGING), g_AM_HAL_GPIO_INPUT_PULLUP); // Make sure the pin does actually get re-configured 66 | delay(1); // Let the pin stabilize 67 | attachInterrupt(PIN_STOP_LOGGING, stopLoggingISR, FALLING); // Enable the interrupt 68 | am_hal_gpio_pincfg_t intPinConfig = g_AM_HAL_GPIO_INPUT_PULLUP; 69 | intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; 70 | pin_config(PinName(PIN_STOP_LOGGING), intPinConfig); // Make sure the pull-up does actually stay enabled 71 | stopLoggingSeen = false; // Make sure the flag is clear 72 | settings.logA32 = false; // Disable analog logging on pin 32 73 | } 74 | } 75 | else 76 | { 77 | SerialPrintln(F("")); 78 | SerialPrintln(F("Stop logging via pin 32 is not possible. \"Detect Bio Sensor Pulse Oximeter\" is enabled.")); 79 | SerialPrintln(F("")); 80 | } 81 | } 82 | #if(HARDWARE_VERSION_MAJOR >= 1) 83 | else if (incoming == '3') 84 | { 85 | settings.enablePwrLedDuringSleep ^= 1; 86 | } 87 | else if (incoming == '4') 88 | { 89 | settings.enableLowBatteryDetection ^= 1; 90 | } 91 | else if (incoming == '5') 92 | { 93 | SerialPrintln(F("Please enter the new low battery threshold:")); 94 | float tempBT = (float)getDouble(menuTimeout); //Timeout after x seconds 95 | if ((tempBT < 3.0) || (tempBT > 6.0)) 96 | SerialPrintln(F("Error: Threshold out of range")); 97 | else 98 | settings.lowBatteryThreshold = tempBT; 99 | } 100 | else if (incoming == '6') 101 | { 102 | SerialPrintln(F("Please measure the voltage on the MEAS pin and enter it here:")); 103 | float tempCF = (float)getDouble(menuTimeout); //Timeout after x seconds 104 | int div3 = analogRead(PIN_VIN_MONITOR); //Read VIN across a 1/3 resistor divider 105 | float vin = (float)div3 * 3.0 * 2.0 / 16384.0; //Convert 1/3 VIN to VIN (14-bit resolution) 106 | tempCF = tempCF / vin; //Calculate the new correction factor 107 | if ((tempCF < 1.0) || (tempCF > 2.0)) 108 | SerialPrintln(F("Error: Correction factor out of range")); 109 | else 110 | settings.vinCorrectionFactor = tempCF; 111 | } 112 | #endif 113 | else if (incoming == '7') 114 | { 115 | settings.serialTxRxDuringSleep ^= 1; 116 | } 117 | else if (incoming == 'x') 118 | break; 119 | else if (incoming == STATUS_GETBYTE_TIMEOUT) 120 | break; 121 | else 122 | printUnknown(incoming); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/menuSerialLogging.ino: -------------------------------------------------------------------------------- 1 | //TODO Add time stamp option after a certain timeout 2 | 3 | void menuSerialLogging() 4 | { 5 | while (1) 6 | { 7 | SerialPrintln(F("")); 8 | SerialPrintln(F("Menu: Configure Serial Logging")); 9 | 10 | SerialPrint(F("1) Log serial data: ")); 11 | if (settings.logSerial == true) SerialPrintln(F("Enabled, analog logging on RX/A13 pin disabled")); 12 | else SerialPrintln(F("Disabled")); 13 | 14 | SerialPrint(F("2) Output serial data to TX pin: ")); 15 | if (settings.outputSerial == true) SerialPrintln(F("Enabled, analog logging on TX/A12 pin disabled")); 16 | else SerialPrintln(F("Disabled")); 17 | 18 | SerialPrint(F("3) zmodem start delay: ")); 19 | Serial.print(settings.zmodemStartDelay); 20 | if (settings.useTxRxPinsForTerminal == true) 21 | Serial1.print(settings.zmodemStartDelay); 22 | SerialPrintln(F(" seconds")); 23 | 24 | if ((settings.logSerial == true) || (settings.outputSerial == true)) 25 | { 26 | SerialPrint(F("4) Set serial baud rate: ")); 27 | Serial.print(settings.serialLogBaudRate); 28 | if (settings.useTxRxPinsForTerminal == true) 29 | Serial1.print(settings.zmodemStartDelay); 30 | SerialPrintln(F(" bps")); 31 | } 32 | 33 | if (settings.logSerial == true) // Suggested by @DennisMelamed in Issue #63 34 | { 35 | SerialPrint(F("5) Add RTC timestamp when token is received: ")); 36 | if (settings.timestampSerial == true) SerialPrintln(F("Enabled")); 37 | else SerialPrintln(F("Disabled")); 38 | 39 | SerialPrint(F("6) Timestamp token: ")); 40 | Serial.print(settings.timeStampToken); 41 | if (settings.useTxRxPinsForTerminal == true) 42 | Serial1.print(settings.timeStampToken); 43 | SerialPrint(F(" (Decimal)")); 44 | switch (settings.timeStampToken) 45 | { 46 | case 0x00: 47 | SerialPrintln(F(" = NULL")); 48 | break; 49 | case 0x03: 50 | SerialPrintln(F(" = End of Text")); 51 | break; 52 | case 0x0A: 53 | SerialPrintln(F(" = Line Feed")); 54 | break; 55 | case 0x0D: 56 | SerialPrintln(F(" = Carriage Return")); 57 | break; 58 | case 0x1B: 59 | SerialPrintln(F(" = Escape")); 60 | break; 61 | default: 62 | SerialPrintln(F("")); 63 | break; 64 | } 65 | } 66 | 67 | SerialPrintln(F("x) Exit")); 68 | 69 | byte incoming = getByteChoice(menuTimeout); //Timeout after x seconds 70 | 71 | if (incoming == '1') 72 | { 73 | if (settings.logSerial == false) 74 | { 75 | settings.logSerial = true; 76 | settings.logA13 = false; //Disable analog readings on RX pin 77 | 78 | beginSerialLogging(); //Start up port and log file (this will set online.serialLogging to true if successful) 79 | } 80 | else 81 | { 82 | if (online.serialLogging) 83 | { 84 | if (incomingBufferSpot > 0) 85 | { 86 | //Write the remainder of the buffer 87 | digitalWrite(PIN_STAT_LED, HIGH); //Toggle stat LED to indicating log recording 88 | serialDataFile.write(incomingBuffer, incomingBufferSpot); //Record the buffer to the card 89 | digitalWrite(PIN_STAT_LED, LOW); 90 | 91 | incomingBufferSpot = 0; 92 | 93 | lastSeriaLogSyncTime = rtcMillis(); //Reset the last sync time to now 94 | } 95 | 96 | //Shut it all down 97 | updateDataFileAccess(&serialDataFile); // Update the file access time & date 98 | serialDataFile.close(); 99 | 100 | online.serialLogging = false; 101 | } 102 | settings.logSerial = false; 103 | } 104 | } 105 | else if (incoming == '2') 106 | { 107 | if (settings.outputSerial == false) 108 | { 109 | settings.outputSerial = true; 110 | settings.logA12 = false; //Disable analog readings on TX pin 111 | 112 | beginSerialOutput(); //Start up port (this will set online.serialOutput to true if successful) 113 | } 114 | else 115 | { 116 | online.serialOutput = false; 117 | settings.outputSerial = false; 118 | } 119 | } 120 | else if (incoming == '3') 121 | { 122 | SerialPrint(F("Enter zmodem start delay (5 to 60): ")); 123 | int newDelay = getNumber(menuTimeout); //Timeout after x seconds 124 | if (newDelay < 5 || newDelay > 60) 125 | { 126 | SerialPrintln(F("Error: start delay out of range")); 127 | } 128 | else 129 | { 130 | settings.zmodemStartDelay = (uint8_t)newDelay; 131 | } 132 | } 133 | else if((settings.logSerial == true) || (settings.outputSerial == true)) 134 | { 135 | if (incoming == '4') 136 | { 137 | SerialPrint(F("Enter baud rate (1200 to 500000): ")); 138 | int newBaud = getNumber(menuTimeout); //Timeout after x seconds 139 | if (newBaud < 1200 || newBaud > 500000) 140 | { 141 | SerialPrintln(F("Error: baud rate out of range")); 142 | } 143 | else 144 | { 145 | configureSerial1TxRx(); 146 | settings.serialLogBaudRate = newBaud; 147 | Serial1.begin(settings.serialLogBaudRate); 148 | } 149 | } 150 | else if (incoming == '5') 151 | settings.timestampSerial ^= 1; 152 | else if (incoming == '6') 153 | { 154 | SerialPrint(F("Enter the timestamp token in decimal (0 to 255): ")); 155 | int newToken = getNumber(menuTimeout); //Timeout after x seconds 156 | if (newToken < 0 || newToken > 255) 157 | { 158 | SerialPrintln(F("Error: token out of range")); 159 | } 160 | else 161 | { 162 | settings.timeStampToken = (uint8_t)newToken; 163 | } 164 | } 165 | else if (incoming == 'x') 166 | return; 167 | else if (incoming == STATUS_GETBYTE_TIMEOUT) 168 | return; 169 | else 170 | printUnknown(incoming); 171 | } 172 | else if (incoming == 'x') 173 | return; 174 | else if (incoming == STATUS_GETBYTE_TIMEOUT) 175 | return; 176 | else 177 | printUnknown(incoming); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/menuTimeStamp.ino: -------------------------------------------------------------------------------- 1 | void menuTimeStamp() 2 | { 3 | while (1) 4 | { 5 | SerialPrintln(F("")); 6 | SerialPrintln(F("Menu: Configure Time Stamp")); 7 | SerialPrint(F("Current date/time: ")); 8 | myRTC.getTime(); 9 | 10 | char rtcDate[11]; // 10/12/2019 11 | char rtcDay[3]; 12 | char rtcMonth[3]; 13 | char rtcYear[5]; 14 | if (myRTC.dayOfMonth < 10) 15 | sprintf(rtcDay, "0%d", myRTC.dayOfMonth); 16 | else 17 | sprintf(rtcDay, "%d", myRTC.dayOfMonth); 18 | if (myRTC.month < 10) 19 | sprintf(rtcMonth, "0%d", myRTC.month); 20 | else 21 | sprintf(rtcMonth, "%d", myRTC.month); 22 | if (myRTC.year < 10) 23 | sprintf(rtcYear, "200%d", myRTC.year); 24 | else 25 | sprintf(rtcYear, "20%d", myRTC.year); 26 | if (settings.dateStyle == 0) 27 | sprintf(rtcDate, "%s/%s/%s,", rtcMonth, rtcDay, rtcYear); 28 | else if (settings.dateStyle == 1) 29 | sprintf(rtcDate, "%s/%s/%s,", rtcDay, rtcMonth, rtcYear); 30 | else 31 | sprintf(rtcDate, "%s/%s/%s,", rtcYear, rtcMonth, rtcDay); 32 | 33 | SerialPrint(rtcDate); 34 | SerialPrint(F(" ")); 35 | 36 | char rtcTime[13]; //09:14:37.41, 37 | int adjustedHour = myRTC.hour; 38 | if (settings.hour24Style == false) 39 | { 40 | if (adjustedHour > 12) adjustedHour -= 12; 41 | } 42 | char rtcHour[3]; 43 | char rtcMin[3]; 44 | char rtcSec[3]; 45 | char rtcHundredths[3]; 46 | if (adjustedHour < 10) 47 | sprintf(rtcHour, "0%d", adjustedHour); 48 | else 49 | sprintf(rtcHour, "%d", adjustedHour); 50 | if (myRTC.minute < 10) 51 | sprintf(rtcMin, "0%d", myRTC.minute); 52 | else 53 | sprintf(rtcMin, "%d", myRTC.minute); 54 | if (myRTC.seconds < 10) 55 | sprintf(rtcSec, "0%d", myRTC.seconds); 56 | else 57 | sprintf(rtcSec, "%d", myRTC.seconds); 58 | if (myRTC.hundredths < 10) 59 | sprintf(rtcHundredths, "0%d", myRTC.hundredths); 60 | else 61 | sprintf(rtcHundredths, "%d", myRTC.hundredths); 62 | sprintf(rtcTime, "%s:%s:%s.%s", rtcHour, rtcMin, rtcSec, rtcHundredths); 63 | 64 | SerialPrintln(rtcTime); 65 | 66 | SerialPrint(F("1) Log Date: ")); 67 | if (settings.logDate == true) SerialPrintln(F("Enabled")); 68 | else SerialPrintln(F("Disabled")); 69 | 70 | SerialPrint(F("2) Log Time: ")); 71 | if (settings.logTime == true) SerialPrintln(F("Enabled")); 72 | else SerialPrintln(F("Disabled")); 73 | 74 | if (settings.logDate == true || settings.logTime == true) 75 | { 76 | SerialPrintln(F("3) Set RTC to compiler macro time")); 77 | } 78 | 79 | if (settings.logDate == true) 80 | { 81 | SerialPrintln(F("4) Manually set RTC date")); 82 | 83 | SerialPrint(F("5) Toggle date style: ")); 84 | if (settings.dateStyle == 0) SerialPrintln(F("mm/dd/yyyy")); 85 | else if (settings.dateStyle == 1) SerialPrintln(F("dd/mm/yyyy")); 86 | else if (settings.dateStyle == 2) SerialPrintln(F("yyyy/mm/dd")); 87 | else SerialPrintln(F("ISO 8601")); 88 | } 89 | 90 | if (settings.logTime == true) 91 | { 92 | SerialPrintln(F("6) Manually set RTC time")); 93 | 94 | SerialPrint(F("7) Toggle time style: ")); 95 | if (settings.hour24Style == true) SerialPrintln(F("24 hour")); 96 | else SerialPrintln(F("12 hour")); 97 | } 98 | 99 | if (settings.logDate == true || settings.logTime == true) 100 | { 101 | if (isUbloxAttached() == true) 102 | { 103 | SerialPrintln(F("8) Synchronize RTC to GPS")); 104 | } 105 | SerialPrint(F("9) Local offset from UTC: ")); 106 | Serial.println(settings.localUTCOffset); 107 | if (settings.useTxRxPinsForTerminal == true) 108 | Serial1.println(settings.localUTCOffset); 109 | } 110 | 111 | SerialPrint(F("10) Log Microseconds: ")); 112 | if (settings.logMicroseconds == true) SerialPrintln(F("Enabled")); 113 | else SerialPrintln(F("Disabled")); 114 | 115 | SerialPrintln(F("x) Exit")); 116 | 117 | int incoming = getNumber(menuTimeout); //Timeout after x seconds 118 | 119 | if (incoming == 1) 120 | settings.logDate ^= 1; 121 | else if (incoming == 2) 122 | settings.logTime ^= 1; 123 | else if (incoming == 10) 124 | settings.logMicroseconds ^= 1; 125 | else if (incoming == STATUS_PRESSED_X) 126 | return; 127 | else if (incoming == STATUS_GETNUMBER_TIMEOUT) 128 | return; 129 | 130 | if ((settings.logDate == true) || (settings.logTime == true)) 131 | { 132 | //Options 3, 8, 9 133 | if (incoming == 3) 134 | { 135 | myRTC.setToCompilerTime(); //Set RTC using the system __DATE__ and __TIME__ macros from compiler 136 | SerialPrintln(F("RTC set to compiler time")); 137 | } 138 | else if ((incoming == 8) && (isUbloxAttached() == true)) 139 | { 140 | myRTC.getTime(); // Get the RTC date and time (just in case getGPSDateTime fails) 141 | int dd = myRTC.dayOfMonth, mm = myRTC.month, yy = myRTC.year, h = myRTC.hour, m = myRTC.minute, s = myRTC.seconds, ms = (myRTC.hundredths * 10); 142 | bool dateValid, timeValid; 143 | getGPSDateTime(yy, mm, dd, h, m, s, ms, dateValid, timeValid); // Get the GPS date and time, corrected for localUTCOffset 144 | myRTC.setTime((ms / 10), s, m, h, dd, mm, (yy - 2000)); //Manually set RTC 145 | lastSDFileNameChangeTime = rtcMillis(); // Record the time of the file name change 146 | SerialPrintln(F("RTC set to GPS (UTC) time")); 147 | if ((dateValid == false) || (timeValid == false)) 148 | { 149 | SerialPrintln(F("\r\nWarning: the GPS time or date was not valid. Please try again.\r\n")); 150 | } 151 | } 152 | else if (incoming == 9) 153 | { 154 | SerialPrint(F("Enter the local hour offset from UTC (-12 to 14): ")); 155 | float offset = (float)getDouble(menuTimeout); //Timeout after x seconds 156 | if (offset < -12 || offset > 14) 157 | SerialPrintln(F("Error: Offset is out of range")); 158 | else 159 | settings.localUTCOffset = offset; 160 | } 161 | } 162 | 163 | if (settings.logDate == true) 164 | { 165 | //4 and 5 166 | if (incoming == 4) //Manually set RTC date 167 | { 168 | myRTC.getTime(); 169 | int dd = myRTC.dayOfMonth, mm = myRTC.month, yy = myRTC.year, h = myRTC.hour, m = myRTC.minute, s = myRTC.seconds; 170 | 171 | SerialPrint(F("Enter current two digit year: ")); 172 | yy = getNumber(menuTimeout); //Timeout after x seconds 173 | if (yy > 2000 && yy < 2100) yy -= 2000; 174 | 175 | SerialPrint(F("Enter current month (1 to 12): ")); 176 | mm = getNumber(menuTimeout); //Timeout after x seconds 177 | 178 | SerialPrint(F("Enter current day (1 to 31): ")); 179 | dd = getNumber(menuTimeout); //Timeout after x seconds 180 | 181 | myRTC.getTime(); 182 | h = myRTC.hour; m = myRTC.minute; s = myRTC.seconds; 183 | myRTC.setTime(0, s, m, h, dd, mm, yy); //Manually set RTC 184 | lastSDFileNameChangeTime = rtcMillis(); // Record the time of the file name change 185 | } 186 | else if (incoming == 5) 187 | { 188 | settings.dateStyle += 1; 189 | if (settings.dateStyle == 4) 190 | settings.dateStyle = 0; 191 | } 192 | } 193 | 194 | if (settings.logTime == true) 195 | { 196 | //6 and 7 197 | if (incoming == 6) //Manually set time 198 | { 199 | myRTC.getTime(); 200 | int dd = myRTC.dayOfMonth, mm = myRTC.month, yy = myRTC.year, h = myRTC.hour, m = myRTC.minute, s = myRTC.seconds; 201 | 202 | SerialPrint(F("Enter current hour (0 to 23): ")); 203 | h = getNumber(menuTimeout); //Timeout after x seconds 204 | 205 | SerialPrint(F("Enter current minute (0 to 59): ")); 206 | m = getNumber(menuTimeout); //Timeout after x seconds 207 | 208 | SerialPrint(F("Enter current second (0 to 59): ")); 209 | s = getNumber(menuTimeout); //Timeout after x seconds 210 | 211 | myRTC.setTime(0, s, m, h, dd, mm, yy); //Manually set RTC 212 | lastSDFileNameChangeTime = rtcMillis(); // Record the time of the file name change 213 | } 214 | else if (incoming == 7) 215 | { 216 | settings.hour24Style ^= 1; 217 | } 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/timeStamp.ino: -------------------------------------------------------------------------------- 1 | //Query the RTC and put the appropriately formatted (according to settings) 2 | //string into the passed buffer. timeStringBuffer should be at least 37 chars long 3 | //Code modified by @DennisMelamed in PR #70 4 | void getTimeString(char timeStringBuffer[]) 5 | { 6 | //reset the buffer 7 | timeStringBuffer[0] = '\0'; 8 | 9 | myRTC.getTime(); 10 | 11 | if (settings.logDate) 12 | { 13 | char rtcDate[12]; // 10/12/2019, 14 | char rtcDay[3]; 15 | char rtcMonth[3]; 16 | char rtcYear[5]; 17 | if (myRTC.dayOfMonth < 10) 18 | sprintf(rtcDay, "0%d", myRTC.dayOfMonth); 19 | else 20 | sprintf(rtcDay, "%d", myRTC.dayOfMonth); 21 | if (myRTC.month < 10) 22 | sprintf(rtcMonth, "0%d", myRTC.month); 23 | else 24 | sprintf(rtcMonth, "%d", myRTC.month); 25 | if (myRTC.year < 10) 26 | sprintf(rtcYear, "200%d", myRTC.year); 27 | else 28 | sprintf(rtcYear, "20%d", myRTC.year); 29 | if (settings.dateStyle == 0) 30 | sprintf(rtcDate, "%s/%s/%s,", rtcMonth, rtcDay, rtcYear); 31 | else if (settings.dateStyle == 1) 32 | sprintf(rtcDate, "%s/%s/%s,", rtcDay, rtcMonth, rtcYear); 33 | else if (settings.dateStyle == 2) 34 | sprintf(rtcDate, "%s/%s/%s,", rtcYear, rtcMonth, rtcDay); 35 | else // if (settings.dateStyle == 3) 36 | sprintf(rtcDate, "%s-%s-%sT", rtcYear, rtcMonth, rtcDay); 37 | strcat(timeStringBuffer, rtcDate); 38 | } 39 | 40 | if ((settings.logTime) || ((settings.logDate) && (settings.dateStyle == 3))) 41 | { 42 | char rtcTime[16]; //09:14:37.41, or 09:14:37+00:00, 43 | int adjustedHour = myRTC.hour; 44 | if (settings.hour24Style == false) 45 | { 46 | if (adjustedHour > 12) adjustedHour -= 12; 47 | } 48 | char rtcHour[3]; 49 | char rtcMin[3]; 50 | char rtcSec[3]; 51 | char rtcHundredths[3]; 52 | char timeZoneH[4]; 53 | char timeZoneM[4]; 54 | if (adjustedHour < 10) 55 | sprintf(rtcHour, "0%d", adjustedHour); 56 | else 57 | sprintf(rtcHour, "%d", adjustedHour); 58 | if (myRTC.minute < 10) 59 | sprintf(rtcMin, "0%d", myRTC.minute); 60 | else 61 | sprintf(rtcMin, "%d", myRTC.minute); 62 | if (myRTC.seconds < 10) 63 | sprintf(rtcSec, "0%d", myRTC.seconds); 64 | else 65 | sprintf(rtcSec, "%d", myRTC.seconds); 66 | if (myRTC.hundredths < 10) 67 | sprintf(rtcHundredths, "0%d", myRTC.hundredths); 68 | else 69 | sprintf(rtcHundredths, "%d", myRTC.hundredths); 70 | if (settings.localUTCOffset >= 0) 71 | { 72 | if (settings.localUTCOffset < 10) 73 | sprintf(timeZoneH, "+0%d", (int)settings.localUTCOffset); 74 | else 75 | sprintf(timeZoneH, "+%d", (int)settings.localUTCOffset); 76 | } 77 | else 78 | { 79 | if (settings.localUTCOffset <= -10) 80 | sprintf(timeZoneH, "-%d", 0 - (int)settings.localUTCOffset); 81 | else 82 | sprintf(timeZoneH, "-0%d", 0 - (int)settings.localUTCOffset); 83 | } 84 | int tzMins = (int)((settings.localUTCOffset - (float)((int)settings.localUTCOffset)) * 60.0); 85 | if (tzMins < 0) 86 | tzMins = 0 - tzMins; 87 | if (tzMins < 10) 88 | sprintf(timeZoneM, ":0%d", tzMins); 89 | else 90 | sprintf(timeZoneM, ":%d", tzMins); 91 | if ((settings.logDate) && (settings.dateStyle == 3)) 92 | { 93 | sprintf(rtcTime, "%s:%s:%s%s%s,", rtcHour, rtcMin, rtcSec, timeZoneH, timeZoneM); 94 | strcat(timeStringBuffer, rtcTime); 95 | } 96 | if (settings.logTime) 97 | { 98 | sprintf(rtcTime, "%s:%s:%s.%s,", rtcHour, rtcMin, rtcSec, rtcHundredths); 99 | strcat(timeStringBuffer, rtcTime); 100 | } 101 | } 102 | 103 | if (settings.logMicroseconds) 104 | { 105 | // Convert uint64_t to string 106 | // Based on printLLNumber by robtillaart 107 | // https://forum.arduino.cc/index.php?topic=143584.msg1519824#msg1519824 108 | char microsecondsRev[20]; // Char array to hold to microseconds (reversed order) 109 | char microseconds[20]; // Char array to hold to microseconds (correct order) 110 | uint64_t microsNow = micros(); 111 | unsigned int i = 0; 112 | 113 | if (microsNow == 0ULL) // if usBetweenReadings is zero, set tempTime to "0" 114 | { 115 | microseconds[0] = '0'; 116 | microseconds[1] = ','; 117 | microseconds[2] = 0; 118 | } 119 | 120 | else 121 | { 122 | while (microsNow > 0) 123 | { 124 | microsecondsRev[i++] = (microsNow % 10) + '0'; // divide by 10, convert the remainder to char 125 | microsNow /= 10; // divide by 10 126 | } 127 | unsigned int j = 0; 128 | while (i > 0) 129 | { 130 | microseconds[j++] = microsecondsRev[--i]; // reverse the order 131 | microseconds[j] = ','; 132 | microseconds[j+1] = 0; // mark the end with a NULL 133 | } 134 | } 135 | 136 | strcat(timeStringBuffer, microseconds); 137 | } 138 | } 139 | 140 | //Gets the current time from GPS 141 | //Adjust the hour by local hour offset 142 | //Adjust the date as necessary 143 | // 144 | //Note: this function should only be called if we know that a u-blox GNSS is actually connected 145 | // 146 | void getGPSDateTime(int &year, int &month, int &day, int &hour, int &minute, int &second, int &millisecond, bool &dateValid, bool &timeValid) { 147 | //Get latested date/time from GPS 148 | //These will be extracted from a single PVT packet 149 | getUbloxDateTime(year, month, day, hour, minute, second, millisecond, dateValid, timeValid); 150 | //Do it twice - to make sure the data is fresh 151 | getUbloxDateTime(year, month, day, hour, minute, second, millisecond, dateValid, timeValid); 152 | 153 | adjustToLocalDateTime(year, month, day, hour, minute, settings.localUTCOffset); 154 | } 155 | 156 | //Given the date and hour, calculate local date/time 157 | //Adjust the hour by local hour offset 158 | //Adjust the hour by DST as necessary 159 | //Adjust the date as necessary 160 | //Leap year is taken into account but does not interact with DST (DST happens later in March) 161 | void adjustToLocalDateTime(int &year, int &month, int &day, int &hour, int &minute, float localUTCOffset) { 162 | 163 | //Apply any offset to UTC 164 | hour += (int)localUTCOffset; 165 | 166 | //Apply minutes offset 167 | int tzMins = (int)((localUTCOffset - (float)((int)localUTCOffset)) * 60.0); 168 | minute += tzMins; 169 | if (minute >= 60) 170 | { 171 | hour += 1; 172 | minute -= 60; 173 | } 174 | else if (minute < 0) 175 | { 176 | hour -= 1; 177 | minute += 60; 178 | } 179 | 180 | //If the adjusted hour is outside 0 to 23, then adjust date as necessary 181 | correctDate(year, month, day, hour); 182 | 183 | //Should we correct for daylight savings time? 184 | if (settings.correctForDST == true) 185 | { 186 | //Calculate DST adjustment based on date and local offset 187 | hour += findUSDSTadjustment(year, month, day, hour); 188 | 189 | //DST may have pushed a date change so do one more time 190 | correctDate(year, month, day, hour); 191 | } 192 | } 193 | 194 | //If the given hour is outside 0 to 23, then adjust date and hour as necessary 195 | void correctDate(int &year, int &month, int &day, int &hour) 196 | { 197 | //Adjust date forwards if the local hour offset causes it 198 | if (hour > 23) 199 | { 200 | hour -= 24; 201 | day++; 202 | bool adjustMonth = false; 203 | if (month == 1 && day == 32) 204 | adjustMonth = true; 205 | else if (month == 2) 206 | { 207 | if (year % 4 == 0 && day == 30) // Note: this will fail in 2100. 2100 is not a leap year. 208 | adjustMonth = true; 209 | else if (day == 29) 210 | adjustMonth = true; 211 | } 212 | else if (month == 3 && day == 32) 213 | adjustMonth = true; 214 | else if (month == 4 && day == 31) 215 | adjustMonth = true; 216 | else if (month == 5 && day == 32) 217 | adjustMonth = true; 218 | else if (month == 6 && day == 31) 219 | adjustMonth = true; 220 | else if (month == 7 && day == 32) 221 | adjustMonth = true; 222 | else if (month == 8 && day == 32) 223 | adjustMonth = true; 224 | else if (month == 9 && day == 31) 225 | adjustMonth = true; 226 | else if (month == 10 && day == 32) 227 | adjustMonth = true; 228 | else if (month == 11 && day == 31) 229 | adjustMonth = true; 230 | else if (month == 11 && day == 32) 231 | adjustMonth = true; 232 | 233 | if (adjustMonth == true) 234 | { 235 | month++; 236 | day = 1; 237 | if (month == 13) 238 | { 239 | month = 1; 240 | year++; 241 | } 242 | } 243 | } 244 | 245 | //Adjust date backwards if the local hour offset causes it 246 | if (hour < 0) 247 | { 248 | hour += 24; 249 | day--; 250 | if (day == 0) 251 | { 252 | //Move back a month and reset day to the last day of the new month 253 | month--; 254 | switch (month) 255 | { 256 | case 0: //December 257 | year--; 258 | month = 12; 259 | day = 31; 260 | break; 261 | case 1: //January 262 | day = 31; 263 | break; 264 | case 2: //February 265 | if (year % 4 == 0) day = 29; // Note: this will fail in 2100. 2100 is not a leap year. 266 | else day = 28; 267 | break; 268 | case 3: //March 269 | day = 31; 270 | break; 271 | case 4: //April 272 | day = 30; 273 | break; 274 | case 5: //May 275 | day = 31; 276 | break; 277 | case 6: //June 278 | day = 30; 279 | break; 280 | case 7: //July 281 | day = 31; 282 | break; 283 | case 8: //August 284 | day = 31; 285 | break; 286 | case 9: //September 287 | day = 30; 288 | break; 289 | case 10: //October 290 | day = 31; 291 | break; 292 | case 11: //November 293 | day = 30; 294 | break; 295 | } 296 | } 297 | } 298 | } 299 | 300 | //Given a year/month/day/current UTC/local offset give me the amount to adjust the current hour 301 | //Clocks adjust at 2AM so we need the local hour as well 302 | int findUSDSTadjustment(int year, byte month, byte day, byte localHour) 303 | { 304 | //Since 2007 DST starts on the second Sunday in March and ends the first Sunday of November 305 | //Let's just assume it's going to be this way for awhile (silly US government!) 306 | //Example from: http://stackoverflow.com/questions/5590429/calculating-daylight-savings-time-from-only-date 307 | 308 | //boolean dst = false; //Assume we're not in DST 309 | if (month > 3 && month < 11) return (1); //DST is happening! 310 | if (month < 3 || month > 11) return (0); //DST is not happening 311 | 312 | int firstSunday = getFirstSunday(year, month); 313 | int secondSunday = firstSunday + 7; 314 | 315 | //In March, we are in DST if we are on or after the second sunday. 316 | if (month == 3) 317 | { 318 | if (day > secondSunday) return (1); //We are in later march 319 | if (day < secondSunday) return (0); //No DST 320 | if (day == secondSunday) 321 | { 322 | if (localHour >= 2) return (1); //It's after 2AM, spring forward, add hour to clock 323 | else return (0); //It's before 2AM, no DST 324 | } 325 | } 326 | 327 | //In November we must be before the first Sunday to be DST. 328 | if (month == 11) 329 | { 330 | if (day < firstSunday) return (1); //Still in DST 331 | if (day > firstSunday) return (0); //No DST 332 | if (day == firstSunday) //Today is the last day of DST 333 | { 334 | //At 2AM the clock gets moved back to 1AM 335 | //When we check the local hour we need to assume DST is still being applied (at least for the 12, 1AM, 2AM checks) 336 | if ((localHour + 1) >= 2) return (0); //It's 2AM or later, fall back, remove hour from clock 337 | else return (1); //It's before 2AM, continue adding DST 338 | } 339 | } 340 | 341 | return (0); //We should not get here 342 | } 343 | 344 | //Given year/month, find day of first Sunday 345 | byte getFirstSunday(int year, int month) 346 | { 347 | int day = 1; 348 | while (dayOfWeek(year, month, day) != 0) 349 | day++; 350 | return (day); 351 | } 352 | 353 | //Given the current year/month/day 354 | //Returns 0 (Sunday) through 6 (Saturday) for the day of the week 355 | //From: http://en.wikipedia.org/wiki/Calculating_the_day_of_the_week 356 | //This function assumes the month from the caller is 1-12 357 | char dayOfWeek(int year, int month, int day) 358 | { 359 | //Devised by Tomohiko Sakamoto in 1993, it is accurate for any Gregorian date: 360 | static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 }; 361 | year -= month < 3; 362 | return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7; 363 | } 364 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/zmodem.h: -------------------------------------------------------------------------------- 1 | // From: http://www.raspberryginger.com/jbailey/minix/html/zmodem_8h-source.html 2 | #ifndef ZMODEM_H 3 | #define ZMODEM_H 4 | #include "zmodem_config.h" 5 | #include "zmodem_fixes.h" 6 | /* 7 | * Z M O D E M . H Manifest constants for ZMODEM 8 | * application to application file transfer protocol 9 | * 05-23-87 Chuck Forsberg Omen Technology Inc 10 | */ 11 | #define ZPAD '*' /* 052 Padding character begins frames */ 12 | #define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ 13 | #define ZDLEE (ZDLE^0100) /* Escaped ZDLE as transmitted */ 14 | #define ZBIN 'A' /* Binary frame indicator */ 15 | #define ZHEX 'B' /* HEX frame indicator */ 16 | #define ZBIN32 'C' /* Binary frame with 32 bit FCS */ 17 | 18 | /* Frame types (see array "frametypes" in zm.c) */ 19 | #define ZRQINIT 0 /* Request receive init */ 20 | #define ZRINIT 1 /* Receive init */ 21 | #define ZSINIT 2 /* Send init sequence (optional) */ 22 | #define ZACK 3 /* ACK to above */ 23 | #define ZFILE 4 /* File name from sender */ 24 | #define ZSKIP 5 /* To sender: skip this file */ 25 | #define ZNAK 6 /* Last packet was garbled */ 26 | #define ZABORT 7 /* Abort batch transfers */ 27 | #define ZFIN 8 /* Finish session */ 28 | #define ZRPOS 9 /* Resume data trans at this position */ 29 | #define ZDATA 10 /* Data packet(s) follow */ 30 | #define ZEOF 11 /* End of file */ 31 | #define ZFERR 12 /* Fatal Read or Write error Detected */ 32 | #define ZCRC 13 /* Request for file CRC and response */ 33 | #define ZCHALLENGE 14 /* Receiver's Challenge */ 34 | #define ZCOMPL 15 /* Request is complete */ 35 | #define ZCAN 16 /* Other end canned session with CAN*5 */ 36 | #define ZFREECNT 17 /* Request for free bytes on filesystem */ 37 | #define ZCOMMAND 18 /* Command from sending program */ 38 | #define ZSTDERR 19 /* Output to standard error, data follows */ 39 | 40 | /* ZDLE sequences */ 41 | #define ZCRCE 'h' /* CRC next, frame ends, header packet follows */ 42 | #define ZCRCG 'i' /* CRC next, frame continues nonstop */ 43 | #define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */ 44 | #define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */ 45 | #define ZRUB0 'l' /* Translate to rubout 0177 */ 46 | #define ZRUB1 'm' /* Translate to rubout 0377 */ 47 | 48 | /* zdlread return values (internal) */ 49 | /* -1 is general error, -2 is timeout */ 50 | #define GOTOR 0400 51 | #define GOTCRCE (ZCRCE|GOTOR) /* ZDLE-ZCRCE received */ 52 | #define GOTCRCG (ZCRCG|GOTOR) /* ZDLE-ZCRCG received */ 53 | #define GOTCRCQ (ZCRCQ|GOTOR) /* ZDLE-ZCRCQ received */ 54 | #define GOTCRCW (ZCRCW|GOTOR) /* ZDLE-ZCRCW received */ 55 | #define GOTCAN (GOTOR|030) /* CAN*5 seen */ 56 | 57 | /* Byte positions within header array */ 58 | #define ZF0 3 /* First flags byte */ 59 | #define ZF1 2 60 | #define ZF2 1 61 | #define ZF3 0 62 | #define ZP0 0 /* Low order 8 bits of position */ 63 | #define ZP1 1 64 | #define ZP2 2 65 | #define ZP3 3 /* High order 8 bits of file position */ 66 | 67 | /* Bit Masks for ZRINIT flags byte ZF0 */ 68 | #define CANFDX 01 /* Rx can send and receive true FDX */ 69 | #define CANOVIO 02 /* Rx can receive data during disk I/O */ 70 | #define CANBRK 04 /* Rx can send a break signal */ 71 | #define CANCRY 010 /* Receiver can decrypt */ 72 | #define CANLZW 020 /* Receiver can uncompress */ 73 | #define CANFC32 040 /* Receiver can use 32 bit Frame Check */ 74 | #define ESCCTL 0100 /* Receiver expects ctl chars to be escaped */ 75 | #define ESC8 0200 /* Receiver expects 8th bit to be escaped */ 76 | 77 | /* Parameters for ZSINIT frame */ 78 | //#define ZATTNLEN 32 /* Max length of attention string */ 79 | #define ZATTNLEN 4 /* Need to take back as many bytes as possible, hopefully no one really sends a lengthy ATTN */ 80 | 81 | /* Bit Masks for ZSINIT flags byte ZF0 */ 82 | #define TESCCTL 0100 /* Transmitter expects ctl chars to be escaped */ 83 | #define TESC8 0200 /* Transmitter expects 8th bit to be escaped */ 84 | 85 | /* Parameters for ZFILE frame */ 86 | /* Conversion options one of these in ZF0 */ 87 | #define ZCBIN 1 /* Binary transfer - inhibit conversion */ 88 | #define ZCNL 2 /* Convert NL to local end of line convention */ 89 | #define ZCRESUM 3 /* Resume interrupted file transfer */ 90 | /* Management include options, one of these ored in ZF1 */ 91 | #define ZMSKNOLOC 0200 /* Skip file if not present at rx */ 92 | /* Management options, one of these ored in ZF1 */ 93 | #define ZMMASK 037 /* Mask for the choices below */ 94 | #define ZMNEWL 1 /* Transfer if source newer or longer */ 95 | #define ZMCRC 2 /* Transfer if different file CRC or length */ 96 | #define ZMAPND 3 /* Append contents to existing file (if any) */ 97 | #define ZMCLOB 4 /* Replace existing file */ 98 | #define ZMNEW 5 /* Transfer if source newer */ 99 | /* Number 5 is alive ... */ 100 | #define ZMDIFF 6 /* Transfer if dates or lengths different */ 101 | #define ZMPROT 7 /* Protect destination file */ 102 | /* Transport options, one of these in ZF2 */ 103 | #define ZTLZW 1 /* Lempel-Ziv compression */ 104 | #define ZTCRYPT 2 /* Encryption */ 105 | #define ZTRLE 3 /* Run Length encoding */ 106 | /* Extended options for ZF3, bit encoded */ 107 | #define ZXSPARS 64 /* Encoding for sparse file operations */ 108 | 109 | /* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */ 110 | #define ZCACK1 1 /* Acknowledge, then do command */ 111 | 112 | //#ifdef NOTDEF 113 | // Pete (El Supremo) - fix up extern int 114 | /* Globals used by ZMODEM functions */ 115 | extern uint8_t Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ 116 | extern uint8_t Rxtype; /* Type of header received */ 117 | extern int Rxcount; /* Count of data bytes received */ 118 | //extern int Zrwindow; /* RX window size (controls garbage count) */ 119 | extern int Rxtimeout; /* Tenths of seconds to wait for something */ 120 | extern char Rxhdr[4]; /* Received header */ 121 | extern char Txhdr[4]; /* Transmitted header */ 122 | extern long Rxpos; /* Received file position */ 123 | extern long Txpos; /* Transmitted file position */ 124 | extern int8_t Txfcs32; /* TURE means send binary frames with 32 bit FCS */ 125 | extern int8_t Crc32t; /* Display flag indicating 32 bit CRC being sent */ 126 | extern int8_t Crc32; /* Display flag indicating 32 bit CRC being received */ 127 | //extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ 128 | extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ 129 | //#endif 130 | 131 | /* crctab.c */ 132 | _PROTOTYPE(long UPDC32 , (int b , long c )); 133 | 134 | /* rbsb.c */ 135 | #ifndef ARDUINO 136 | _PROTOTYPE(void from_cu , (void)); 137 | _PROTOTYPE(void cucheck , (void)); 138 | _PROTOTYPE(int rdchk , (int f )); 139 | _PROTOTYPE(int rdchk , (int f )); 140 | _PROTOTYPE(void sendbrk , (void)); 141 | #endif 142 | /* zm.c */ 143 | 144 | _PROTOTYPE(void zsbhdr , (int type , char *hdr )); 145 | _PROTOTYPE(void zshhdr , (int type , char *hdr )); 146 | _PROTOTYPE(void zsdata , (char *buf , int length , int frameend )); 147 | _PROTOTYPE(int zrdata , (char *buf , int length )); 148 | _PROTOTYPE(int zgethdr , (char *hdr , int eflag )); 149 | _PROTOTYPE(int zrbhdr , (char *hdr )); 150 | _PROTOTYPE(int zrbhdr32 , (char *hdr )); 151 | _PROTOTYPE(int zrhhdr , (char *hdr )); 152 | _PROTOTYPE(void zputhex , (int c )); 153 | _PROTOTYPE(int zsendline2 , (int c )); 154 | _PROTOTYPE(int zgethex , (void)); 155 | _PROTOTYPE(int zgeth1 , (void)); 156 | //_PROTOTYPE(int zdlread , (void)); 157 | _PROTOTYPE(int noxrd7 , (void)); 158 | _PROTOTYPE(void stohdr , (long pos )); 159 | _PROTOTYPE(long rclhdr , (char *hdr )); 160 | 161 | /* rz.c sz.c */ 162 | #ifndef ARDUINO 163 | void vfile(); 164 | #else 165 | #define vfile(a, ... ) 166 | #endif 167 | 168 | _PROTOTYPE(void bibi , (int n )); 169 | _PROTOTYPE(int wcs , (const char *oname)); 170 | _PROTOTYPE(void saybibi, (void)); 171 | 172 | int wctxpn(char *name); 173 | int wcrx(); 174 | 175 | /* Ward Christensen / CP/M parameters - Don't change these! */ 176 | #define ENQ 005 177 | #define CAN ('X'&037) 178 | #define XOFF ('s'&037) 179 | #define XON ('q'&037) 180 | #define SOH 1 181 | #define STX 2 182 | #define EOT 4 183 | #define ACK 6 184 | #define NAK 025 185 | #define CPMEOF 032 186 | #define WANTCRC 0103 /* send C not NAK to get crc not checksum */ 187 | #define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */ 188 | //#define TIMEOUT (-2) 189 | #define RCDO (-3) 190 | #define Tx_RETRYMAX 10 191 | #define Rx_RETRYMAX 5 192 | 193 | #endif 194 | 195 | /* End of ZMODEM.H */ 196 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/zmodem_config.h: -------------------------------------------------------------------------------- 1 | #ifndef ZMODEM_CONFIG_H 2 | #define ZMODEM_CONFIG_H 3 | 4 | #define Progname F("Arduino ZModem (for the OLA): v2.1.3") 5 | 6 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - The SparkFun MP3 shield (which contains an SDCard) 7 | // doesn't operate properly with the SDFat library (SPI related?) unless the MP3 library is 8 | // initialized as well. If you are using a SparkFun MP3 shield as your SDCard interface, 9 | // the following macro must be defined. Otherwise, comment it out. 10 | 11 | //#define SFMP3_SHIELD 12 | 13 | //#ifndef SFMP3_SHIELD 14 | //// Make sure you set this correctly to define the pin where you have connected your SDCard's 15 | //// CS pin! 16 | //#define SD_SEL 9 17 | //#endif 18 | 19 | // Serial output for debugging info 20 | //#define DSERIAL Serial 21 | //Stream *DSERIAL; 22 | 23 | // The Serial port for the Zmodem connection 24 | // must not be the same as DSERIAL unless all 25 | // debugging output to DSERIAL is removed 26 | //#define ZSERIAL Serial3 27 | //#define ZSERIAL Serial 28 | //Stream *ZSERIAL; 29 | 30 | //#ifdef TEENSYDUINO 31 | // #ifndef SERIAL_TX_BUFFER_SIZE 32 | // #define SERIAL_TX_BUFFER_SIZE 64 33 | // #endif 34 | //#endif 35 | 36 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - Adjust the baud rate to suit your board and needs 37 | //#define ZMODEM_SPEED 57600 38 | 39 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - For smaller boards (32K flash, 2K RAM) it may only 40 | // be possible to have only one or some of the following 3 features enabled at a time: 1) File manager 41 | // commands (DEL, MD, RD, etc.), 2) SZ (Send ZModem) or 3) RZ (Receive ZModem). Large boards 42 | // like the Arduino Mega can handle all 3 features in a single sketch easily, but for smaller boards like 43 | // Uno or Nano, it's very tight. It seems to work okay, but if you don't need the file manager commands, 44 | // or one of send or receive, comment out the associated macro and it'll slim the sketch down some. 45 | 46 | // Uncomment the following macro to build a version with file manipulation commands. 47 | 48 | #define ARDUINO_SMALL_MEMORY_INCLUDE_FILE_MGR 49 | 50 | // Uncomment the following macro to build a version with SZ enabled. 51 | 52 | #define ARDUINO_SMALL_MEMORY_INCLUDE_SZ 53 | 54 | // Uncomment the following macro to build a version with RZ enabled 55 | 56 | //#define ARDUINO_SMALL_MEMORY_INCLUDE_RZ 57 | 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/zmodem_crc16.cpp: -------------------------------------------------------------------------------- 1 | //#include - not supported in v2 of the Apollo3 core 2 | 3 | 4 | /* 5 | * Crc calculation stuff 6 | */ 7 | #ifndef ZMODEM_CRC16_CPP 8 | #define ZMODEM_CRC16_CPP 9 | /* crctab calculated by Mark G. Mendel, Network Systems Corporation */ 10 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - Moved to PROGMEM 11 | //PROGMEM static const unsigned short crctab[256] = { - not supported in v2 of the Apollo3 core 12 | static const unsigned short crctab[256] = { 13 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 14 | 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 15 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 16 | 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 17 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 18 | 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 19 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 20 | 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 21 | 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 22 | 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 23 | 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 24 | 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 25 | 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 26 | 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 27 | 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 28 | 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 29 | 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 30 | 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 31 | 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 32 | 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 33 | 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 34 | 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 35 | 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 36 | 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 37 | 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 38 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 39 | 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 40 | 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 41 | 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 42 | 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 43 | 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 44 | 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 45 | }; 46 | 47 | /* 48 | * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. 49 | * NOTE: First argument must be in range 0 to 255. 50 | * Second argument is referenced twice. 51 | * 52 | * Programmers may incorporate any or all code into their programs, 53 | * giving proper credit within the source. Publication of the 54 | * source routines is permitted so long as proper credit is given 55 | * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, 56 | * Omen Technology. 57 | */ 58 | // Pete (El Supremo) Can't parenthesize this in a way that gets rid of a compiler 59 | // warning on line 283 of zmodem_zm.cpp 60 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - No warning in Arduino IDE 1.6.5 61 | 62 | #ifdef ARDUINO 63 | #define updcrc(cp, crc) ( ( (pgm_read_word(crctab + ((crc >> 8) & 255)) ^ (crc << 8) ) ^ cp)) 64 | #else 65 | #define updcrc(cp, crc) ( ( (crctab[((crc >> 8) & 255)] ^ (crc << 8) ) ^ cp)) 66 | #endif 67 | 68 | /* 69 | * Copyright (C) 1986 Gary S. Brown. You may use this program, or 70 | * code or tables extracted from it, as desired without restriction. 71 | */ 72 | 73 | /* First, the polynomial itself and its table of feedback terms. The */ 74 | /* polynomial is */ 75 | /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ 76 | /* Note that we take it "backwards" and put the highest-order term in */ 77 | /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ 78 | /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ 79 | /* the MSB being 1. */ 80 | 81 | /* Note that the usual hardware shift register implementation, which */ 82 | /* is what we're using (we're merely optimizing it by doing eight-bit */ 83 | /* chunks at a time) shifts bits into the lowest-order term. In our */ 84 | /* implementation, that means shifting towards the right. Why do we */ 85 | /* do it this way? Because the calculated CRC must be transmitted in */ 86 | /* order from highest-order term to lowest-order term. UARTs transmit */ 87 | /* characters in order from LSB to MSB. By storing the CRC this way, */ 88 | /* we hand it to the UART in the order low-byte to high-byte; the UART */ 89 | /* sends each low-bit to hight-bit; and the result is transmission bit */ 90 | /* by bit from highest- to lowest-order term without requiring any bit */ 91 | /* shuffling on our part. Reception works similarly. */ 92 | 93 | /* The feedback terms table consists of 256, 32-bit entries. Notes: */ 94 | /* */ 95 | /* The table can be generated at runtime if desired; code to do so */ 96 | /* is shown later. It might not be obvious, but the feedback */ 97 | /* terms simply represent the results of eight shift/xor opera- */ 98 | /* tions for all combinations of data and CRC register values. */ 99 | /* */ 100 | /* The values must be right-shifted by eight bits by the "updcrc" */ 101 | /* logic; the shift must be unsigned (bring in zeroes). On some */ 102 | /* hardware you could probably optimize the shift in assembler by */ 103 | /* using byte-swap instructions. */ 104 | 105 | // Pete (El_Supremo) add 'unsigned' 106 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - Moved to PROGMEM 107 | //PROGMEM static const unsigned long cr3tab[] = { /* CRC polynomial 0xedb88320 */ - not supported in v2 of the Apollo3 core 108 | static const unsigned long cr3tab[] = { /* CRC polynomial 0xedb88320 */ 109 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 110 | 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 111 | 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 112 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 113 | 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 114 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 115 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 116 | 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 117 | 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 118 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 119 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 120 | 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 121 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 122 | 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 123 | 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 124 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 125 | 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 126 | 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 127 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 128 | 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 129 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 130 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 131 | 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 132 | 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 133 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 134 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 135 | 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 136 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 137 | 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 138 | 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 139 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 140 | 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 141 | }; 142 | 143 | #ifdef NFGM 144 | long 145 | UPDC32(b, c) 146 | long c; 147 | { 148 | return (pgm_read_dword(cr3tab + (((int)c ^ b) & 0xff)) ^ ((c >> 8) & 0x00FFFFFF)); 149 | // return (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)); 150 | } 151 | 152 | #else 153 | #ifdef ARDUINO 154 | #define UPDC32(b, c) (pgm_read_dword(cr3tab + (((int)c ^ b) & 0xff)) ^ ((c >> 8) & 0x00FFFFFF)) 155 | #else 156 | #define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) 157 | #endif 158 | 159 | #endif 160 | 161 | /* End of crctab.c */ 162 | #endif 163 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/zmodem_fixes.h: -------------------------------------------------------------------------------- 1 | /* 2 | Keep everything for ANSI prototypes. 3 | From: http://stackoverflow.com/questions/2607853/why-prototype-is-used-header-files 4 | */ 5 | 6 | #ifndef ZMODEM_FIXES_H 7 | #define ZMODEM_FIXES_H 8 | 9 | #define SERIAL_TX_BUFFER_SIZE SERIAL_BUFFER_SIZE // AP3_UART_RINGBUFF_SIZE 10 | 11 | //////////////////////////////////////////////////////// 12 | 13 | 14 | #define _PROTOTYPE(function, params) function params 15 | 16 | #include 17 | 18 | extern SdFat sd; 19 | 20 | #include 21 | 22 | // Dylan (monte_carlo_ecm, bitflipper, etc.) - changed serial read/write to macros to try to squeeze 23 | // out higher speed 24 | 25 | #define READCHECK 26 | #define TYPICAL_SERIAL_TIMEOUT 1200 27 | 28 | extern Stream *ZSERIAL; 29 | extern int Rxtimeout; 30 | #define TIMEOUT (-2) 31 | 32 | //#define readline(timeout) ({ char _c; ZSERIAL->readBytes(&_c, 1) > 0 ? _c : TIMEOUT; }) 33 | //#define zdlread(void) ({ int _z; ((_z = readline(Rxtimeout)) & 0140) ? _z : zdlread2(_z); }) 34 | //#define sendline(_c) ZSERIAL->write(char(_c)) 35 | //#define sendline(_c) ({ if (ZSERIAL->availableForWrite() > SERIAL_TX_BUFFER_SIZE / 2) ZSERIAL->flush(); ZSERIAL->write(char(_c)); }) 36 | //#define zsendline(_z) ({ (_z & 0140 ) ? sendline(_z) : zsendline2(_z); }) 37 | 38 | int readline(int timeout); // Header. Code is in zmodem_zm.cpp 39 | 40 | void sendline(int _c); // Header. Code is in zmodem_zm.cpp 41 | #define xsendline(c) sendline(c) 42 | 43 | //int zdlread2(int); // Header. Code is in zmodem_zm.cpp 44 | 45 | void zsendline(int _z); // Header. Code is in zmodem_zm.cpp 46 | 47 | //int zdlread(void) 48 | //{ 49 | // int _z; 50 | // if ((_z = readline(Rxtimeout)) & 0140) 51 | // return (_z); 52 | // else 53 | // return (zdlread2(_z)); 54 | //} 55 | 56 | void sendzrqinit(void); 57 | int wctxpn(const char *name); 58 | #define ARDUINO_RECV 59 | //int wcrx(void); 60 | int wcreceive(int argc, char **argp); 61 | 62 | extern int Filcnt; 63 | 64 | #define register int 65 | 66 | // If this is not defined the default is 1024. 67 | // It must be a power of 2 68 | 69 | #ifdef ARDUINO_SMALL_MEMORY 70 | #define TXBSIZE 1024 71 | #else 72 | #define TXBSIZE 1024 73 | #endif 74 | 75 | #define sleep(x) delay((x)*1000L) 76 | #define signal(x,y) 77 | 78 | // Handle the calls to exit - one has SS_NORMAL 79 | #define SS_NORMAL 0 80 | #define exit(n) 81 | 82 | // For now, evaluate it to zero so that it does not 83 | // enter the "if" statement's clause 84 | #define setjmp(...) 85 | 86 | #define printf(s, ... ) DSERIAL->println(s); 87 | #define fprintf(...) 88 | 89 | // fseek(in, Rxpos, 0) 90 | //#define fseek(fd, pos, rel) sdfile->seekSet(pos) 91 | //#define fclose(c) 92 | 93 | // ignore calls to mode() function in rbsb.cpp 94 | #define mode(a) 95 | 96 | #define sendbrk() 97 | 98 | //extern int Fromcu; 99 | void purgeline(void); 100 | 101 | #ifndef UNSL 102 | #define UNSL unsigned 103 | #endif 104 | 105 | void flushmo(void); 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /Firmware/OpenLog_Artemis/zmodem_zm.h: -------------------------------------------------------------------------------- 1 | #ifndef ZMODEM_ZM_h 2 | #define ZMODEM_ZM_H 3 | 4 | #define VERSION Progname 5 | 6 | extern char oneKbuf[1025]; 7 | 8 | //extern int Rxtimeout; /* Tenths of seconds to wait for something */ 9 | 10 | /* Globals used by ZMODEM functions */ 11 | extern uint8_t Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ 12 | extern uint8_t Rxtype; /* Type of header received */ 13 | extern int Rxcount; /* Count of data bytes received */ 14 | extern char Rxhdr[4]; /* Received header */ 15 | extern char Txhdr[4]; /* Transmitted header */ 16 | extern long Rxpos; /* Received file position */ 17 | extern long Txpos; /* Transmitted file position */ 18 | extern int8_t Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ 19 | extern int8_t Crc32t; /* Display flag indicating 32 bit CRC being sent */ 20 | extern int8_t Crc32; /* Display flag indicating 32 bit CRC being received */ 21 | //extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ 22 | extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ 23 | 24 | extern int lastsent; /* Last char we sent */ 25 | extern uint8_t Not8bit; /* Seven bits seen on header */ 26 | 27 | //extern char *frametypes[]; 28 | 29 | extern uint32_t Baudrate; 30 | #define xsendline(c) sendline(c) 31 | //int readline(int timeout); 32 | 33 | #define OK 0 34 | #define FALSE 0 35 | #define TRUE 1 36 | #undef ERROR 37 | #define ERROR (-1) 38 | 39 | #ifndef ARDUINO 40 | #define zperr(a, ... ) 41 | #else 42 | /* 43 | #define WHERESTR "[FILE : %s, FUNC : %s, LINE : %d]: " 44 | #define WHEREARG __FILE__,__func__,__LINE__ 45 | #define DEBUG(...) {char s[256]; sprintf(s, __VA_ARGS__); DSERIAL->println(s);} 46 | #define zperr(_fmt, ...) DEBUG(WHERESTR _fmt, WHEREARG,__VA_ARGS__) 47 | */ 48 | //#define zperr(...) {char s[256]; sprintf(s, __VA_ARGS__); DSERIAL->println(s);} 49 | #define zperr(...) 50 | #endif 51 | 52 | void bttyout(int c); 53 | 54 | #define Zmodem 1 /* ZMODEM protocol requested */ 55 | extern uint8_t Verbose; 56 | extern char zconv; /* ZMODEM file conversion request */ 57 | extern char zmanag; /* ZMODEM file management request */ 58 | extern char ztrans; /* ZMODEM file transport request */ 59 | extern uint8_t Zctlesc; /* Encode control characters */ 60 | //extern int Zrwindow; /* RX window size (controls garbage count) */ 61 | //extern int Nozmodem; 62 | #define Nozmodem 0 63 | #define Lzmanag 0 64 | //extern int Restricted; 65 | //extern int Quiet; 66 | #define Quiet 0 67 | extern uint8_t Eofseen; 68 | 69 | extern uint8_t firstsec; 70 | extern char Lastrx; 71 | extern char Crcflg; 72 | extern uint8_t errors; 73 | // This is declared in the main sketch .ino 74 | //extern char *Progname; 75 | #endif 76 | -------------------------------------------------------------------------------- /Firmware/Test Sketches/IMU_DMP_MultipleSensors/IMU_DMP_MultipleSensors.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************** 2 | * This is an example for OpenLog Artemis - based on a DMP example from the ICM-20948 Library: 3 | * 4 | * Example9_DMP_MultipleSensors.ino 5 | * ICM 20948 Arduino Library Demo 6 | * Initialize the DMP based on the TDK InvenSense ICM20948_eMD_nucleo_1.0 example-icm20948 7 | * Paul Clark, August 17th 2021 8 | * Based on original code by: 9 | * Owen Lyke @ SparkFun Electronics 10 | * Original Creation Date: April 17 2019 11 | * 12 | * This version uses v2.1.0 of the SparkFun Apollo3 (artemis) core. 13 | * 14 | * The Board should be set to SparkFun Apollo3 \ RedBoard Artemis ATP. 15 | * 16 | * ** This example is based on InvenSense's _confidential_ Application Note "Programming Sequence for DMP Hardware Functions". 17 | * ** We are grateful to InvenSense for sharing this with us. 18 | * 19 | * ** Important note: by default the DMP functionality is disabled in the library 20 | * ** as the DMP firmware takes up 14301 Bytes of program memory. 21 | * ** To use the DMP, you will need to: 22 | * ** Edit ICM_20948_C.h 23 | * ** Uncomment line 29: #define ICM_20948_USE_DMP 24 | * ** Save changes 25 | * ** If you are using Windows, you can find ICM_20948_C.h in: 26 | * ** Documents\Arduino\libraries\SparkFun_ICM-20948_ArduinoLibrary\src\util 27 | * 28 | * Please see License.md for the license information. 29 | * 30 | * Distributed as-is; no warranty is given. 31 | ***************************************************************/ 32 | 33 | // OLA Specifics: 34 | const byte PIN_IMU_POWER = 27; // The Red SparkFun version of the OLA (V10) uses pin 27 35 | //const byte PIN_IMU_POWER = 22; // The Black SparkX version of the OLA (X04) uses pin 22 36 | const byte PIN_IMU_INT = 37; 37 | const byte PIN_IMU_CHIP_SELECT = 44; 38 | const byte PIN_SPI_SCK = 5; 39 | const byte PIN_SPI_CIPO = 6; 40 | const byte PIN_SPI_COPI = 7; 41 | 42 | #include "ICM_20948.h" // Click here to get the library: http://librarymanager/All#SparkFun_ICM_20948_IMU 43 | 44 | #define SERIAL_PORT Serial 45 | 46 | #define SPI_PORT SPI // Your desired SPI port. OLA uses SPI. 47 | #define CS_PIN PIN_IMU_CHIP_SELECT // Which pin you connect CS to. OLA uses pin 44. 48 | 49 | ICM_20948_SPI myICM; // Create an ICM_20948_SPI object 50 | 51 | void setup() { 52 | 53 | // Start the SPI port 54 | SPI_PORT.begin(); 55 | // 'Kickstart' the SPI hardware at 4MHz - this changes the CIPO pin mode 56 | SPI_PORT.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); 57 | SPI_PORT.transfer(0x00); 58 | SPI_PORT.endTransaction(); 59 | // *Now* enable CIPO pull-up on the OLA 60 | enableCIPOpullUp(); 61 | 62 | pinMode(PIN_IMU_CHIP_SELECT, OUTPUT); 63 | digitalWrite(PIN_IMU_CHIP_SELECT, HIGH); //Be sure IMU is deselected 64 | pinMode(PIN_IMU_INT, INPUT_PULLUP); 65 | 66 | //Reset ICM by power cycling it 67 | imuPowerOff(); 68 | 69 | delay(10); 70 | 71 | imuPowerOn(); // Enable power for the OLA IMU 72 | 73 | delay(100); // Wait for the IMU to power up 74 | 75 | SERIAL_PORT.begin(115200); // Start the serial console 76 | SERIAL_PORT.println(F("OpenLog Artemis ICM-20948 Example")); 77 | 78 | delay(100); 79 | 80 | while (SERIAL_PORT.available()) // Make sure the serial RX buffer is empty 81 | SERIAL_PORT.read(); 82 | 83 | SERIAL_PORT.println(F("Press any key to continue...")); 84 | 85 | while (!SERIAL_PORT.available()) // Wait for the user to press a key (send any serial character) 86 | ; 87 | 88 | //myICM.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial 89 | 90 | // Initialize the ICM-20948 91 | // If the DMP is enabled, .begin performs a minimal startup. We need to configure the sample mode etc. manually. 92 | myICM.begin( CS_PIN, SPI_PORT, 4000000); //Set IMU SPI rate to 4MHz 93 | bool initialized = (myICM.status == ICM_20948_Stat_Ok); 94 | 95 | while( !initialized ){ 96 | 97 | enableCIPOpullUp(); // Enable CIPO pull-up on the OLA 98 | 99 | //Reset ICM by power cycling it 100 | imuPowerOff(); 101 | 102 | delay(10); 103 | 104 | imuPowerOn(); // Enable power for the OLA IMU 105 | 106 | delay(100); // Wait for the IMU to power up 107 | 108 | myICM.begin( CS_PIN, SPI_PORT, 4000000); //Set IMU SPI rate to 4MHz 109 | 110 | SERIAL_PORT.print( F("Initialization of the IMU returned: ") ); 111 | SERIAL_PORT.println( myICM.statusString() ); 112 | if( myICM.status != ICM_20948_Stat_Ok ){ 113 | SERIAL_PORT.println( F("Trying again...") ); 114 | delay(500); 115 | }else{ 116 | initialized = true; 117 | } 118 | } 119 | 120 | SERIAL_PORT.println(F("IMU connected!")); 121 | 122 | bool success = true; // Use success to show if the DMP configuration was successful 123 | 124 | // Initialize the DMP. initializeDMP is a weak function. You can overwrite it if you want to e.g. to change the sample rate 125 | success &= (myICM.initializeDMP() == ICM_20948_Stat_Ok); 126 | 127 | // DMP sensor options are defined in ICM_20948_DMP.h 128 | // INV_ICM20948_SENSOR_ACCELEROMETER (16-bit accel) 129 | // INV_ICM20948_SENSOR_GYROSCOPE (16-bit gyro + 32-bit calibrated gyro) 130 | // INV_ICM20948_SENSOR_RAW_ACCELEROMETER (16-bit accel) 131 | // INV_ICM20948_SENSOR_RAW_GYROSCOPE (16-bit gyro + 32-bit calibrated gyro) 132 | // INV_ICM20948_SENSOR_MAGNETIC_FIELD_UNCALIBRATED (16-bit compass) 133 | // INV_ICM20948_SENSOR_GYROSCOPE_UNCALIBRATED (16-bit gyro) 134 | // INV_ICM20948_SENSOR_STEP_DETECTOR (Pedometer Step Detector) 135 | // INV_ICM20948_SENSOR_STEP_COUNTER (Pedometer Step Detector) 136 | // INV_ICM20948_SENSOR_GAME_ROTATION_VECTOR (32-bit 6-axis quaternion) 137 | // INV_ICM20948_SENSOR_ROTATION_VECTOR (32-bit 9-axis quaternion + heading accuracy) 138 | // INV_ICM20948_SENSOR_GEOMAGNETIC_ROTATION_VECTOR (32-bit Geomag RV + heading accuracy) 139 | // INV_ICM20948_SENSOR_GEOMAGNETIC_FIELD (32-bit calibrated compass) 140 | // INV_ICM20948_SENSOR_GRAVITY (32-bit 6-axis quaternion) 141 | // INV_ICM20948_SENSOR_LINEAR_ACCELERATION (16-bit accel + 32-bit 6-axis quaternion) 142 | // INV_ICM20948_SENSOR_ORIENTATION (32-bit 9-axis quaternion + heading accuracy) 143 | 144 | // Enable the DMP Game Rotation Vector sensor (Quat6) 145 | success &= (myICM.enableDMPSensor(INV_ICM20948_SENSOR_GAME_ROTATION_VECTOR) == ICM_20948_Stat_Ok); 146 | 147 | // Enable additional sensors / features 148 | success &= (myICM.enableDMPSensor(INV_ICM20948_SENSOR_RAW_GYROSCOPE) == ICM_20948_Stat_Ok); 149 | success &= (myICM.enableDMPSensor(INV_ICM20948_SENSOR_RAW_ACCELEROMETER) == ICM_20948_Stat_Ok); 150 | success &= (myICM.enableDMPSensor(INV_ICM20948_SENSOR_MAGNETIC_FIELD_UNCALIBRATED) == ICM_20948_Stat_Ok); 151 | 152 | // Configuring DMP to output data at multiple ODRs: 153 | // DMP is capable of outputting multiple sensor data at different rates to FIFO. 154 | // Setting value can be calculated as follows: 155 | // Value = (DMP running rate / ODR ) - 1 156 | // E.g. For a 5Hz ODR rate when DMP is running at 55Hz, value = (55/5) - 1 = 10. 157 | success &= (myICM.setDMPODRrate(DMP_ODR_Reg_Quat6, 10) == ICM_20948_Stat_Ok); // Set to 5Hz 158 | success &= (myICM.setDMPODRrate(DMP_ODR_Reg_Accel, 54) == ICM_20948_Stat_Ok); // Set to 1Hz 159 | success &= (myICM.setDMPODRrate(DMP_ODR_Reg_Gyro, 54) == ICM_20948_Stat_Ok); // Set to 1Hz 160 | success &= (myICM.setDMPODRrate(DMP_ODR_Reg_Gyro_Calibr, 54) == ICM_20948_Stat_Ok); // Set to 1Hz 161 | success &= (myICM.setDMPODRrate(DMP_ODR_Reg_Cpass, 54) == ICM_20948_Stat_Ok); // Set to 1Hz 162 | success &= (myICM.setDMPODRrate(DMP_ODR_Reg_Cpass_Calibr, 54) == ICM_20948_Stat_Ok); // Set to 1Hz 163 | 164 | // Enable the FIFO 165 | success &= (myICM.enableFIFO() == ICM_20948_Stat_Ok); 166 | 167 | // Enable the DMP 168 | success &= (myICM.enableDMP() == ICM_20948_Stat_Ok); 169 | 170 | // Reset DMP 171 | success &= (myICM.resetDMP() == ICM_20948_Stat_Ok); 172 | 173 | // Reset FIFO 174 | success &= (myICM.resetFIFO() == ICM_20948_Stat_Ok); 175 | 176 | // Check success 177 | if (success) 178 | { 179 | SERIAL_PORT.println(F("DMP enabled!")); 180 | } 181 | else 182 | { 183 | SERIAL_PORT.println(F("Enable DMP failed!")); 184 | SERIAL_PORT.println(F("Please check that you have uncommented line 29 (#define ICM_20948_USE_DMP) in ICM_20948_C.h...")); 185 | while (1) 186 | ; // Do nothing more 187 | } 188 | } 189 | 190 | void loop() 191 | { 192 | // Read any DMP data waiting in the FIFO 193 | // Note: 194 | // readDMPdataFromFIFO will return ICM_20948_Stat_FIFONoDataAvail if no data is available. 195 | // If data is available, readDMPdataFromFIFO will attempt to read _one_ frame of DMP data. 196 | // readDMPdataFromFIFO will return ICM_20948_Stat_FIFOIncompleteData if a frame was present but was incomplete 197 | // readDMPdataFromFIFO will return ICM_20948_Stat_Ok if a valid frame was read. 198 | // readDMPdataFromFIFO will return ICM_20948_Stat_FIFOMoreDataAvail if a valid frame was read _and_ the FIFO contains more (unread) data. 199 | icm_20948_DMP_data_t data; 200 | myICM.readDMPdataFromFIFO(&data); 201 | 202 | if ((myICM.status == ICM_20948_Stat_Ok) || (myICM.status == ICM_20948_Stat_FIFOMoreDataAvail)) // Was valid data available? 203 | { 204 | //SERIAL_PORT.print(F("Received data! Header: 0x")); // Print the header in HEX so we can see what data is arriving in the FIFO 205 | //if ( data.header < 0x1000) SERIAL_PORT.print( "0" ); // Pad the zeros 206 | //if ( data.header < 0x100) SERIAL_PORT.print( "0" ); 207 | //if ( data.header < 0x10) SERIAL_PORT.print( "0" ); 208 | //SERIAL_PORT.println( data.header, HEX ); 209 | 210 | if ((data.header & DMP_header_bitmap_Quat6) > 0) // Check for orientation data (Quat9) 211 | { 212 | // Q0 value is computed from this equation: Q0^2 + Q1^2 + Q2^2 + Q3^2 = 1. 213 | // In case of drift, the sum will not add to 1, therefore, quaternion data need to be corrected with right bias values. 214 | // The quaternion data is scaled by 2^30. 215 | 216 | //SERIAL_PORT.printf("Quat6 data is: Q1:%ld Q2:%ld Q3:%ld\r\n", data.Quat6.Data.Q1, data.Quat6.Data.Q2, data.Quat6.Data.Q3); 217 | 218 | // Scale to +/- 1 219 | double q1 = ((double)data.Quat6.Data.Q1) / 1073741824.0; // Convert to double. Divide by 2^30 220 | double q2 = ((double)data.Quat6.Data.Q2) / 1073741824.0; // Convert to double. Divide by 2^30 221 | double q3 = ((double)data.Quat6.Data.Q3) / 1073741824.0; // Convert to double. Divide by 2^30 222 | 223 | SERIAL_PORT.print(F("Q1:")); 224 | SERIAL_PORT.print(q1, 3); 225 | SERIAL_PORT.print(F(" Q2:")); 226 | SERIAL_PORT.print(q2, 3); 227 | SERIAL_PORT.print(F(" Q3:")); 228 | SERIAL_PORT.println(q3, 3); 229 | } 230 | 231 | if ((data.header & DMP_header_bitmap_Accel) > 0) // Check for Accel 232 | { 233 | float acc_x = (float)data.Raw_Accel.Data.X; // Extract the raw accelerometer data 234 | float acc_y = (float)data.Raw_Accel.Data.Y; 235 | float acc_z = (float)data.Raw_Accel.Data.Z; 236 | 237 | SERIAL_PORT.print(F("Accel: X:")); 238 | SERIAL_PORT.print(acc_x); 239 | SERIAL_PORT.print(F(" Y:")); 240 | SERIAL_PORT.print(acc_y); 241 | SERIAL_PORT.print(F(" Z:")); 242 | SERIAL_PORT.println(acc_z); 243 | } 244 | 245 | if ((data.header & DMP_header_bitmap_Gyro) > 0) // Check for Gyro 246 | { 247 | float x = (float)data.Raw_Gyro.Data.X; // Extract the raw gyro data 248 | float y = (float)data.Raw_Gyro.Data.Y; 249 | float z = (float)data.Raw_Gyro.Data.Z; 250 | 251 | SERIAL_PORT.print(F("Gyro: X:")); 252 | SERIAL_PORT.print(x); 253 | SERIAL_PORT.print(F(" Y:")); 254 | SERIAL_PORT.print(y); 255 | SERIAL_PORT.print(F(" Z:")); 256 | SERIAL_PORT.println(z); 257 | } 258 | 259 | if ((data.header & DMP_header_bitmap_Compass) > 0) // Check for Compass 260 | { 261 | float x = (float)data.Compass.Data.X; // Extract the compass data 262 | float y = (float)data.Compass.Data.Y; 263 | float z = (float)data.Compass.Data.Z; 264 | 265 | SERIAL_PORT.print(F("Compass: X:")); 266 | SERIAL_PORT.print(x); 267 | SERIAL_PORT.print(F(" Y:")); 268 | SERIAL_PORT.print(y); 269 | SERIAL_PORT.print(F(" Z:")); 270 | SERIAL_PORT.println(z); 271 | } 272 | } 273 | 274 | if (myICM.status != ICM_20948_Stat_FIFOMoreDataAvail) // If more data is available then we should read it right away - and not delay 275 | { 276 | delay(10); 277 | } 278 | } 279 | 280 | // OLA Specifics 281 | 282 | void imuPowerOn() 283 | { 284 | pinMode(PIN_IMU_POWER, OUTPUT); 285 | digitalWrite(PIN_IMU_POWER, HIGH); 286 | } 287 | void imuPowerOff() 288 | { 289 | pinMode(PIN_IMU_POWER, OUTPUT); 290 | digitalWrite(PIN_IMU_POWER, LOW); 291 | } 292 | 293 | void enableCIPOpullUp() // updated for v2.1.0 of the Apollo3 core 294 | { 295 | //Add 1K5 pull-up on CIPO 296 | am_hal_gpio_pincfg_t cipoPinCfg = g_AM_BSP_GPIO_IOM0_MISO; 297 | cipoPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; 298 | pin_config(PinName(PIN_SPI_CIPO), cipoPinCfg); 299 | } 300 | 301 | void disableCIPOpullUp() // updated for v2.1.0 of the Apollo3 core 302 | { 303 | am_hal_gpio_pincfg_t cipoPinCfg = g_AM_BSP_GPIO_IOM0_MISO; 304 | pin_config(PinName(PIN_SPI_CIPO), cipoPinCfg); 305 | } 306 | -------------------------------------------------------------------------------- /Firmware/Test Sketches/OLA_IMU_Basics/OLA_IMU_Basics.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************** 2 | * Testing basic functionality of the ICM 20948 on the OpenLog Artemis. 3 | * Select "SparkFun Apollo3" \ SparkFun RedBoard Artemis ATP" as the board. 4 | * 5 | * Based on: 6 | * 7 | * Example1_Basics.ino 8 | * ICM 20948 Arduino Library Demo 9 | * Use the default configuration to stream 9-axis IMU data 10 | * Owen Lyke @ SparkFun Electronics 11 | * Original Creation Date: April 17 2019 12 | * 13 | * This code is beerware; if you see me (or any other SparkFun employee) at the 14 | * local, and you've found our code helpful, please buy us a round! 15 | * 16 | * Distributed as-is; no warranty is given. 17 | ***************************************************************/ 18 | 19 | // OLA Specifics: 20 | const byte PIN_IMU_POWER = 27; // The Red SparkFun version of the OLA (V10) uses pin 27 21 | //const byte PIN_IMU_POWER = 22; // The Black SparkX version of the OLA (X04) uses pin 22 22 | const byte PIN_IMU_INT = 37; 23 | const byte PIN_IMU_CHIP_SELECT = 44; 24 | const byte PIN_SPI_SCK = 5; 25 | const byte PIN_SPI_CIPO = 6; 26 | const byte PIN_SPI_COPI = 7; 27 | 28 | 29 | #include "ICM_20948.h" // Click here to get the library: http://librarymanager/All#SparkFun_ICM_20948_IMU 30 | 31 | #define USE_SPI // Uncomment this to use SPI 32 | 33 | #define SERIAL_PORT Serial 34 | 35 | #define SPI_PORT SPI // Your desired SPI port. Used only when "USE_SPI" is defined 36 | #define CS_PIN PIN_IMU_CHIP_SELECT // Which pin you connect CS to. Used only when "USE_SPI" is defined. OLA uses pin 44. 37 | 38 | #define WIRE_PORT Wire // Your desired Wire port. Used when "USE_SPI" is not defined 39 | #define AD0_VAL 1 // The value of the last bit of the I2C address. 40 | // On the SparkFun 9DoF IMU breakout the default is 1, and when 41 | // the ADR jumper is closed the value becomes 0 42 | 43 | #ifdef USE_SPI 44 | ICM_20948_SPI myICM; // If using SPI create an ICM_20948_SPI object 45 | #else 46 | ICM_20948_I2C myICM; // Otherwise create an ICM_20948_I2C object 47 | #endif 48 | 49 | 50 | void setup() { 51 | 52 | #ifdef USE_SPI 53 | SPI_PORT.begin(); 54 | 55 | pinMode(PIN_IMU_CHIP_SELECT, OUTPUT); 56 | digitalWrite(PIN_IMU_CHIP_SELECT, HIGH); //Be sure IMU is deselected 57 | 58 | enableCIPOpullUp(); // Enable CIPO pull-up on the OLA 59 | 60 | //There is a quirk in v2.1 of the Apollo3 mbed core which means that the first SPI transaction will 61 | //disable the pull-up on CIPO. We need to do a fake transaction and then re-enable the pull-up 62 | //to work around this... 63 | #if defined(ARDUINO_ARCH_MBED) 64 | SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); // Do a fake transaction 65 | SPI.endTransaction(); 66 | enableCIPOpullUp(); // Re-enable the CIPO pull-up 67 | #endif 68 | 69 | #else 70 | WIRE_PORT.begin(); 71 | WIRE_PORT.setClock(400000); 72 | #endif 73 | 74 | //Reset ICM by power cycling it 75 | imuPowerOff(); 76 | 77 | delay(10); 78 | 79 | imuPowerOn(); // Enable power for the OLA IMU 80 | 81 | delay(100); // Wait for the IMU to power up 82 | 83 | SERIAL_PORT.begin(115200); 84 | while(!SERIAL_PORT){}; 85 | 86 | bool initialized = false; 87 | while( !initialized ){ 88 | 89 | #ifdef USE_SPI 90 | myICM.begin( CS_PIN, SPI_PORT ); 91 | #else 92 | myICM.begin( WIRE_PORT, AD0_VAL ); 93 | #endif 94 | 95 | SERIAL_PORT.print( F("Initialization of the sensor returned: ") ); 96 | SERIAL_PORT.println( myICM.statusString() ); 97 | if( myICM.status != ICM_20948_Stat_Ok ){ 98 | SERIAL_PORT.println( "Trying again..." ); 99 | delay(500); 100 | }else{ 101 | initialized = true; 102 | } 103 | } 104 | } 105 | 106 | void loop() { 107 | 108 | if( myICM.dataReady() ){ 109 | myICM.getAGMT(); // The values are only updated when you call 'getAGMT' 110 | // printRawAGMT( myICM.agmt ); // Uncomment this to see the raw values, taken directly from the agmt structure 111 | printScaledAGMT( myICM.agmt); // This function takes into account the sclae settings from when the measurement was made to calculate the values with units 112 | delay(30); 113 | }else{ 114 | Serial.println("Waiting for data"); 115 | delay(500); 116 | } 117 | 118 | } 119 | 120 | 121 | // Below here are some helper functions to print the data nicely! 122 | 123 | void printPaddedInt16b( int16_t val ){ 124 | if(val > 0){ 125 | SERIAL_PORT.print(" "); 126 | if(val < 10000){ SERIAL_PORT.print("0"); } 127 | if(val < 1000 ){ SERIAL_PORT.print("0"); } 128 | if(val < 100 ){ SERIAL_PORT.print("0"); } 129 | if(val < 10 ){ SERIAL_PORT.print("0"); } 130 | }else{ 131 | SERIAL_PORT.print("-"); 132 | if(abs(val) < 10000){ SERIAL_PORT.print("0"); } 133 | if(abs(val) < 1000 ){ SERIAL_PORT.print("0"); } 134 | if(abs(val) < 100 ){ SERIAL_PORT.print("0"); } 135 | if(abs(val) < 10 ){ SERIAL_PORT.print("0"); } 136 | } 137 | SERIAL_PORT.print(abs(val)); 138 | } 139 | 140 | void printRawAGMT( ICM_20948_AGMT_t agmt){ 141 | SERIAL_PORT.print("RAW. Acc [ "); 142 | printPaddedInt16b( agmt.acc.axes.x ); 143 | SERIAL_PORT.print(", "); 144 | printPaddedInt16b( agmt.acc.axes.y ); 145 | SERIAL_PORT.print(", "); 146 | printPaddedInt16b( agmt.acc.axes.z ); 147 | SERIAL_PORT.print(" ], Gyr [ "); 148 | printPaddedInt16b( agmt.gyr.axes.x ); 149 | SERIAL_PORT.print(", "); 150 | printPaddedInt16b( agmt.gyr.axes.y ); 151 | SERIAL_PORT.print(", "); 152 | printPaddedInt16b( agmt.gyr.axes.z ); 153 | SERIAL_PORT.print(" ], Mag [ "); 154 | printPaddedInt16b( agmt.mag.axes.x ); 155 | SERIAL_PORT.print(", "); 156 | printPaddedInt16b( agmt.mag.axes.y ); 157 | SERIAL_PORT.print(", "); 158 | printPaddedInt16b( agmt.mag.axes.z ); 159 | SERIAL_PORT.print(" ], Tmp [ "); 160 | printPaddedInt16b( agmt.tmp.val ); 161 | SERIAL_PORT.print(" ]"); 162 | SERIAL_PORT.println(); 163 | } 164 | 165 | 166 | void printFormattedFloat(float val, uint8_t leading, uint8_t decimals){ 167 | float aval = abs(val); 168 | if(val < 0){ 169 | SERIAL_PORT.print("-"); 170 | }else{ 171 | SERIAL_PORT.print(" "); 172 | } 173 | for( uint8_t indi = 0; indi < leading; indi++ ){ 174 | uint32_t tenpow = 0; 175 | if( indi < (leading-1) ){ 176 | tenpow = 1; 177 | } 178 | for(uint8_t c = 0; c < (leading-1-indi); c++){ 179 | tenpow *= 10; 180 | } 181 | if( aval < tenpow){ 182 | SERIAL_PORT.print("0"); 183 | }else{ 184 | break; 185 | } 186 | } 187 | if(val < 0){ 188 | SERIAL_PORT.print(-val, decimals); 189 | }else{ 190 | SERIAL_PORT.print(val, decimals); 191 | } 192 | } 193 | 194 | void printScaledAGMT( ICM_20948_AGMT_t agmt){ 195 | SERIAL_PORT.print("Scaled. Acc (mg) [ "); 196 | printFormattedFloat( myICM.accX(), 5, 2 ); 197 | SERIAL_PORT.print(", "); 198 | printFormattedFloat( myICM.accY(), 5, 2 ); 199 | SERIAL_PORT.print(", "); 200 | printFormattedFloat( myICM.accZ(), 5, 2 ); 201 | SERIAL_PORT.print(" ], Gyr (DPS) [ "); 202 | printFormattedFloat( myICM.gyrX(), 5, 2 ); 203 | SERIAL_PORT.print(", "); 204 | printFormattedFloat( myICM.gyrY(), 5, 2 ); 205 | SERIAL_PORT.print(", "); 206 | printFormattedFloat( myICM.gyrZ(), 5, 2 ); 207 | SERIAL_PORT.print(" ], Mag (uT) [ "); 208 | printFormattedFloat( myICM.magX(), 5, 2 ); 209 | SERIAL_PORT.print(", "); 210 | printFormattedFloat( myICM.magY(), 5, 2 ); 211 | SERIAL_PORT.print(", "); 212 | printFormattedFloat( myICM.magZ(), 5, 2 ); 213 | SERIAL_PORT.print(" ], Tmp (C) [ "); 214 | printFormattedFloat( myICM.temp(), 5, 2 ); 215 | SERIAL_PORT.print(" ]"); 216 | SERIAL_PORT.println(); 217 | } 218 | 219 | void imuPowerOn() 220 | { 221 | pinMode(PIN_IMU_POWER, OUTPUT); 222 | digitalWrite(PIN_IMU_POWER, HIGH); 223 | } 224 | void imuPowerOff() 225 | { 226 | pinMode(PIN_IMU_POWER, OUTPUT); 227 | digitalWrite(PIN_IMU_POWER, LOW); 228 | } 229 | 230 | #if defined(ARDUINO_ARCH_MBED) // updated for v2.1.0 of the Apollo3 core 231 | bool enableCIPOpullUp() 232 | { 233 | //Add 1K5 pull-up on CIPO 234 | am_hal_gpio_pincfg_t cipoPinCfg = g_AM_BSP_GPIO_IOM0_MISO; 235 | cipoPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; 236 | pin_config(PinName(PIN_SPI_CIPO), cipoPinCfg); 237 | return (true); 238 | } 239 | #else 240 | bool enableCIPOpullUp() 241 | { 242 | //Add CIPO pull-up 243 | ap3_err_t retval = AP3_OK; 244 | am_hal_gpio_pincfg_t cipoPinCfg = AP3_GPIO_DEFAULT_PINCFG; 245 | cipoPinCfg.uFuncSel = AM_HAL_PIN_6_M0MISO; 246 | cipoPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; 247 | cipoPinCfg.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA; 248 | cipoPinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL; 249 | cipoPinCfg.uIOMnum = AP3_SPI_IOM; 250 | padMode(MISO, cipoPinCfg, &retval); 251 | return (retval == AP3_OK); 252 | } 253 | #endif 254 | -------------------------------------------------------------------------------- /Firmware/Test Sketches/Sensor_Autodetect/AutoDetectWithMux/Sensors.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | //Read values from the devices on the node list 4 | void gatherDeviceValues() 5 | { 6 | char tempData[50]; 7 | char tempData1[16]; 8 | char tempData2[16]; 9 | char tempData3[16]; 10 | outputData[0] = '\0'; //Clear string contents 11 | 12 | //Step through list, printing values as we go 13 | node *temp = head; 14 | while (temp != NULL) 15 | { 16 | //If this node successfully begin()'d 17 | if (temp->online == true) 18 | { 19 | //Switch on device type to set proper class and setting struct 20 | switch (temp->deviceType) 21 | { 22 | case DEVICE_MULTIPLEXER: 23 | { 24 | //No data to print for a mux 25 | } 26 | break; 27 | case DEVICE_IMU_ICM20948: 28 | { 29 | ICM_20948_I2C *nodeDevice = (ICM_20948_I2C *)temp->classPtr; 30 | struct_ICM20948 *nodeSetting = (struct_ICM20948 *)temp->configPtr; //Create a local pointer that points to same spot as node does 31 | 32 | if (nodeSetting->log == true) 33 | { 34 | openConnection(temp->muxAddress, temp->portNumber); //Connect to this device through muxes as needed 35 | 36 | if (nodeDevice->dataReady()) 37 | { 38 | nodeDevice->getAGMT(); // The values are only updated when you call 'getAGMT' 39 | if (nodeSetting->logAccel) 40 | { 41 | olaftoa(nodeDevice->accX(), tempData1, 2, sizeof(tempData1) / sizeof(char)); 42 | olaftoa(nodeDevice->accY(), tempData2, 2, sizeof(tempData2) / sizeof(char)); 43 | olaftoa(nodeDevice->accZ(), tempData3, 2, sizeof(tempData3) / sizeof(char)); 44 | sprintf(tempData, "%s,%s,%s,", tempData1, tempData2, tempData3); 45 | strcat(outputData, tempData); 46 | } 47 | if (nodeSetting->logGyro) 48 | { 49 | olaftoa(nodeDevice->gyrX(), tempData1, 2, sizeof(tempData1) / sizeof(char)); 50 | olaftoa(nodeDevice->gyrY(), tempData2, 2, sizeof(tempData2) / sizeof(char)); 51 | olaftoa(nodeDevice->gyrZ(), tempData3, 2, sizeof(tempData3) / sizeof(char)); 52 | sprintf(tempData, "%s,%s,%s,", tempData1, tempData2, tempData3); 53 | strcat(outputData, tempData); 54 | } 55 | if (nodeSetting->logMag) 56 | { 57 | olaftoa(nodeDevice->magX(), tempData1, 2, sizeof(tempData1) / sizeof(char)); 58 | olaftoa(nodeDevice->magY(), tempData2, 2, sizeof(tempData2) / sizeof(char)); 59 | olaftoa(nodeDevice->magZ(), tempData3, 2, sizeof(tempData3) / sizeof(char)); 60 | sprintf(tempData, "%s,%s,%s,", tempData1, tempData2, tempData3); 61 | strcat(outputData, tempData); 62 | } 63 | if (nodeSetting->logTemp) 64 | { 65 | olaftoa(nodeDevice->temp(), tempData1, 2, sizeof(tempData1) / sizeof(char)); 66 | sprintf(tempData, "%s,", tempData1); 67 | strcat(outputData, tempData); 68 | } 69 | } 70 | } 71 | } 72 | break; 73 | case DEVICE_DISTANCE_VL53L1X: 74 | { 75 | SFEVL53L1X *nodeDevice = (SFEVL53L1X *)temp->classPtr; 76 | struct_VL53L1X *nodeSetting = (struct_VL53L1X *)temp->configPtr; //Create a local pointer that points to same spot as node does 77 | 78 | if (nodeSetting->log == true) 79 | { 80 | openConnection(temp->muxAddress, temp->portNumber); //Connect to this device through muxes as needed 81 | 82 | if (nodeSetting->logDistance) 83 | { 84 | sprintf(tempData, "%d,", nodeDevice->getDistance()); 85 | strcat(outputData, tempData); 86 | } 87 | if (nodeSetting->logRangeStatus) 88 | { 89 | sprintf(tempData, "%d,", nodeDevice->getRangeStatus()); 90 | strcat(outputData, tempData); 91 | } 92 | if (nodeSetting->logSignalRate) 93 | { 94 | sprintf(tempData, "%d,", nodeDevice->getSignalRate()); 95 | strcat(outputData, tempData); 96 | } 97 | } 98 | } 99 | break; 100 | case DEVICE_PHT_BME280: 101 | { 102 | BME280 *nodeDevice = (BME280 *)temp->classPtr; 103 | struct_BME280 *nodeSetting = (struct_BME280 *)temp->configPtr; //Create a local pointer that points to same spot as node does 104 | if (nodeSetting->log == true) 105 | { 106 | openConnection(temp->muxAddress, temp->portNumber); //Connect to this device through muxes as needed 107 | 108 | if (nodeSetting->logPressure) 109 | { 110 | olaftoa(nodeDevice->readFloatPressure(), tempData1, 2, sizeof(tempData1) / sizeof(char)); 111 | sprintf(tempData, "%s,", tempData1); 112 | strcat(outputData, tempData); 113 | } 114 | if (nodeSetting->logHumidity) 115 | { 116 | olaftoa(nodeDevice->readFloatHumidity(), tempData1, 2, sizeof(tempData1) / sizeof(char)); 117 | sprintf(tempData, "%s,", tempData1); 118 | strcat(outputData, tempData); 119 | } 120 | if (nodeSetting->logAltitude) 121 | { 122 | olaftoa(nodeDevice->readFloatAltitudeMeters(), tempData1, 2, sizeof(tempData1) / sizeof(char)); 123 | sprintf(tempData, "%s,", tempData1); 124 | strcat(outputData, tempData); 125 | } 126 | if (nodeSetting->logTemperature) 127 | { 128 | olaftoa(nodeDevice->readTempC(), tempData1, 2, sizeof(tempData1) / sizeof(char)); 129 | sprintf(tempData, "%s,", tempData1); 130 | strcat(outputData, tempData); 131 | } 132 | } 133 | } 134 | break; 135 | case DEVICE_VOC_CCS811: 136 | { 137 | CCS811 *nodeDevice = (CCS811 *)temp->classPtr; 138 | struct_CCS811 *nodeSetting = (struct_CCS811 *)temp->configPtr; //Create a local pointer that points to same spot as node does 139 | if (nodeSetting->log == true) 140 | { 141 | openConnection(temp->muxAddress, temp->portNumber); //Connect to this device through muxes as needed 142 | 143 | nodeDevice->readAlgorithmResults(); 144 | if (nodeSetting->logTVOC) 145 | { 146 | sprintf(tempData, "%d,", nodeDevice->getTVOC()); 147 | strcat(outputData, tempData); 148 | } 149 | if (nodeSetting->logCO2) 150 | { 151 | sprintf(tempData, "%d,", nodeDevice->getCO2()); 152 | strcat(outputData, tempData); 153 | } 154 | } 155 | } 156 | break; 157 | default: 158 | Serial.printf("printDeviceValue unknown device type: %s\n", getDeviceName(temp->deviceType)); 159 | break; 160 | } 161 | 162 | } 163 | temp = temp->next; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /Firmware/Test Sketches/Sensor_Autodetect/AutoDetectWithMux/extras.ino: -------------------------------------------------------------------------------- 1 | //Get a string/value from user, remove all non-numeric values 2 | //Returns STATUS_GETNUMBER_TIMEOUT if input times out 3 | //Returns STATUS_PRESSED_X if user presses 'x' 4 | int64_t getNumber(int numberOfSeconds) 5 | { 6 | delay(10); //Wait for any incoming chars to hit buffer 7 | while (Serial.available() > 0) Serial.read(); //Clear buffer 8 | 9 | //Get input from user 10 | char cleansed[20]; //Good for very large numbers: 123,456,789,012,345,678\0 11 | 12 | long startTime = millis(); 13 | int spot = 0; 14 | while (spot < 20 - 1) //Leave room for terminating \0 15 | { 16 | while (Serial.available() == 0) //Wait for user input 17 | { 18 | if ( (millis() - startTime) / 1000 >= numberOfSeconds) 19 | { 20 | if (spot == 0) 21 | { 22 | Serial.println("No user input recieved. Do you have line endings turned on?"); 23 | return (STATUS_GETNUMBER_TIMEOUT); //Timeout. No user input. 24 | } 25 | else if (spot > 0) 26 | { 27 | break; //Timeout, but we have data 28 | } 29 | } 30 | } 31 | 32 | //See if we timed out waiting for a line ending 33 | if (spot > 0 && (millis() - startTime) / 1000 >= numberOfSeconds) 34 | { 35 | Serial.println("Do you have line endings turned on?"); 36 | break; //Timeout, but we have data 37 | } 38 | 39 | byte incoming = Serial.read(); 40 | if (incoming == '\n' || incoming == '\r') 41 | { 42 | Serial.println(); 43 | break; 44 | } 45 | 46 | if (isDigit(incoming) == true) 47 | { 48 | Serial.write(incoming); //Echo user's typing 49 | cleansed[spot++] = (char)incoming; 50 | } 51 | 52 | if (incoming == 'x') 53 | { 54 | return (STATUS_PRESSED_X); 55 | } 56 | } 57 | 58 | cleansed[spot] = '\0'; 59 | 60 | uint64_t largeNumber = 0; 61 | for(int x = 0 ; x < spot ; x++) 62 | { 63 | largeNumber *= 10; 64 | largeNumber += (cleansed[x] - '0'); 65 | } 66 | 67 | return (largeNumber); 68 | } 69 | 70 | //Option not known 71 | void printUnknown(uint8_t unknownChoice) 72 | { 73 | Serial.print("Unknown choice: "); 74 | Serial.write(unknownChoice); 75 | Serial.println(); 76 | } 77 | void printUnknown(int unknownValue) 78 | { 79 | Serial.print("Unknown value: "); 80 | Serial.write(unknownValue); 81 | Serial.println(); 82 | } 83 | 84 | 85 | //Get single byte from user 86 | //Waits for and returns the character that the user provides 87 | //Returns STATUS_GETNUMBER_TIMEOUT if input times out 88 | //Returns 'x' if user presses 'x' 89 | uint8_t getByteChoice(int numberOfSeconds) 90 | { 91 | Serial.flush(); 92 | delay(50); //Wait for any incoming chars to hit buffer 93 | while (Serial.available() > 0) Serial.read(); //Clear buffer 94 | 95 | long startTime = millis(); 96 | byte incoming; 97 | while (1) 98 | { 99 | if (Serial.available() > 0) 100 | { 101 | incoming = Serial.read(); 102 | // Serial.print("byte: 0x"); 103 | // Serial.println(incoming, HEX); 104 | if (incoming >= 'a' && incoming <= 'z') break; 105 | if (incoming >= 'A' && incoming <= 'Z') break; 106 | if (incoming >= '0' && incoming <= '9') break; 107 | } 108 | 109 | if ( (millis() - startTime) / 1000 >= numberOfSeconds) 110 | { 111 | Serial.println("No user input recieved."); 112 | return (STATUS_GETBYTE_TIMEOUT); //Timeout. No user input. 113 | } 114 | 115 | delay(10); 116 | } 117 | 118 | return (incoming); 119 | } 120 | 121 | //***************************************************************************** 122 | // 123 | // Divide an unsigned 32-bit value by 10. 124 | // 125 | // Note: Adapted from Ch10 of Hackers Delight (hackersdelight.org). 126 | // 127 | //***************************************************************************** 128 | static uint64_t divu64_10(uint64_t ui64Val) 129 | { 130 | uint64_t q64, r64; 131 | uint32_t q32, r32, ui32Val; 132 | 133 | // 134 | // If a 32-bit value, use the more optimal 32-bit routine. 135 | // 136 | if ( ui64Val >> 32 ) 137 | { 138 | q64 = (ui64Val>>1) + (ui64Val>>2); 139 | q64 += (q64 >> 4); 140 | q64 += (q64 >> 8); 141 | q64 += (q64 >> 16); 142 | q64 += (q64 >> 32); 143 | q64 >>= 3; 144 | r64 = ui64Val - q64*10; 145 | return q64 + ((r64 + 6) >> 4); 146 | } 147 | else 148 | { 149 | ui32Val = (uint32_t)(ui64Val & 0xffffffff); 150 | q32 = (ui32Val>>1) + (ui32Val>>2); 151 | q32 += (q32 >> 4); 152 | q32 += (q32 >> 8); 153 | q32 += (q32 >> 16); 154 | q32 >>= 3; 155 | r32 = ui32Val - q32*10; 156 | return (uint64_t)(q32 + ((r32 + 6) >> 4)); 157 | } 158 | } 159 | 160 | //***************************************************************************** 161 | // 162 | // Converts ui64Val to a string. 163 | // Note: pcBuf[] must be sized for a minimum of 21 characters. 164 | // 165 | // Returns the number of decimal digits in the string. 166 | // 167 | // NOTE: If pcBuf is NULL, will compute a return ui64Val only (no chars 168 | // written). 169 | // 170 | //***************************************************************************** 171 | static int uint64_to_str(uint64_t ui64Val, char *pcBuf) 172 | { 173 | char tbuf[25]; 174 | int ix = 0, iNumDig = 0; 175 | unsigned uMod; 176 | uint64_t u64Tmp; 177 | 178 | do 179 | { 180 | // 181 | // Divide by 10 182 | // 183 | u64Tmp = divu64_10(ui64Val); 184 | 185 | // 186 | // Get modulus 187 | // 188 | uMod = ui64Val - (u64Tmp * 10); 189 | 190 | tbuf[ix++] = uMod + '0'; 191 | ui64Val = u64Tmp; 192 | } while ( ui64Val ); 193 | 194 | // 195 | // Save the total number of digits 196 | // 197 | iNumDig = ix; 198 | 199 | // 200 | // Now, reverse the buffer when saving to the caller's buffer. 201 | // 202 | if ( pcBuf ) 203 | { 204 | while ( ix-- ) 205 | { 206 | *pcBuf++ = tbuf[ix]; 207 | } 208 | 209 | // 210 | // Terminate the caller's buffer 211 | // 212 | *pcBuf = 0x00; 213 | } 214 | 215 | return iNumDig; 216 | } 217 | 218 | //***************************************************************************** 219 | // 220 | // Float to ASCII text. A basic implementation for providing support for 221 | // single-precision %f. 222 | // 223 | // param 224 | // fValue = Float value to be converted. 225 | // pcBuf = Buffer to place string AND input of buffer size. 226 | // iPrecision = Desired number of decimal places. 227 | // bufSize = The size (in bytes) of the buffer. 228 | // The recommended size is at least 16 bytes. 229 | // 230 | // This function performs a basic translation of a floating point single 231 | // precision value to a string. 232 | // 233 | // return Number of chars printed to the buffer. 234 | // 235 | //***************************************************************************** 236 | #define OLA_FTOA_ERR_VAL_TOO_SMALL -1 237 | #define OLA_FTOA_ERR_VAL_TOO_LARGE -2 238 | #define OLA_FTOA_ERR_BUFSIZE -3 239 | 240 | typedef union 241 | { 242 | int32_t I32; 243 | float F; 244 | } ola_i32fl_t; 245 | 246 | static int olaftoa(float fValue, char *pcBuf, int iPrecision, int bufSize) 247 | { 248 | ola_i32fl_t unFloatValue; 249 | int iExp2, iBufSize; 250 | int32_t i32Significand, i32IntPart, i32FracPart; 251 | char *pcBufInitial, *pcBuftmp; 252 | 253 | iBufSize = bufSize; // *(uint32_t*)pcBuf; 254 | if (iBufSize < 4) 255 | { 256 | return OLA_FTOA_ERR_BUFSIZE; 257 | } 258 | 259 | if (fValue == 0.0f) 260 | { 261 | // "0.0" 262 | *(uint32_t*)pcBuf = 0x00 << 24 | ('0' << 16) | ('.' << 8) | ('0' << 0); 263 | return 3; 264 | } 265 | 266 | pcBufInitial = pcBuf; 267 | 268 | unFloatValue.F = fValue; 269 | 270 | iExp2 = ((unFloatValue.I32 >> 23) & 0x000000FF) - 127; 271 | i32Significand = (unFloatValue.I32 & 0x00FFFFFF) | 0x00800000; 272 | i32FracPart = 0; 273 | i32IntPart = 0; 274 | 275 | if (iExp2 >= 31) 276 | { 277 | return OLA_FTOA_ERR_VAL_TOO_LARGE; 278 | } 279 | else if (iExp2 < -23) 280 | { 281 | return OLA_FTOA_ERR_VAL_TOO_SMALL; 282 | } 283 | else if (iExp2 >= 23) 284 | { 285 | i32IntPart = i32Significand << (iExp2 - 23); 286 | } 287 | else if (iExp2 >= 0) 288 | { 289 | i32IntPart = i32Significand >> (23 - iExp2); 290 | i32FracPart = (i32Significand << (iExp2 + 1)) & 0x00FFFFFF; 291 | } 292 | else // if (iExp2 < 0) 293 | { 294 | i32FracPart = (i32Significand & 0x00FFFFFF) >> -(iExp2 + 1); 295 | } 296 | 297 | if (unFloatValue.I32 < 0) 298 | { 299 | *pcBuf++ = '-'; 300 | } 301 | 302 | if (i32IntPart == 0) 303 | { 304 | *pcBuf++ = '0'; 305 | } 306 | else 307 | { 308 | if (i32IntPart > 0) 309 | { 310 | uint64_to_str(i32IntPart, pcBuf); 311 | } 312 | else 313 | { 314 | *pcBuf++ = '-'; 315 | uint64_to_str(-i32IntPart, pcBuf); 316 | } 317 | while (*pcBuf) // Get to end of new string 318 | { 319 | pcBuf++; 320 | } 321 | } 322 | 323 | // 324 | // Now, begin the fractional part 325 | // 326 | *pcBuf++ = '.'; 327 | 328 | if (i32FracPart == 0) 329 | { 330 | *pcBuf++ = '0'; 331 | } 332 | else 333 | { 334 | int jx, iMax; 335 | 336 | iMax = iBufSize - (pcBuf - pcBufInitial) - 1; 337 | iMax = (iMax > iPrecision) ? iPrecision : iMax; 338 | 339 | for (jx = 0; jx < iMax; jx++) 340 | { 341 | i32FracPart *= 10; 342 | *pcBuf++ = (i32FracPart >> 24) + '0'; 343 | i32FracPart &= 0x00FFFFFF; 344 | } 345 | 346 | // 347 | // Per the printf spec, the number of digits printed to the right of the 348 | // decimal point (i.e. iPrecision) should be rounded. 349 | // Some examples: 350 | // Value iPrecision Formatted value 351 | // 1.36399 Unspecified (6) 1.363990 352 | // 1.36399 3 1.364 353 | // 1.36399 4 1.3640 354 | // 1.36399 5 1.36399 355 | // 1.363994 Unspecified (6) 1.363994 356 | // 1.363994 3 1.364 357 | // 1.363994 4 1.3640 358 | // 1.363994 5 1.36399 359 | // 1.363995 Unspecified (6) 1.363995 360 | // 1.363995 3 1.364 361 | // 1.363995 4 1.3640 362 | // 1.363995 5 1.36400 363 | // 1.996 Unspecified (6) 1.996000 364 | // 1.996 2 2.00 365 | // 1.996 3 1.996 366 | // 1.996 4 1.9960 367 | // 368 | // To determine whether to round up, we'll look at what the next 369 | // decimal value would have been. 370 | // 371 | if ( ((i32FracPart * 10) >> 24) >= 5 ) 372 | { 373 | // 374 | // Yes, we need to round up. 375 | // Go back through the string and make adjustments as necessary. 376 | // 377 | pcBuftmp = pcBuf - 1; 378 | while ( pcBuftmp >= pcBufInitial ) 379 | { 380 | if ( *pcBuftmp == '.' ) 381 | { 382 | } 383 | else if ( *pcBuftmp == '9' ) 384 | { 385 | *pcBuftmp = '0'; 386 | } 387 | else 388 | { 389 | *pcBuftmp += 1; 390 | break; 391 | } 392 | pcBuftmp--; 393 | } 394 | } 395 | } 396 | 397 | // 398 | // Terminate the string and we're done 399 | // 400 | *pcBuf = 0x00; 401 | 402 | return (pcBuf - pcBufInitial); 403 | } // ftoa() 404 | -------------------------------------------------------------------------------- /Firmware/Test Sketches/Sensor_Autodetect/AutoDetectWithMux/settings.h: -------------------------------------------------------------------------------- 1 | typedef enum 2 | { 3 | DEVICE_MULTIPLEXER = 0, 4 | DEVICE_LOADCELL_NAU7802, 5 | DEVICE_DISTANCE_VL53L1X, 6 | DEVICE_GPS_UBLOX, 7 | DEVICE_PROXIMITY_VCNL4040, 8 | DEVICE_TEMPERATURE_TMP117, 9 | DEVICE_PRESSURE_MS5637, 10 | DEVICE_PRESSURE_LPS25HB, 11 | DEVICE_PHT_BME280, 12 | DEVICE_UV_VEML6075, 13 | DEVICE_VOC_CCS811, 14 | DEVICE_VOC_SGP30, 15 | DEVICE_CO2_SCD30, 16 | DEVICE_PRESSURE_MS8607, 17 | DEVICE_IMU_ICM20948, 18 | DEVICE_LIGHT_VEML7700, 19 | 20 | DEVICE_TOTAL_DEVICES, //Marks the end, used to iterate loops 21 | DEVICE_UNKNOWN_DEVICE, 22 | } deviceType_e; 23 | 24 | struct node 25 | { 26 | deviceType_e deviceType; 27 | 28 | uint8_t address = 0; 29 | uint8_t portNumber = 0; 30 | uint8_t muxAddress = 0; 31 | bool online = false; //Goes true once successfully begin()'d 32 | 33 | void *classPtr; //Pointer to this devices' class instantiation 34 | void *configPtr; //The struct containing this devices logging options 35 | node *next; 36 | }; 37 | 38 | node *head = NULL; 39 | node *tail = NULL; 40 | 41 | typedef void (*FunctionPointer)(void*); //Used for pointing to device config menus 42 | 43 | enum returnStatus { 44 | STATUS_GETBYTE_TIMEOUT = 255, 45 | STATUS_GETNUMBER_TIMEOUT = -123455555, 46 | STATUS_PRESSED_X, 47 | }; 48 | 49 | //Begin specific sensor config structs 50 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 51 | 52 | struct struct_multiplexer { 53 | //There is nothing about a multiplexer that we want to configure 54 | //Ignore certain ports at detection step? 55 | }; 56 | 57 | #define VL53L1X_DISTANCE_MODE_SHORT 0 58 | #define VL53L1X_DISTANCE_MODE_LONG 1 59 | struct struct_VL53L1X { 60 | bool log = true; 61 | bool logDistance = true; 62 | bool logRangeStatus = true; 63 | bool logSignalRate = false; 64 | byte distanceMode = VL53L1X_DISTANCE_MODE_LONG; 65 | int intermeasurementPeriod = 140; //ms 66 | int offset = 0; //In mm 67 | int crosstalk = 0; 68 | }; 69 | 70 | struct struct_CCS811 { 71 | bool log = true; 72 | bool logTVOC = true; 73 | bool logCO2 = true; 74 | }; 75 | 76 | struct struct_BME280 { 77 | bool log = true; 78 | bool logHumidity = true; 79 | bool logPressure = true; 80 | bool logAltitude = true; 81 | bool logTemperature = true; 82 | }; 83 | 84 | struct struct_ICM20948 { 85 | bool log = true; 86 | bool logAccel = true; 87 | bool logGyro = true; 88 | bool logMag = true; 89 | bool logTemp = true; 90 | }; 91 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 92 | -------------------------------------------------------------------------------- /Firmware/Test Sketches/Sensor_Autodetect/AutoDetectWithMux/settings.ino: -------------------------------------------------------------------------------- 1 | 2 | // Check for extra characters in field or find minus sign. 3 | char* skipSpace(char* str) { 4 | while (isspace(*str)) str++; 5 | return str; 6 | } 7 | 8 | 9 | void beginSD() 10 | { 11 | pinMode(PIN_MICROSD_POWER, OUTPUT); 12 | pinMode(PIN_MICROSD_CHIP_SELECT, OUTPUT); 13 | digitalWrite(PIN_MICROSD_CHIP_SELECT, HIGH); //Be sure SD is deselected 14 | 15 | if (true == true) 16 | { 17 | microSDPowerOn(); 18 | 19 | //Max power up time is 250ms: https://www.kingston.com/datasheets/SDCIT-specsheet-64gb_en.pdf 20 | //Max current is 200mA average across 1s, peak 300mA 21 | delay(10); 22 | 23 | if (sd.begin(SD_CONFIG) == false) //Slightly Faster SdFat Beta (we don't have dedicated SPI) 24 | { 25 | delay(250); //Give SD more time to power up, then try again 26 | if (sd.begin(SD_CONFIG) == false) //Slightly Faster SdFat Beta (we don't have dedicated SPI) 27 | { 28 | Serial.println("SD init failed. Is card present? Formatted?"); 29 | digitalWrite(PIN_MICROSD_CHIP_SELECT, HIGH); //Be sure SD is deselected 30 | //online.microSD = false; 31 | return; 32 | } 33 | } 34 | // } 35 | 36 | //Change to root directory. All new file creation will be in root. 37 | if (sd.chdir() == false) 38 | { 39 | Serial.println("SD change directory failed"); 40 | //online.microSD = false; 41 | return; 42 | } 43 | 44 | //online.microSD = true; 45 | } 46 | else 47 | { 48 | microSDPowerOff(); 49 | //online.microSD = false; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Firmware/Test Sketches/Sensor_Autodetect/I2CScanner/I2CScanner.ino: -------------------------------------------------------------------------------- 1 | #include 2 | const byte PIN_QWIIC_SCL = 8; 3 | const byte PIN_QWIIC_SDA = 9; 4 | TwoWire qwiic(PIN_QWIIC_SDA,PIN_QWIIC_SCL); //Will use pads 8/9 5 | 6 | const byte PIN_QWIIC_POWER = 18; 7 | 8 | //Define the pin functions 9 | //Depends on hardware version. This can be found as a marking on the PCB. 10 | //x04 was the SparkX 'black' version. 11 | //v10 was the first red version. 12 | #define HARDWARE_VERSION_MAJOR 1 13 | #define HARDWARE_VERSION_MINOR 0 14 | 15 | void setup() 16 | { 17 | Serial.begin(115200); 18 | Serial.println("Scanning..."); 19 | 20 | qwiicPowerOn(); 21 | 22 | delay(1000); // Allow extra time for a u-blox module to start. It seems to need 1sec total. 23 | 24 | qwiic.begin(); 25 | qwiic.setClock(100000); 26 | 27 | setQwiicPullups(1); //Set pullups to 1k 28 | 29 | byte error, address; 30 | int nDevices = 0; 31 | for (address = 1; address < 127; address++ ) 32 | { 33 | qwiic.beginTransmission(address); 34 | error = qwiic.endTransmission(); 35 | 36 | if (error == 0) 37 | { 38 | Serial.print("I2C device found at address 0x"); 39 | if (address < 16) 40 | Serial.print("0"); 41 | Serial.print(address, HEX); 42 | Serial.println(); 43 | 44 | nDevices++; 45 | } 46 | // else if (error == 4) 47 | // { 48 | // Serial.print("Unknown error at address 0x"); 49 | // if (address < 16) 50 | // Serial.print("0"); 51 | // Serial.println(address, HEX); 52 | // } 53 | } 54 | if (nDevices == 0) 55 | Serial.println("No I2C devices found\n"); 56 | else 57 | Serial.println("done\n"); 58 | } 59 | 60 | void loop() 61 | { 62 | 63 | } 64 | 65 | void qwiicPowerOn() 66 | { 67 | pinMode(PIN_QWIIC_POWER, OUTPUT); 68 | #if(HARDWARE_VERSION_MAJOR == 0) 69 | digitalWrite(PIN_QWIIC_POWER, LOW); 70 | #else 71 | digitalWrite(PIN_QWIIC_POWER, HIGH); 72 | #endif 73 | } 74 | void qwiicPowerOff() 75 | { 76 | pinMode(PIN_QWIIC_POWER, OUTPUT); 77 | #if(HARDWARE_VERSION_MAJOR == 0) 78 | digitalWrite(PIN_QWIIC_POWER, HIGH); 79 | #else 80 | digitalWrite(PIN_QWIIC_POWER, LOW); 81 | #endif 82 | } 83 | 84 | void setQwiicPullups(uint32_t qwiicBusPullUps) 85 | { 86 | //Change SCL and SDA pull-ups manually using pin_config 87 | am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM1_SCL; 88 | am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM1_SDA; 89 | 90 | if (qwiicBusPullUps == 0) 91 | { 92 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // No pull-ups 93 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; 94 | } 95 | else if (qwiicBusPullUps == 1) 96 | { 97 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; // Use 1K5 pull-ups 98 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; 99 | } 100 | else if (qwiicBusPullUps == 6) 101 | { 102 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K; // Use 6K pull-ups 103 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K; 104 | } 105 | else if (qwiicBusPullUps == 12) 106 | { 107 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K; // Use 12K pull-ups 108 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K; 109 | } 110 | else 111 | { 112 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K; // Use 24K pull-ups 113 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K; 114 | } 115 | 116 | pin_config(PinName(PIN_QWIIC_SCL), sclPinCfg); 117 | pin_config(PinName(PIN_QWIIC_SDA), sdaPinCfg); 118 | } 119 | -------------------------------------------------------------------------------- /Firmware/Test Sketches/Sensor_Autodetect/I2C_Detector/I2C_Detector.ino: -------------------------------------------------------------------------------- 1 | #include 2 | const byte PIN_QWIIC_SCL = 8; 3 | const byte PIN_QWIIC_SDA = 9; 4 | TwoWire qwiic(PIN_QWIIC_SDA,PIN_QWIIC_SCL); //Will use pads 8/9 5 | 6 | const byte PIN_QWIIC_POWER = 18; 7 | 8 | //Define the pin functions 9 | //Depends on hardware version. This can be found as a marking on the PCB. 10 | //x04 was the SparkX 'black' version. 11 | //v10 was the first red version. 12 | #define HARDWARE_VERSION_MAJOR 1 13 | #define HARDWARE_VERSION_MINOR 0 14 | 15 | //Header files for all possible Qwiic sensors 16 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 17 | 18 | #include "ICM_20948.h" // Click here to get the library: http://librarymanager/All#SparkFun_ICM_20948_IMU 19 | ICM_20948_I2C IMU_ICM20948; // Otherwise create an ICM_20948_I2C object 20 | 21 | #include "SparkFun_Qwiic_Scale_NAU7802_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_NAU7802 22 | NAU7802 loadcellSensor_NAU7802; 23 | 24 | #include "SparkFun_VL53L1X.h" //Click here to get the library: http://librarymanager/All#SparkFun_VL53L1X 25 | SFEVL53L1X distanceSensor_VL53L1X(qwiic); 26 | 27 | #include "SparkFun_u-blox_GNSS_Arduino_Library.h" //http://librarymanager/All#SparkFun_u-blox_GNSS 28 | SFE_UBLOX_GNSS gpsSensor_ublox; 29 | 30 | #include "SparkFun_VCNL4040_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_VCNL4040 31 | VCNL4040 proximitySensor_VCNL4040; 32 | 33 | #include "SparkFun_MCP9600.h" //Click here to get the library: http://librarymanager/All#SparkFun_MCP9600 34 | MCP9600 thermoSensor_MCP9600; 35 | 36 | #include "SparkFun_TMP117.h" //Click here to get the library: http://librarymanager/All#SparkFun_TMP117 37 | TMP117 tempSensor_TMP117; 38 | 39 | #include "SparkFun_MS5637_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_MS5637 40 | MS5637 pressureSensor_MS5637; 41 | 42 | #include "SparkFun_LPS25HB_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_LPS25HB 43 | LPS25HB pressureSensor_LPS25HB; 44 | 45 | #include "SparkFunBME280.h" //Click here to get the library: http://librarymanager/All#SparkFun_BME280 46 | BME280 phtSensor_BME280; 47 | 48 | #include "SparkFun_VEML6075_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_VEML6075 49 | VEML6075 uvSensor_VEML6075; 50 | 51 | #include "SparkFun_VEML7700_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_VEML7700 52 | VEML7700 light_VEML7700; 53 | 54 | #include "SparkFunCCS811.h" //Click here to get the library: http://librarymanager/All#SparkFun_CCS811 55 | #define ADR_CCS811_1 0x5B 56 | CCS811 vocSensor_CCS811(ADR_CCS811_1); 57 | 58 | #include "SparkFun_SGP30_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_SGP30 59 | SGP30 vocSensor_SGP30; 60 | 61 | #include "SparkFun_SCD30_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_SCD30 62 | SCD30 co2Sensor_SCD30; 63 | 64 | #include "SparkFun_PHT_MS8607_Arduino_Library.h" //Click here to get the library: http://librarymanager/All#SparkFun_PHT_MS8607 65 | MS8607 pressureSensor_MS8607; 66 | 67 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 68 | 69 | struct struct_QwiicSensors { 70 | bool ICM_20948_I2C; 71 | bool LPS25HB; 72 | bool MCP9600; 73 | bool BH1749NUC; 74 | bool NAU7802; 75 | bool uBlox; 76 | bool VL53L1X; 77 | bool VCNL4040; 78 | bool TMP117; 79 | bool CCS811; 80 | bool BME280; 81 | bool SGP30; 82 | bool VEML6075; 83 | bool VEML7700; 84 | bool MS5637; 85 | bool SCD30; 86 | bool MS8607; 87 | }; 88 | 89 | struct_QwiicSensors qwiicAvailable = { 90 | .ICM_20948_I2C = false, 91 | .LPS25HB = false, 92 | .MCP9600 = false, 93 | .BH1749NUC = false, 94 | .NAU7802 = false, 95 | .uBlox = false, 96 | .VL53L1X = false, 97 | .VCNL4040 = false, 98 | .TMP117 = false, 99 | .CCS811 = false, 100 | .BME280 = false, 101 | .SGP30 = false, 102 | .VEML6075 = false, 103 | .VEML7700 = false, 104 | .MS5637 = false, 105 | .SCD30 = false, 106 | .MS8607 = false, 107 | }; 108 | 109 | void setup() 110 | { 111 | Serial.begin(115200); 112 | Serial.println("Scanning..."); 113 | 114 | qwiicPowerOn(); 115 | 116 | qwiic.begin(); 117 | qwiic.setClock(100000); 118 | 119 | setQwiicPullups(1); //Set pullups to 1K5 120 | } 121 | 122 | void loop() 123 | { 124 | qwiicPowerOff(); 125 | delay(1000); 126 | qwiicPowerOn(); 127 | //delay(1000); //SCD30 acks and responds 128 | //delay(100); //SCD30 acks but fails to start 129 | delay(1000); //u-blox GNSS needs at least 1s 130 | Serial.println("On!"); 131 | Serial.flush(); 132 | 133 | bool somethingDetected = false; 134 | 135 | for (uint8_t address = 0x10 ; address < 127 ; address++) 136 | { 137 | qwiic.beginTransmission(address); 138 | if (qwiic.endTransmission() == 0) 139 | { 140 | Serial.printf("Device found at address 0x%02X\n", address); 141 | if (testDevice(address) == false) 142 | Serial.printf("Unknown I2C device found at address 0x%02X\n", address); 143 | else 144 | somethingDetected = true; 145 | } 146 | } 147 | 148 | if (somethingDetected == false) 149 | Serial.println("Nothing detected"); 150 | } 151 | 152 | // Available Qwiic devices 153 | #define ADR_VEML6075 0x10 154 | #define ADR_VEML7700 0x10 155 | #define ADR_NAU7802 0x2A 156 | #define ADR_VL53L1X 0x29 157 | #define ADR_MS8607 0x40 //Humidity portion of the MS8607 sensor 158 | #define ADR_UBLOX 0x42 159 | #define ADR_TMP117 0x48 //Alternates: 0x49, 0x4A, and 0x4B 160 | #define ADR_SGP30 0x58 161 | #define ADR_CCS811_2 0x5A 162 | //#define ADR_CCS811_1 0x5B 163 | #define ADR_LPS25HB_2 0x5C 164 | #define ADR_LPS25HB_1 0x5D 165 | #define ADR_VCNL4040_OR_MCP9600 0x60 166 | #define ADR_SCD30 0x61 167 | #define ADR_MCP9600_1 0x66 168 | #define ADR_ICM_20948_AD0 0x68 // Or 0x69 when AD0 is high 169 | #define ADR_ICM_20948_AD1 0x69 170 | #define ADR_BME280_2 0x76 171 | #define ADR_MS5637 0x76 172 | //#define ADR_MS8607 0x76 //Pressure portion of the MS8607 sensor. We'll catch the 0x40 first 173 | #define ADR_BME280_1 0x77 174 | 175 | //Given an address, see if it repsonds as we would expect 176 | //Returns false if I2C address is not known 177 | bool testDevice(uint8_t i2cAddress) 178 | { 179 | switch (i2cAddress) 180 | { 181 | case ADR_ICM_20948_AD0: 182 | if (IMU_ICM20948.begin(qwiic, false) == true) //Wire port, ad0val 183 | qwiicAvailable.ICM_20948_I2C = true; 184 | break; 185 | case ADR_ICM_20948_AD1: 186 | if (IMU_ICM20948.begin(qwiic, true) == true) //Wire port, ad0val 187 | qwiicAvailable.ICM_20948_I2C = true; 188 | break; 189 | case ADR_LPS25HB_1: 190 | if (pressureSensor_LPS25HB.begin(qwiic, ADR_LPS25HB_1) == true) //Wire port, Address. 191 | if (pressureSensor_LPS25HB.isConnected() == true) 192 | qwiicAvailable.LPS25HB = true; 193 | break; 194 | case ADR_LPS25HB_2: 195 | if (pressureSensor_LPS25HB.begin(qwiic, ADR_LPS25HB_2) == true) //Wire port, Address. 196 | if (pressureSensor_LPS25HB.isConnected() == true) 197 | qwiicAvailable.LPS25HB = true; 198 | break; 199 | case ADR_MCP9600_1: 200 | if (thermoSensor_MCP9600.begin(ADR_MCP9600_1, qwiic) == true) //Address, Wire port 201 | if (thermoSensor_MCP9600.isConnected() == true) 202 | qwiicAvailable.MCP9600 = true; 203 | break; 204 | case ADR_VCNL4040_OR_MCP9600: 205 | // if (thermoSensor_MCP9600.begin(ADR_MCP9600_1, qwiic) == true) //Address, Wire port 206 | // if (thermoSensor_MCP9600.isConnected() == true) 207 | // qwiicAvailable.MCP9600 = true; 208 | if (proximitySensor_VCNL4040.begin(qwiic) == true) //Wire port. Checks ID so should avoid collision with MCP9600 209 | qwiicAvailable.VCNL4040 = true; 210 | break; 211 | case ADR_NAU7802: 212 | if (loadcellSensor_NAU7802.begin(qwiic) == true) //Wire port 213 | qwiicAvailable.NAU7802 = true; 214 | break; 215 | case ADR_UBLOX: 216 | if (gpsSensor_ublox.begin(qwiic, ADR_UBLOX) == true) //Wire port, address 217 | qwiicAvailable.uBlox = true; 218 | break; 219 | case ADR_VL53L1X: 220 | if (distanceSensor_VL53L1X.begin() == 0) //Returns 0 if init was successful. Wire port passed in constructor. 221 | qwiicAvailable.VL53L1X = true; 222 | break; 223 | case ADR_TMP117: 224 | if (tempSensor_TMP117.begin(ADR_TMP117, qwiic) == true) //Adr, Wire port 225 | qwiicAvailable.TMP117 = true; 226 | break; 227 | case ADR_CCS811_1: 228 | if (vocSensor_CCS811.begin(qwiic) == true) //Wire port 229 | qwiicAvailable.CCS811 = true; 230 | break; 231 | case ADR_BME280_1: 232 | if (phtSensor_BME280.beginI2C(qwiic) == true) //Wire port 233 | qwiicAvailable.BME280 = true; 234 | break; 235 | case ADR_SGP30: 236 | if (vocSensor_SGP30.begin(qwiic) == true) //Wire port 237 | qwiicAvailable.SGP30 = true; 238 | break; 239 | case ADR_VEML6075: 240 | case ADR_VEML7700: 241 | { 242 | if (uvSensor_VEML6075.begin(qwiic) == true) //Wire port 243 | qwiicAvailable.VEML6075 = true; 244 | else if (light_VEML7700.begin(qwiic) == true) //Wire port 245 | qwiicAvailable.VEML7700 = true; 246 | } 247 | break; 248 | case ADR_MS5637: 249 | { 250 | //By the time we hit this address, MS8607 should have already been started by its first address 251 | if (qwiicAvailable.MS8607 == false) 252 | { 253 | if (pressureSensor_MS5637.begin(qwiic) == true) //Wire port 254 | qwiicAvailable.MS5637 = true; 255 | } 256 | break; 257 | } 258 | case ADR_SCD30: 259 | if (co2Sensor_SCD30.begin(qwiic) == true) //Wire port 260 | qwiicAvailable.SCD30 = true; 261 | else 262 | { 263 | //Give it 2s to boot and then try again 264 | delay(2000); 265 | if (co2Sensor_SCD30.begin(qwiic) == true) //Wire port 266 | { 267 | qwiicAvailable.SCD30 = true; 268 | Serial.println("SCD30 found on second attempt!"); 269 | } 270 | } 271 | break; 272 | case ADR_MS8607: 273 | if (pressureSensor_MS8607.begin(qwiic) == true) //Wire port. Tests for both 0x40 and 0x76 I2C addresses. 274 | qwiicAvailable.MS8607 = true; 275 | break; 276 | default: 277 | Serial.printf("Unknown device at address 0x%02X\n", i2cAddress); 278 | return false; 279 | break; 280 | } 281 | return true; 282 | } 283 | 284 | void qwiicPowerOn() 285 | { 286 | pinMode(PIN_QWIIC_POWER, OUTPUT); 287 | #if(HARDWARE_VERSION_MAJOR == 0) 288 | digitalWrite(PIN_QWIIC_POWER, LOW); 289 | #else 290 | digitalWrite(PIN_QWIIC_POWER, HIGH); 291 | #endif 292 | } 293 | void qwiicPowerOff() 294 | { 295 | pinMode(PIN_QWIIC_POWER, OUTPUT); 296 | #if(HARDWARE_VERSION_MAJOR == 0) 297 | digitalWrite(PIN_QWIIC_POWER, HIGH); 298 | #else 299 | digitalWrite(PIN_QWIIC_POWER, LOW); 300 | #endif 301 | } 302 | 303 | void setQwiicPullups(uint32_t qwiicBusPullUps) 304 | { 305 | //Change SCL and SDA pull-ups manually using pin_config 306 | am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM1_SCL; 307 | am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM1_SDA; 308 | 309 | if (qwiicBusPullUps == 0) 310 | { 311 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // No pull-ups 312 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; 313 | } 314 | else if (qwiicBusPullUps == 1) 315 | { 316 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; // Use 1K5 pull-ups 317 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; 318 | } 319 | else if (qwiicBusPullUps == 6) 320 | { 321 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K; // Use 6K pull-ups 322 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K; 323 | } 324 | else if (qwiicBusPullUps == 12) 325 | { 326 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K; // Use 12K pull-ups 327 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K; 328 | } 329 | else 330 | { 331 | sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K; // Use 24K pull-ups 332 | sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K; 333 | } 334 | 335 | pin_config(PinName(PIN_QWIIC_SCL), sclPinCfg); 336 | pin_config(PinName(PIN_QWIIC_SDA), sdaPinCfg); 337 | } 338 | -------------------------------------------------------------------------------- /Hardware/Production/SparkFun_Artemis_OpenLog-Panel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Hardware/Production/SparkFun_Artemis_OpenLog-Panel.zip -------------------------------------------------------------------------------- /Hardware/Production/SparkFun_Artemis_OpenLog.dru: -------------------------------------------------------------------------------- 1 | description[en] = SparkFun 2 Layer Design Rule Checks - Limits for PCBWay\n

\n If you're ordering from PCBWay, these are the 'free' minimums. 2 | layerSetup = (1+2*15+16) 3 | mtCopper = 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 4 | mtIsolate = 1.5mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 5 | mdWireWire = 6mil 6 | mdWirePad = 6mil 7 | mdWireVia = 6mil 8 | mdPadPad = 6mil 9 | mdPadVia = 6mil 10 | mdViaVia = 6mil 11 | mdSmdPad = 6mil 12 | mdSmdVia = 6mil 13 | mdSmdSmd = 6mil 14 | mdViaViaSameLayer = 8mil 15 | mnLayersViaInSmd = 2 16 | mdCopperDimension = 6mil 17 | mdDrill = 6mil 18 | mdSmdStop = 0mil 19 | msWidth = 6mil 20 | msDrill = 0.3mm 21 | msMicroVia = 9.99mm 22 | msBlindViaRatio = 0.500000 23 | rvPadTop = 0.250000 24 | rvPadInner = 0.250000 25 | rvPadBottom = 0.250000 26 | rvViaOuter = 0.250000 27 | rvViaInner = 0.250000 28 | rvMicroViaOuter = 0.250000 29 | rvMicroViaInner = 0.250000 30 | rlMinPadTop = 6mil 31 | rlMaxPadTop = 20mil 32 | rlMinPadInner = 6mil 33 | rlMaxPadInner = 20mil 34 | rlMinPadBottom = 6mil 35 | rlMaxPadBottom = 20mil 36 | rlMinViaOuter = 6mil 37 | rlMaxViaOuter = 20mil 38 | rlMinViaInner = 6mil 39 | rlMaxViaInner = 20mil 40 | rlMinMicroViaOuter = 6mil 41 | rlMaxMicroViaOuter = 20mil 42 | rlMinMicroViaInner = 6mil 43 | rlMaxMicroViaInner = 20mil 44 | psTop = -1 45 | psBottom = -1 46 | psFirst = -1 47 | psElongationLong = 100 48 | psElongationOffset = 100 49 | mvStopFrame = 1.000000 50 | mvCreamFrame = 0.000000 51 | mlMinStopFrame = 4mil 52 | mlMaxStopFrame = 4mil 53 | mlMinCreamFrame = 0mil 54 | mlMaxCreamFrame = 0mil 55 | mlViaStopLimit = 25mil 56 | srRoundness = 0.000000 57 | srMinRoundness = 0mil 58 | srMaxRoundness = 0mil 59 | slThermalIsolate = 10mil 60 | slThermalsForVias = 0 61 | dpMaxLengthDifference = 10mm 62 | dpGapFactor = 2.500000 63 | checkAngle = 1 64 | checkFont = 1 65 | checkRestrict = 1 66 | checkStop = 0 67 | checkValues = 0 68 | checkNames = 1 69 | checkWireStubs = 1 70 | checkPolygonWidth = 0 71 | useDiameter = 13 72 | maxErrors = 50 73 | -------------------------------------------------------------------------------- /Hardware/Production/ordering_instructions.txt: -------------------------------------------------------------------------------- 1 | panel size, 107x187mm 2 | PCB thickness, 1.6mm 3 | number of layers, 4 4 | soldermask color, Red 5 | silkscreen color, White 6 | oz copper, 1oz 7 | finish, ENIG 8 | stencils, top+bottom 9 | pcs per panel, 15 10 | min trace width, 0.1524mm / 0.0060in 11 | min drill size, 0.3048mm / 0.0120in 12 | filename to layer stackup 1/2/3/4: GTL, GL2, GL3, GBL 13 | -------------------------------------------------------------------------------- /Hardware/SparkFun_Artemis_OpenLog-Dimensions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Hardware/SparkFun_Artemis_OpenLog-Dimensions.pdf -------------------------------------------------------------------------------- /Hardware/SparkFun_Artemis_OpenLog-Schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Hardware/SparkFun_Artemis_OpenLog-Schematic.pdf -------------------------------------------------------------------------------- /Hardware/SparkFun_Artemis_OpenLog.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/Hardware/SparkFun_Artemis_OpenLog.zip -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Subject of the issue 2 | Describe your issue here. If you reference a datasheet please specify which one and in which section (ie, the protocol manual, section 5.1.2). Additionally, screenshots are easy to paste into github. 3 | 4 | ### Your workbench 5 | * Are you using a microSD card? If so, what size? How is it formatted (FAT, FAT32, or exFat)? 6 | * At what frequency are you logging? For example, 10Hz, 1Hz, once every 5 seconds, etc. 7 | * What version of firmware are you using? This is shown at boot, for example: "Artemis OpenLog v1.10" 8 | * How is OpenLog Artemis wired to your sensor(s)? 9 | * How is everything being powered? 10 | * Are there any additional details that may help us help you? 11 | 12 | ### Steps to reproduce 13 | Tell us how to reproduce this issue. Please post stripped down example code demonstrating your issue. 14 | 15 | ### Expected behavior 16 | Tell us what should happen 17 | 18 | ### Actual behavior 19 | Tell us what happens instead 20 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | SparkFun License Information 2 | ============================ 3 | 4 | SparkFun uses two different licenses for our files — one for hardware and one for code. 5 | 6 | Hardware 7 | --------- 8 | 9 | **SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).** 10 | 11 | Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode). 12 | 13 | You are free to: 14 | 15 | Share — copy and redistribute the material in any medium or format 16 | Adapt — remix, transform, and build upon the material 17 | for any purpose, even commercially. 18 | The licensor cannot revoke these freedoms as long as you follow the license terms. 19 | Under the following terms: 20 | 21 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 22 | ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 23 | No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. 24 | Notices: 25 | 26 | You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation. 27 | No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material. 28 | 29 | 30 | Code 31 | -------- 32 | 33 | **SparkFun code, firmware, and software is released under the [MIT License](http://opensource.org/licenses/MIT).** 34 | 35 | The MIT License (MIT) 36 | 37 | Copyright (c) 2020 SparkFun Electronics 38 | 39 | Permission is hereby granted, free of charge, to any person obtaining a copy 40 | of this software and associated documentation files (the "Software"), to deal 41 | in the Software without restriction, including without limitation the rights 42 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 43 | copies of the Software, and to permit persons to whom the Software is 44 | furnished to do so, subject to the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be included in all 47 | copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 53 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 54 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 55 | SOFTWARE. 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun OpenLog Artemis 2 | =========================================================== 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
SparkFun OpenLog Artemis (DEV-16832)SparkX OpenLog Artemis (SPX-15846)
14 | 15 | The OpenLog Artemis is an open source datalogger that comes preprogrammed to automatically log IMU, GPS, serial data, and various pressure, humidity, and distance sensors. All without writing a single line of code! OLA automatically detects, configures, and logs Qwiic sensors. OLA is designed for users who just need to capture a bunch of data to a CSV and get back to their larger project. 16 | 17 | Included on every OpenLog Artemis is an IMU for built-in logging of triple axis accelerometer, gyro, and magnetometer. Whereas the original [9DOF Razor](https://www.sparkfun.com/products/14001) used the old MPU-9250, the OpenLog Artemis uses the latest [ICM-20948](https://www.sparkfun.com/products/15335) capable of nearly 1kHz logging of all 9 axis. We then took over a decade of experience with the original [OpenLog](https://www.sparkfun.com/products/13712) and took it much farther. Simply power up OpenLog Artemis and all incoming serial data is automatically recorded to a log file. Baud rates up to 921600bps are supported! Additionally, based on feedback from users we've added an onboard RTC so that all data can be time stamped. 18 | 19 | OpenLog Artemis is highly configurable over an easy to use serial interface. Simply plug in a USB C cable and open a terminal at 115200kbps. The logging output is automatically streamed to both the terminal and the microSD. Pressing any key will open the configuration menu. 20 | 21 | The OpenLog Artemis automatically scans, detects, configures, and logs various Qwiic sensors plugged into the board (no soldering required!). Currently, auto-detection is supported on the following Qwiic products: 22 | 23 | * Any u-blox GPS Modules (Lat/Long, Altitude, Velocity, SIV, Time, Date) such as: 24 | * [ZED-F9P](https://www.sparkfun.com/products/15136) 1cm High Precision GPS 25 | * [NEO-M8P-2](https://www.sparkfun.com/products/15005) 2.5cm High Precision GPS 26 | * [SAM-M8Q](https://www.sparkfun.com/products/15210) 1.5m 72 Channel GPS 27 | * [ZOE-M8Q](https://www.sparkfun.com/products/15193) 1.5m Compact GPS 28 | * [NEO-M9N](https://www.sparkfun.com/products/15712) 1.5m GPS 29 | * [MAX-M10S](https://www.sparkfun.com/products/18037) 1.5m Ultra-Low Power GPS 30 | * [MCP9600 Thermocouple Amplifier](https://www.sparkfun.com/products/16294) 31 | * [NAU7802 Load Cell Amplifier](https://www.sparkfun.com/products/15242) 32 | * [LPS25HB Barometric Pressure Sensor](https://www.sparkfun.com/products/14767) 33 | * [BME280 Humidity and Barometric Pressure Sensor](https://www.sparkfun.com/products/15440) 34 | * [MS5637 Barometric Pressure Sensor](https://www.sparkfun.com/products/14688) 35 | * [MS5837 Depth / Pressure Sensor](https://www.sparkfun.com/products/17709) 36 | * [SDP3X Differential Pressure Sensor](https://www.sparkfun.com/products/17874) 37 | * [MS8607 Pressure Humidity Temperature Sensor](https://www.sparkfun.com/products/16298) 38 | * [MPR0025PA MicroPressure Sensor](https://www.sparkfun.com/products/16476) 39 | * [TMP102 Temperature Sensor] (https://www.sparkfun.com/products/13314) 40 | * [TMP117 High Precision Temperature Sensor](https://www.sparkfun.com/products/15805) 41 | * [AHT20 Humidity and Temperature Sensor](https://www.sparkfun.com/products/16618) 42 | * [SHTC3 Humidity and Temperature Sensor](https://www.sparkfun.com/products/16467) 43 | * [CCS811 Air Quality Sensor](https://www.sparkfun.com/products/14348) 44 | * [SGP30 Air Quality Sensor](https://www.sparkfun.com/products/16531) 45 | * [SGP40 Air Quality Sensor](https://www.sparkfun.com/products/17729) 46 | * [SCD30 CO2 and Air Quality Sensor](https://www.sparkfun.com/products/15112) 47 | * [SN-GCJA5 Particle Sensor](https://www.sparkfun.com/products/17123) 48 | * [VEML6075 UV Sensor](https://www.sparkfun.com/products/15089) 49 | * [VCNL4040 Proximity Sensor](https://www.sparkfun.com/products/15177) 50 | * [VL53L1X LIDAR Distance Sensor](https://www.sparkfun.com/products/14722) 51 | * [ADS122C04 ADC PT100 Sensor](https://www.sparkfun.com/products/16770) 52 | * [Qwiic Mux](https://www.sparkfun.com/products/16784) allowing for the chaining of up to 64 unique buses! 53 | * [Pulse Oximeter and Heart Rate Sensor](https://www.sparkfun.com/products/15219) (requires exclusive use of pins 32 and 11) 54 | * [ISM330DHCX IMU](https://www.sparkfun.com/products/19764) 55 | * [MMC5983MA Magnetometer](https://www.sparkfun.com/products/19921) 56 | * [KX134 Accelerometer](https://www.sparkfun.com/products/17589) 57 | * [ADS1015 ADC](https://www.sparkfun.com/products/15334) 58 | * [LPS28DFW Barometer](https://www.sparkfun.com/products/21221) 59 | * [VEML7700 Ambient Light Sensor](https://www.sparkfun.com/products/18981) 60 | * [TMP102 Temperature Sensor](https://www.sparkfun.com/sparkfun-digital-temperature-sensor-tmp102-qwiic.html) 61 | 62 | Very low power logging is supported. OpenLog Artemis can be configured to take readings at 500 times a second, or as slow as 1 reading every 24 hours. You choose! When there is more than 2 seconds between readings OLA will automatically power down itself and the sensors on the bus resulting in a sleep current of approximately 18uA. This means a normal [2Ah battery](https://www.sparkfun.com/products/13855) will enable logging for more than 4,000 days! OpenLog Artemis has built-in LiPo charging set at 450mA/hr. 63 | 64 | New features are constantly being added so we’ve released an easy to use firmware upgrade tool. No need to install Arduino or a bunch of libraries, simply open the [Artemis Firmware Upload GUI](https://github.com/sparkfun/Artemis-Firmware-Upload-GUI), load the latest OLA firmware, and add features to OpenLog Artemis as they come out! Full instructions are available in [UPGRADE.md](UPGRADE.md). 65 | 66 | The OLA can be tailored to many different applications and we will be releasing custom versions of the firmware for those too: 67 | 68 | * [Latest OLA firmware](https://github.com/sparkfun/OpenLog_Artemis/tree/main/Binaries) 69 | * [Geophone Logger firmware](https://github.com/sparkfun/OpenLog_Artemis_Geophone_Logger) for logging seismic activity 70 | * [GNSS Logger](https://github.com/sparkfun/OpenLog_Artemis_GNSS_Logger) for advanced data logging with the u-blox F9 and M9 GNSS modules including support for RAWX and RELPOSNED 71 | 72 | Repository Contents 73 | ------------------- 74 | 75 | * **/Binaries** - The binary files for the different versions of the OLA firmware. 76 | * **/Firmware** - The main sketch that runs OpenLog Artemis as well as a variety of sketches to test various sensor interfaces and power saving states. 77 | * **/Hardware** - Eagle files. 78 | 79 | Documentation 80 | -------------- 81 | 82 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/openlog-artemis-hookup-guide)** - hookup guide for the OLA. 83 | * **[UPGRADE.md](./UPGRADE.md)** - contains full instructions on how to upgrade the firmware on the OLA using the [Artemis Firmware Upload GUI](https://github.com/sparkfun/Artemis-Firmware-Upload-GUI). 84 | * **[CONTRIBUTING.md](./CONTRIBUTING.md)** - guidance on how to contribute to this library. 85 | * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - OLA includes a large number of libraries that will need to be installed before compiling will work. 86 | * **[ADDING_SENSORS.md](./ADDING_SENSORS.md)** - contains _abbreviated_ instructions on how to add a new sensor to the OLA firmware. It's more of an aide-memoire really... Sorry about that. 87 | * **[COMPILE_BINARY.md](./COMPILE_BINARY.md)** - contains _abbreviated_ instructions on how to compile the OLA firmware binary manually. It's also an aide-memoire really... Sorry about that. 88 | * **[SENSOR_UNITS.md](./SENSOR_UNITS.md)** - contains a summary of the units used for each sensor measurement. 89 | 90 | Product Versions 91 | ---------------- 92 | * [DEV-19426](https://www.sparkfun.com/products/19426) - SparkFun OpenLog Artemis without IMU 93 | * [DEV-16832](https://www.sparkfun.com/products/16832) - SparkFun OpenLog Artemis 94 | * [SPX-15846](https://www.sparkfun.com/products/15846) - SparkX OpenLog Artemis 95 | 96 | License Information 97 | ------------------- 98 | 99 | This product is _**open source**_! 100 | 101 | Various bits of the code have different licenses applied. Anything SparkFun wrote is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round! 102 | 103 | Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license. 104 | 105 | Distributed as-is; no warranty is given. 106 | 107 | - Your friends at SparkFun. 108 | -------------------------------------------------------------------------------- /SENSOR_UNITS.md: -------------------------------------------------------------------------------- 1 | # OpenLog Artemis : Sensor Units 2 | 3 | This document summarizes the units used for each sensor measurement. 4 | 5 | --- 6 | ## Index 7 | 8 | ### Built-in Inertial Measurement Unit: 9 | 10 | - [ICM-20948 IMU](#ICM-20948-IMU) 11 | 12 | ### Global Navigation Satellite System (GNSS) navigation data: 13 | 14 | - [u-blox GNSS boards](#u-blox-GNSS-boards) 15 | 16 | ### Pressure, Altitude, Humidity and Temperature Data: 17 | 18 | - [BME280 atmospheric sensor](#BME280-atmospheric-sensor) 19 | - [LPS25HB absolute pressure sensor](#LPS25HB-absolute-pressure-sensor) 20 | - [MS8607 PHT sensor](#MS8607-PHT-sensor) 21 | - [MPR0025PA MicroPressure sensor](#MPR0025PA-MicroPressure-sensor) 22 | - [MS5637 barometric pressure sensor](#MS5637-barometric-pressure-sensor) 23 | - [MS5837 depth and pressure sensor](#MS5837-depth-pressure-sensor) 24 | - [AHT20 humidity and temperature sensor](#AHT20-humidity-and-temperature-sensor) 25 | - [SHTC3 humidity and temperature sensor](#SHTC3-humidity-and-temperature-sensor) 26 | - [LPS28DFW absolute pressure sensor](#LPS28DFW-absolute-pressure-sensor) 27 | 28 | ### Differential Pressure: 29 | 30 | - [SDP3X differential pressure sensor](#SDP3X-differential-pressure-sensor) 31 | 32 | ### Air Quality and Environmental Sensors: 33 | 34 | - [CCS811 air quality sensor](#CCS811-air-quality-sensor) 35 | - [VEML6075 UV light sensor](#VEML6075-UV-light-sensor) 36 | - [SGP30 air quality and Volatile Organic Compound (VOC) sensor](#SGP30-air-quality-and-VOC-sensor) 37 | - [SGP40 air quality (VOC index) sensor](#SGP40-air-quality-sensor) 38 | - [SCD30 CO2 humidity and temperature sensor](#SCD30-CO2-humidity-and-temperature-sensor) 39 | - [SN-GCJA5 Particle Sensor](#SN-GCJA5-Particle-Sensor) 40 | - [VEML7700 Ambient light sensor](#VEML7700-Ambient-light-sensor) 41 | 42 | ### Distance: 43 | 44 | - [VL53L1X laser Time of Flight (ToF) sensor](#VL53L1X-laser-ToF-sensor) 45 | - [VCNL4040 proximity sensor](#VCNL4040-proximity-sensor) 46 | 47 | ### Precision Temperature Sensors: 48 | 49 | - [MCP9600 thermocouple amplifier](#MCP9600-thermocouple-amplifier) 50 | - [Qwiic PT100 ADS122C04 platinum resistance sensor](#Qwiic-PT100-ADS122C04-platinum-resistance-sensor) 51 | - [TMP117 precision temperature sensor](#TMP117-precision-temperature-sensor) 52 | - [TMP102 temperature sensor](#TMP102-temperature-sensor) 53 | 54 | ### Weight: 55 | 56 | - [NAU7802 load cell sensor](#NAU7802-load-cell-sensor) 57 | 58 | ### ADC: 59 | 60 | - [Qwiic PT100 ADS122C04 platinum resistance sensor](#Qwiic-PT100-ADS122C04-platinum-resistance-sensor) 61 | - [ADS1015 ADC](#ADS1015-ADC) 62 | 63 | ### Biometric Sensors: 64 | 65 | - [Pulse Oximeter and Heart Rate Sensor](#Pulse-Oximeter) 66 | 67 | ### Inertial Measurement Unit: 68 | 69 | - [ISM330DHCX IMU](#ISM330DHCX-IMU) 70 | 71 | ### Magnetometer: 72 | 73 | - [MMC5983MA magnetometer](#MMC5983MA-Magnetometer) 74 | 75 | ### Accelerometer: 76 | 77 | - [KX134 accelerometer](#KX134-accelerometer) 78 | 79 | 80 | --- 81 | ## Sensor Units 82 | 83 | --- 84 | ## ICM-20948 IMU 85 | 86 | | []() | | | 87 | |---|---|---| 88 | | Accelerometer | aX,aY,aZ | milli g | 89 | | Gyro | gX,gY,gZ | Degrees per Second | 90 | | Magnetometer | mX,mY,mZ | micro Tesla | 91 | | Temperature | imu_degC | Degrees Centigrade | 92 | 93 | --- 94 | ## u-blox GNSS boards 95 | 96 | | []() | | | 97 | |---|---|---| 98 | | Date | gps_Date | MM/DD/YYYY or DD/MM/YYYY | 99 | | Time | gps_Time | HH:MM:SS.SSS | 100 | | Lat & Lon | gps_Lat,gps_Long | Degrees-7 | 101 | | Altitude | gps_Alt | mm | 102 | | Altitude MSL | gps_AltMSL | mm | 103 | | SIV | gps_SIV | Count | 104 | | Fix Type | gps_FixType | 0-5 | 105 | | Carrier Soln. | gps_CarrierSolution | 0-2 | 106 | | Ground Speed | gps_GroundSpeed | mm/s | 107 | | Heading | gps_Heading | Degrees-5 | 108 | | PDOP | gps_pDOP | 10-2 (dimensionless) | 109 | | Time Of Week | gps_iTOW | ms | 110 | 111 | Lat = Latitude 112 | Lon = Longitude 113 | MSL = Metres above Sea Level 114 | SIV = Satellites In View 115 | PDOP = Positional Dilution Of Precision 116 | 117 | Fix Type: 118 | 0: No 119 | 1: Dead Reckoning Only 120 | 2: 2D 121 | 3: 3D 122 | 4: GNSS + Dead Reckoning 123 | 5: Time Only 124 | 125 | Carrier Solution: 126 | 0: No 127 | 1: Float Solution 128 | 2: Fixed Solution 129 | 130 | --- 131 | ## BME280 atmospheric sensor 132 | 133 | | []() | | | 134 | |---|---|---| 135 | | Pressure | pressure_Pa | Pascals | 136 | | Humidity | humidity_% | Percent | 137 | | Altitude | altitude_m | m | 138 | | Temperature | temp_degC | Degrees Centigrade | 139 | 140 | --- 141 | ## LPS25HB absolute pressure sensor 142 | 143 | | []() | | | 144 | |---|---|---| 145 | | Pressure | pressure_hPa | hectoPascals | 146 | | Temperature | temperature_degC | Degrees Centigrade | 147 | 148 | --- 149 | ## LPS28DFW absolute pressure sensor 150 | 151 | | []() | | | 152 | |---|---|---| 153 | | Pressure | pressure_hPa | hectoPascals | 154 | | Temperature | temperature_degC | Degrees Centigrade | 155 | 156 | --- 157 | ## MS8607 PHT sensor 158 | 159 | | []() | | | 160 | |---|---|---| 161 | | Humidity | humidity_% | Percent | 162 | | Pressure | hPa | hectoPascals | 163 | | Temperature | degC | Degrees Centigrade | 164 | 165 | --- 166 | ## MPR0025PA MicroPressure sensor 167 | 168 | | []() | | | 169 | |---|---|---| 170 | | Pressure (PSI) | PSI | Pounds per Square Inch | 171 | | Pressure (Pa) | Pa | Pascals | 172 | | Pressure (kPa) | kPa | kiloPascals | 173 | | Pressure (torr) | torr | torr | 174 | | Pressure (inHg) | inHg | inches of Mercury | 175 | | Pressure (atm) | atm | atmospheres | 176 | | Pressure (bar) | bar | barometric pressure | 177 | 178 | --- 179 | ## MS5637 barometric pressure sensor 180 | 181 | | []() | | | 182 | |---|---|---| 183 | | Pressure | pressure_hPa | hectoPascals | 184 | | Temperature | temperature_degC | Degrees Centigrade | 185 | 186 | --- 187 | ## MS5837 depth pressure sensor 188 | 189 | | []() | | | 190 | |---|---|---| 191 | | Pressure | mbar | millibar | 192 | | Temperature | degC | Degrees Centigrade | 193 | | Depth | depth_m | Metres | 194 | | Altitude | alt_m | Metres | 195 | 196 | --- 197 | ## SDP3X differential pressure sensor 198 | 199 | | []() | | | 200 | |---|---|---| 201 | | Pressure | Pa | Pascals | 202 | | Temperature | degC | Degrees Centigrade | 203 | 204 | --- 205 | ## AHT20 humidity and temperature sensor 206 | 207 | | []() | | | 208 | |---|---|---| 209 | | Humidity | humidity_% | Percent | 210 | | Temperature | degC | Degrees Centigrade | 211 | 212 | --- 213 | ## SHTC3 humidity and temperature sensor 214 | 215 | | []() | | | 216 | |---|---|---| 217 | | Humidity | humidity_% | Percent | 218 | | Temperature | degC | Degrees Centigrade | 219 | 220 | --- 221 | ## CCS811 air quality sensor 222 | 223 | | []() | | | 224 | |---|---|---| 225 | | VOC | tvoc_ppb | Parts Per Billion | 226 | | CO2 | co2_ppm | Parts Per Million | 227 | 228 | VOC = Volatile Organic Compounds 229 | 230 | --- 231 | ## VEML6075 UV light sensor 232 | 233 | | []() | | | 234 | |---|---|---| 235 | | UVA | uva | | 236 | | UVB | uvb | | 237 | | UV Index | uvIndex | | 238 | 239 | --- 240 | ## VEML7700 Ambient light sensor 241 | 242 | | []() | | | 243 | |---|---|---| 244 | | Lux | lux | | 245 | 246 | --- 247 | ## SGP30 air quality and VOC sensor 248 | 249 | | []() | | | 250 | |---|---|---| 251 | | Total VOC | tvoc_ppb | Parts Per Billion | 252 | | CO2 | co2_ppm | Parts Per Million | 253 | | H2 | H2 | none | 254 | | Ethanol | ethanol | none | 255 | 256 | --- 257 | ## SGP40 air quality sensor 258 | 259 | | []() | | | 260 | |---|---|---| 261 | | VOC Index | VOCindex | none | 262 | 263 | --- 264 | ## SCD30 CO2 humidity and temperature sensor 265 | 266 | | []() | | | 267 | |---|---|---| 268 | | CO2 | co2_ppm | Parts Per Million | 269 | | Humidity | humidity_% | Percent | 270 | | Temperature | degC | Degrees Centigrade | 271 | 272 | --- 273 | ## SN-GCJA5 Particle Sensor 274 | 275 | | []() | | | 276 | |---|---|---| 277 | | Particle Density (1.0µm) | PM1_0 | µg/m3 | 278 | | Particle Density (2.5µm) | PM2_5 | µg/m3 | 279 | | Particle Density (10µm) | PM10 | µg/m3 | 280 | | Particle Count (0.5µm) | PC0_5 | Count | 281 | | Particle Count (1.0µm) | PC1_0 | Count | 282 | | Particle Count (2.5µm) | PC2_5 | Count | 283 | | Particle Count (5.0µm) | PC5_0 | Count | 284 | | Particle Count (7.5µm) | PC7_5 | Count | 285 | | Particle Count (10µm) | PC10 | Count | 286 | | Sensor Status | Sensors | | 287 | | Photodiode Status | PD | 0-3 | 288 | | Laser Diode Status | LD | 0-3 | 289 | | Fan Status | Fan | 0-3 | 290 | 291 | Sensor status: 292 | | []() | | 293 | |---|---| 294 | | | PD LD Fan | 295 | | 0 | 0 0 0 | 296 | | 1 | Any 1, nor 2 & 3 | 297 | | 2 | Any 2 | 298 | | 3 | Any 3 nor 2 | 299 | 300 | PD status: 301 | 0: Normal status 302 | 1: Normal status (within -80% against initial value), with S/W correction 303 | 2: Abnormal (below -90% against initial value), loss of function 304 | 3: Abnormal (below -80% against initial value), with S/W correction 305 | 306 | LD operational status: 307 | 0: Normal status 308 | 1: Normal status (within -70% against initial LOP), with S/W correction 309 | 2: Abnormal (below -90% against initial LOP) or no LOP, loss of function 310 | 3: Abnormal (below -70% against initial LOP), with S/W correction 311 | 312 | Fan operational status: 313 | 0: Normal status 314 | 1: Normal status (1,000rpm or more), with S/W correction 315 | 2: In initial calibration 316 | 3: Abnormal (below 1,000rpm), out of control 317 | 318 | 319 | --- 320 | ## VL53L1X laser ToF sensor 321 | 322 | | []() | | | 323 | |---|---|---| 324 | | Distance | distance_mm | mm | 325 | | Range Status | distance_rangeStatus(0=good) | | 326 | | Signal Rate | distance_signalRate | | 327 | 328 | --- 329 | ## VCNL4040 proximity sensor 330 | 331 | | []() | | | 332 | |---|---|---| 333 | | Proximity | prox(no unit) | none | 334 | | Ambient Light | ambient_lux | | 335 | 336 | --- 337 | ## MCP9600 thermocouple amplifier 338 | 339 | | []() | | | 340 | |---|---|---| 341 | | Temperature | thermo_degC | Degrees Centigrade | 342 | | Ambient Temperature | thermo_ambientDegC | Degrees Centigrade | 343 | 344 | --- 345 | ## Qwiic PT100 ADS122C04 platinum resistance sensor 346 | 347 | | []() | | | 348 | |---|---|---| 349 | | Temperature (C) | degC | Degrees Centigrade | 350 | | Temperature (F) | degF | Degrees Fahrenheit | 351 | | Temperature Internal | degC | Degrees Centigrade | 352 | | Raw Voltage | V*2.048/2^23 | Volts * 2.048 / 223 | 353 | 354 | --- 355 | ## TMP102 temperature sensor 356 | 357 | | []() | | | 358 | |---|---|---| 359 | | Temperature | degC | Degrees Centigrade | 360 | 361 | --- 362 | ## TMP117 precision temperature sensor 363 | 364 | | []() | | | 365 | |---|---|---| 366 | | Temperature | degC | Degrees Centigrade | 367 | 368 | --- 369 | ## NAU7802 load cell sensor 370 | 371 | | []() | | | 372 | |---|---|---| 373 | | Weight | weight(no unit) | none | 374 | 375 | --- 376 | ## Pulse Oximeter 377 | 378 | | []() | | | 379 | |---|---|---| 380 | | bpm | heart rate | beats per minute | 381 | | conf% | confidence | percent | 382 | | O2% | oxygen level | percent | 383 | | stat | sensor status | 0 to 3 | 384 | | eStat | extended status | -6 to 1 | 385 | | O2R | oxygen SpO2 R value | | 386 | 387 | Sensor status: 388 | 0: No object detected 389 | 1: Object detected 390 | 2: Object other than finger detected 391 | 3: Finger detected 392 | 393 | Extended status: 394 | 0: Success 395 | +1: Not ready 396 | -1: Object detected 397 | -2: Excessive sensor device motion 398 | -3: No object detected 399 | -4: Pressing too hard 400 | -5: Object other than finger detected 401 | -6: Excessive finger motion 402 | 403 | --- 404 | ## ISM330DHCX IMU 405 | 406 | | []() | | | 407 | |---|---|---| 408 | | Accelerometer | aX,aY,aZ | milli g | 409 | | Gyro | gX,gY,gZ | milli Degrees per Second | 410 | 411 | --- 412 | ## MMC5983MA Magnetometer 413 | 414 | | []() | | | 415 | |---|---|---| 416 | | Magnetometer | mX,mY,mZ | Gauss | 417 | | Temperature | degC | Degrees Centigrade | 418 | 419 | --- 420 | ## KX134 Accelerometer 421 | 422 | | []() | | | 423 | |---|---|---| 424 | | Accelerometer | aX,aY,aZ | g | 425 | 426 | --- 427 | ## ADS1015 ADC 428 | 429 | | []() | | | 430 | |---|---|---| 431 | | Voltage | A0mV,A1mV,A2mV,A3mV,A0A1mV,A0A3mV,A1A3mV,A2A3mV | milliVolts | 432 | 433 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | # OpenLog Artemis : Upgrade Instructions 2 | 3 | The [**/Binaries**](./Binaries) folder contains the binary files for the different versions of the OLA firmware. 4 | 5 | You can upload these to the OLA using the [Artemis Firmware Upload GUI](https://github.com/sparkfun/Artemis-Firmware-Upload-GUI) instead of the Arduino IDE. 6 | Which is handy if you want to quickly update the firmware in the field, or are not familiar with the IDE. 7 | 8 | The firmware is customized for the different versions of the OLA hardware. You will find versions for the **X04 SparkX (Black) OLA** and **V10 SparkFun (Red) OLA** plus any subsequent revisions. The filename tells you which hardware the firmware is for and what version it is: 9 | 10 | * **OpenLog_Artemis-V10-v210.bin** - is the _stable_ version (2.10) for the **V10 SparkFun (Red) OLA** 11 | * **OpenLog_Artemis-X04-v210.bin** - is the _stable_ version (2.10) for the **X04 SparkX (Black) OLA** 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
SparkFun OpenLog Artemis V10 (DEV-16832)SparkX OpenLog Artemis X04 (SPX-15846)
23 | 24 | * From time to time, you may also see versions with names like **OpenLog_Artemis-V10-v17_BETA.bin** 25 | * These are _beta_ versions containing new features and improvements which are still being tested and documented 26 | 27 | * **OpenLog_Artemis-V10-v210-NoPowerLossProtection.bin** is a special build of v2.8 which has no power loss protection 28 | * With the normal firmware, the OLA goes into deep sleep if the power fails or is disconnected. This allows the Real Time Clock to keep running, but it does mean that a reset is required to wake the OLA again. 29 | * With the **NoPowerLossProtection** firmware, the code does not go into deep sleep when the power is lost, meaning that it will restart automatically as soon as power is reconnected. 30 | * This can be useful for embedded OLA systems which are hard to access. The downside is that the Real Time Clock setting is lost when the OLA restarts. 31 | 32 | ## To use: 33 | 34 | * Download and extract the [OLA repo ZIP](https://github.com/sparkfun/OpenLog_Artemis/archive/main.zip) 35 | * Download and extract the [AFU repo ZIP](https://github.com/sparkfun/Artemis-Firmware-Upload-GUI/archive/master.zip) 36 | * Run the AFU artemis_firmware_uploader_gui executable for your platform 37 | * **/Windows** contains the Windows .exe 38 | * **/OSX** contains an executable for macOS X 39 | * **/Linux** contains an executable built on Ubuntu 40 | * **/Raspberry_Pi__Debian** contains an executable for Raspberry Pi 4 (Debian Buster) 41 | * Select the OLA firmware file you'd like to upload from the OLA **/Binaries** folder (should end in *.bin*) 42 | * Attach the OLA target board using USB 43 | * Select the COM port (hit Refresh to refresh the list of USB devices) 44 | * Press **Upload Firmware** 45 | 46 | The GUI does take a few seconds to load and run. _**Don't Panic**_ if the GUI does not start right away. 47 | 48 | - Your friends at SparkFun. 49 | -------------------------------------------------------------------------------- /img/Contributing.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sparkfun/OpenLog_Artemis/721d455fb71bd9b7c7024a391c06b6370b835472/img/Contributing.JPG --------------------------------------------------------------------------------