diff --git a/.github/workflows/compile-blink.yaml b/.github/workflows/compile-blink.yaml index b17a291..57cd396 100644 --- a/.github/workflows/compile-blink.yaml +++ b/.github/workflows/compile-blink.yaml @@ -18,7 +18,7 @@ jobs: # CHANGE program/lib/aux as needed program: - src: 'blink' - lib: 'DeviceNameHelperRK MyLib' + lib: 'DeviceNameHelperRK/src MyLib/src' aux: '' # CHANGE platforms as needed platform: @@ -31,6 +31,7 @@ jobs: # workflow call uses: ./.github/workflows/compile.yaml + secrets: inherit with: platform: ${{ matrix.platform.name }} version: ${{ matrix.platform.version }} diff --git a/.github/workflows/compile-controller.yaml b/.github/workflows/compile-controller.yaml index 823d5af..645c6a5 100644 --- a/.github/workflows/compile-controller.yaml +++ b/.github/workflows/compile-controller.yaml @@ -19,7 +19,7 @@ jobs: # CHANGE program/lib/aux as needed program: - src: 'controller' - lib: 'LoggerCore DeviceNameHelperRK FileHelperRK SequentialFileRK PublishQueueExtRK SparkFun_Qwiic_OpenLog_Arduino_Library' + lib: 'LoggerCore/src DeviceNameHelperRK/src FileHelperRK/src SequentialFileRK/src PublishQueueExtRK/src SparkFun_Qwiic_OpenLog_Arduino_Library/src' aux: '' # CHANGE platforms as needed platform: @@ -30,6 +30,7 @@ jobs: # workflow call uses: ./.github/workflows/compile.yaml + secrets: inherit with: platform: ${{ matrix.platform.name }} version: ${{ matrix.platform.version }} diff --git a/.github/workflows/compile-i2c_scanner.yaml b/.github/workflows/compile-i2c_scanner.yaml new file mode 100644 index 0000000..839e840 --- /dev/null +++ b/.github/workflows/compile-i2c_scanner.yaml @@ -0,0 +1,40 @@ +# name of the job +name: Compile i2c scanner + +# specify which paths to watch for changes +on: + push: + paths: + - src/i2c_scanner + - .github/workflows/compile.yaml + - .github/workflows/compile-i2c_scanner.yaml + +# run compile via the compile.yaml +jobs: + compile: + strategy: + fail-fast: false + matrix: + # CHANGE program/lib/aux as needed + program: + - src: 'i2c_scanner' + lib: '' + aux: '' + # CHANGE platforms as needed + platform: + - {name: 'photon', version: '2.3.1'} + - {name: 'argon', version: '4.2.0'} + - {name: 'p2', version: '6.3.2'} + + # program name + name: ${{ matrix.program.src }}-${{ matrix.platform.name }}-${{ matrix.platform.version }} + + # workflow call + uses: ./.github/workflows/compile.yaml + secrets: inherit + with: + platform: ${{ matrix.platform.name }} + version: ${{ matrix.platform.version }} + src: ${{ matrix.program.src }} + lib: ${{ matrix.program.lib }} + aux: ${{ matrix.program.aux }} \ No newline at end of file diff --git a/.github/workflows/compile-publish.yaml b/.github/workflows/compile-publish.yaml index 46e4bd8..c39c572 100644 --- a/.github/workflows/compile-publish.yaml +++ b/.github/workflows/compile-publish.yaml @@ -19,7 +19,7 @@ jobs: # CHANGE program/lib/aux as needed program: - src: 'publish' - lib: 'DeviceNameHelperRK FileHelperRK SequentialFileRK PublishQueueExtRK SparkFun_Qwiic_OpenLog_Arduino_Library' + lib: 'DeviceNameHelperRK/src FileHelperRK/src SequentialFileRK/src PublishQueueExtRK/src SparkFun_Qwiic_OpenLog_Arduino_Library/src' aux: 'LoggerCore/src/LoggerPlatform* LoggerCore/src/LoggerUtils* LoggerCore/src/LoggerPublisher* LoggerCore/src/LoggerSD*' # CHANGE platforms as needed platform: @@ -30,6 +30,7 @@ jobs: # workflow call uses: ./.github/workflows/compile.yaml + secrets: inherit with: platform: ${{ matrix.platform.name }} version: ${{ matrix.platform.version }} diff --git a/.github/workflows/compile.yaml b/.github/workflows/compile.yaml index e939d5c..6a449cc 100644 --- a/.github/workflows/compile.yaml +++ b/.github/workflows/compile.yaml @@ -1,4 +1,4 @@ -name: Compile Firmware +name: Base workflow_call for compile actions on: workflow_call: @@ -41,13 +41,13 @@ jobs: echo "Including libraries:" for lib in ${{ inputs.lib }}; do if [ -d "$lib" ]; then - echo " - $lib/src/*" - mv $lib/src/* ${{ inputs.src }} + echo " - $lib/*" + mv $lib/* ${{ inputs.src }} elif [ -d "lib/$lib" ]; then - echo " - lib/$lib/src/*" - mv lib/$lib/src/* ${{ inputs.src }} + echo " - lib/$lib/*" + mv lib/$lib/* ${{ inputs.src }} else - echo " - could not find $lib, make sure the library exists" + echo " - could not find $lib, make sure the folder exists" fi done echo "Including auxiliary resources:" @@ -56,7 +56,8 @@ jobs: mv $aux ${{ inputs.src }} done - - name: Compile in cloud + - name: Compile in cloud (on master) + if: ${{ github.ref == 'refs/heads/master' }} id: compile uses: particle-iot/compile-action@v1 with: @@ -65,20 +66,27 @@ jobs: device-os-version: ${{ inputs.version }} sources-folder: ${{ inputs.src }} - - name: Move binary + - name: Move cloud binary + if: ${{ github.ref == 'refs/heads/master' }} run: | mv ${{ steps.compile.outputs.firmware-path }} ${{ inputs.src }}/${{ inputs.src }}-${{ inputs.platform }}-${{ inputs.version }}.bin + - name: Compile locally # if not on master or if cloud compile failed + if: ${{ failure() || github.ref != 'refs/heads/master' }} + id: localcompile + uses: particle-iot/compile-action@v1 + with: + particle-platform-name: ${{ inputs.platform }} + device-os-version: ${{ inputs.version }} + sources-folder: ${{ inputs.src }} + + - name: Move local binary + if: ${{ github.ref != 'refs/heads/master' }} + run: | + mv ${{ steps.localcompile.outputs.firmware-path }} ${{ inputs.src }}/${{ inputs.src }}-${{ inputs.platform }}-${{ inputs.version }}.bin + - name: Upload binary uses: actions/upload-artifact@v4 with: name: ${{ inputs.src }}-${{ inputs.platform }}-${{ inputs.version }} path: ${{ inputs.src }} - - - name: Compile locally to debug - if: ${{ failure() }} - uses: particle-iot/compile-action@v1 - with: - particle-platform-name: ${{ inputs.platform }} - device-os-version: ${{ inputs.version }} - sources-folder: ${{ inputs.src }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 061ab17..b0a95af 100644 --- a/.gitignore +++ b/.gitignore @@ -59,4 +59,7 @@ bin/*.bin .DS_Store # gemfile -Gemfile.lock \ No newline at end of file +Gemfile.lock + +# credentials +credentials \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d9cd3ea --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,79 @@ +{ + "C_Cpp.default.configurationProvider": "particle.particle-vscode-core", + "C_Cpp.errorSquiggles": "enabled", + "C_Cpp.dimInactiveRegions": false, + "particle.targetPlatform": "p2", // needs to be defined for IntelliSense to work + "particle.firmwareVersion": "6.2.1", // needs to be defined for IntelliSense to work + "editor.tabSize": 4, + "files.associations": { + "__config": "cpp", + "__cxx_version": "cpp", + "__locale": "cpp", + "cstdlib": "cpp", + "memory_resource": "cpp", + "locale": "cpp", + "ostream": "cpp", + "system_error": "cpp", + "typeinfo": "cpp", + "vector": "cpp", + "__bit_reference": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__functional_base": "cpp", + "__hash_table": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tuple": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "cmath": "cpp", + "complex": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "exception": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "memory": "cpp", + "mutex": "cpp", + "new": "cpp", + "optional": "cpp", + "ratio": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "unordered_map": "cpp", + "utility": "cpp", + "__memory": "cpp", + "__functional_03": "cpp", + "*.hold": "cpp", + "__verbose_abort": "cpp", + "charconv": "cpp", + "clocale": "cpp", + "span": "cpp", + "variant": "cpp" + } +} \ No newline at end of file diff --git a/Guardfile b/Guardfile index b99719d..b87d2c6 100644 --- a/Guardfile +++ b/Guardfile @@ -14,8 +14,9 @@ bin_folder = "bin" # program last_bin = Dir.glob(File.join(bin_folder, '*.bin')).select { |f| File.file?(f) }.max_by { |f| File.mtime(f) } -program = File.basename(last_bin).split('-').first -puts "\nINFO: Setting up guard to re-compile '#{program}' when there are code changes in:" +program, platform, version = File.basename(last_bin).split('-') +version = version.chomp('.bin') +puts "\nINFO: Setting up guard to re-compile '#{program}' for #{platform} #{version} when there are code changes in:" # workflow workflow_path = File.join(".github", "workflows", "compile-#{program}.yaml") @@ -32,7 +33,7 @@ end puts "\n" # guard -guard 'rake', :task => 'autoCompile', :run_on_start => false, wait_for_changes: true, :task_args => [program] do +guard 'rake', :task => 'autoCompile', :run_on_start => false, wait_for_changes: true, :task_args => [program, platform, version] do watch_paths.each do |pattern| watch(Regexp.new(pattern)) end diff --git a/LoggerCore/src/LoggerPlatform.h b/LoggerCore/src/LoggerPlatform.h index 34bba29..721dbcd 100644 --- a/LoggerCore/src/LoggerPlatform.h +++ b/LoggerCore/src/LoggerPlatform.h @@ -2,6 +2,11 @@ #include "Particle.h" +// address issue where this is not defined anymore in newer firmware +#ifndef PLATFORM_PHOTON +#define PLATFORM_PHOTON 0 +#endif + // file helper to get at flash system usage // dependencies.FileHelperRK=0.0.3 #include "FileHelperRK.h" diff --git a/README.md b/README.md index e352fbb..ba65e49 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ The following firmware is included in the repository to provide frequently used | Program | *main* branch | *dev* branch | | :------- | :--- | :--- | | blink | ![blink](https://github.com/KopfLab/LabLoggerLibs/actions/workflows/compile-blink.yaml/badge.svg?branch=main) | ![blink-dev](https://github.com/KopfLab/LabLoggerLibs/actions/workflows/compile-blink.yaml/badge.svg?branch=dev) | +| i2c_scanner | ![blink](https://github.com/KopfLab/LabLoggerLibs/actions/workflows/compile-i2c_scanner.yaml/badge.svg?branch=main) | ![blink-dev](https://github.com/KopfLab/LabLoggerLibs/actions/workflows/compile-i2c_scanner.yaml/badge.svg?branch=dev) | | publish | ![publish](https://github.com/KopfLab/LabLoggerLibs/actions/workflows/compile-publish.yaml/badge.svg?branch=main) | ![publish-dev](https://github.com/KopfLab/LabLoggerLibs/actions/workflows/compile-publish.yaml/badge.svg?branch=dev) | ### Compile @@ -53,6 +54,17 @@ The configuration for individual programs is managed via their compile workflow The workflow YAML additionally specifies which folders to watch for changes to trigger the automatic rebuild on GitHub in the `push` -> `paths` setting. This information is also used by the [Guardfile](Guardfile) to figure out which files should trigger an automatic rebuild during development. Use `rake PROGRAM` to compile a program for the first time and then activate automatic re-compiles by running `bundle exec guard`. It will figure out which program was last build, pull the folders to watch out of the workflow YAML and trigger re-compile if anything changes. +To add a new program (`myprog`): + + - work in a development git branch (e.g. `dev-myprog`) + - create a sub folder `src/myprog` that includes a `project.properties` file with `name=myprog` and a list of commented out dependencies + - if there are any new dependencies, add them to the table at the end of the `README.md`, and as git submodules in the lib/ folder via `cd lib` + `git submodule add https://github.com/...` + - add a YAML workflow for github actions in `.github/workflows/compile-myprog.yaml` (see e.g. `i2c_scanner` as example) that lists the `src`, `lib` and `aux` needed to compile the program + - add a task in the `Rakefile` under the `### PROGRAM ###` subheading that's simply `task :myprog => :compile` + - test compilation with `rake myprog`, fix issues in the sources (`src/myprog/`) and with libraries as needed until it compiles successfully + - use `bundle exec guard` to continue development with auto compilation + - once the program works as intended and compiles correctly via GitHub actions (https://github.com/kopflab/LabLoggerLibs/actions), add it to the list of firmware in the `README.md` with the github actions badges to `main` and `dev` (whichever dev branch is the correct one, e.g. `dev-myprog`) + ## Libraries ### LoggerCore @@ -79,4 +91,7 @@ The following third-party software is used in the ***LabLogger*** libraries: | LoggerCore | PublishQueueExtRK | https://github.com/rickkas7/PublishQueueExtRK | MIT | | LoggerCore | SparkFun_Qwiic_OpenLog_Arduino_Library | https://github.com/sparkfun/SparkFun_Qwiic_OpenLog_Arduino_Library | MIT | | LoggerOled | Adafruit_SSD1306 | https://github.com/adafruit/Adafruit_SSD1306 | BSD | +| LoggerOled | Adafruit-GFX-Library | https://github.com/adafruit/Adafruit-GFX-Library | BSD | +| LoggerOled | Adafruit_BusIO | https://github.com/adafruit/Adafruit_BusIO | MIT | + diff --git a/Rakefile b/Rakefile index ab04032..39ed652 100644 --- a/Rakefile +++ b/Rakefile @@ -3,17 +3,20 @@ # install the CLI from https://github.com/spark/particle-cli # install ruby rake with: bundle install # log into your particle account with: particle login -# to compile: rake PROGRAM +# to compile program x: rake x +# to compile program x without shortcut: rake compile PROGRAM=x # to flash latest compile via USB: rake flash # to flash latest compile via cloud: rake flash DEVICE=name # to start serial monitor: rake monitor -# to compile & flash: rake PROGRAM flash -# to compile, flash & monitor: rake PROGRAM flash monitor +# to compile & flash: rake x flash +# to compile, flash & monitor: rake x flash monitor ### PROGRAMS ### task :blink => :compile task :publish => :compile +task :i2c_scanner => :compile +task :oled => :compile ### SETUP ### @@ -46,7 +49,7 @@ bin = ENV['BIN'] desc "compile binary in the cloud" task :compile do # what program are we compiling? - program = Rake.application.top_level_tasks.first + program = ENV['PROGRAM'] || Rake.application.top_level_tasks.first if program == "default" next end @@ -62,47 +65,55 @@ task :compile do # paths workflow_path = File.join(".github", "workflows", "compile-#{program}.yaml") unless File.exist?(workflow_path) - raise "Workflow YAML config file not found: #{workflow_path}" + warn "Workflow YAML config file not found, compiling just with source folder: #{workflow_path}" + src_path = program + lib_path = "" + aux_files = "" + else + workflow = YAML.load_file(workflow_path) + paths = workflow.dig("jobs", "compile", "strategy", "matrix", "program")[0] + src_path = paths["src"] + lib_path = paths["lib"] + aux_files = paths["aux"] + if src_path.nil? || src_path.strip.empty? + raise "Error: could not extract src/lib/aux dependencies from #{workflow_path}" + end end - workflow = YAML.load_file(workflow_path) - - paths = workflow.dig("jobs", "compile", "strategy", "matrix", "program")[0] - src_path = paths["src"] - lib_path = paths["lib"] - aux_path = paths["aux"] - if src_path.nil? || src_path.strip.empty? - raise "Error: could not extract src/lib/aux dependencies from #{workflow_path}" - end - + # source src_path = File.join(src_folder, src_path) unless Dir.exist?(src_path) raise "Error: folder '#{src_path}' does not exist." end + src_files = Dir.glob("#{src_path}/**/*.{h,c,cpp,properties}").join(' ') # libs unless lib_path.nil? || lib_path.strip.empty? paths = lib_path.strip.split(/\s+/).map do |path| if Dir.exist?(path) - File.join(path, src_folder) + path elsif Dir.exists?(File.join(lib_folder, path)) - File.join(lib_folder, path, src_folder) + File.join(lib_folder, path) else - raise "Warning: could not find '#{path}' library in root or #{lib_folder} - rake sure it exists" + raise "Could not find '#{path}' library in root or #{lib_folder} - make sure it exists" end end.compact lib_path = paths.join(' ') + lib_files = paths.map do |path| + Dir.glob("#{path}/**/*.{h,c,cpp}").join(' ') + end + lib_files = lib_files.join(' ') end # info puts "\nINFO: compiling '#{program}' in the cloud for #{platform} #{version}...." puts " - src path: #{src_path}" puts " - lib paths: #{lib_path}" - puts " - aux files: #{aux_path}" + puts " - aux files: #{aux_files}" puts "\n" - + # compile - sh "particle compile #{platform} #{src_path} #{src_path}/project.properties #{lib_path} #{aux_path} --target #{version} --saveTo #{bin_folder}/#{program}-#{platform}-#{version}.bin", verbose: false + sh "particle compile #{platform} #{src_files} #{lib_files} #{aux_files} --target #{version} --saveTo #{bin_folder}/#{program}-#{platform}-#{version}.bin", verbose: false end ### FLASH ### @@ -147,6 +158,7 @@ desc "list available devices connected to USB" task :list do puts "\nINFO: querying list of available USB devices..." sh "particle usb list" + sh "particle identify" end desc "get MAC address of device connected to USB" @@ -200,6 +212,7 @@ end desc "update device OS" task :update do puts "\nINFO: updating device OS of the device connected on USB to #{version}..." + puts "Careful, the firmware on the device needs to be compatible with the new OS (tinker is usually safe)." print "Are you sure you want to continue? (y/N): " answer = STDIN.gets.strip.downcase unless answer == 'y' || answer == 'yes' @@ -211,18 +224,20 @@ end desc "flash the tinker app" # commands: digitalWrite "D7,HIGH", analogWrite, digitalRead, analogRead "A0" -task :update do +task :tinker do puts "\nINFO: flashing tinker..." sh "particle flash --usb tinker" end desc "used by Guardfile to automatically re-compile binaries on code changes" -task :autoCompile, [:program, :paths] do |t, args| +task :autoCompile, [:program, :platform, :version, :paths] do |t, args| puts "\n**** RE-COMPILE AUTOMATICALLY ****" - puts "program: #{args.program}\nmodified files:" + puts "program: #{args.program}" + puts "platform: #{args.platform} #{args.version}" + puts "modified files:" args.paths.each do |path| puts " - #{path}" end - sh "bundle exec rake #{args.program}", verbose: false + sh "bundle exec rake compile PROGRAM=#{args.program} PLATFORM=#{args.platform} VERSION=#{args.version}", verbose: false puts "**** RE-COMPILE COMPLETE ****" end \ No newline at end of file diff --git a/lib/MyLib/src/lib.h b/lib/MyLib/src/lib.h deleted file mode 100644 index 24b5389..0000000 --- a/lib/MyLib/src/lib.h +++ /dev/null @@ -1 +0,0 @@ -#define MY_CONST 42 \ No newline at end of file diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..372325f --- /dev/null +++ b/project.properties @@ -0,0 +1,2 @@ +# note: this project.properties file needs to exist for VSCode IntelliSense to work properly for the particle code base, it serves no other purpose +name=LabLoggerLibs \ No newline at end of file diff --git a/src/blink/blink.cpp b/src/blink/blink.cpp index d1a81c9..ccbd4bc 100644 --- a/src/blink/blink.cpp +++ b/src/blink/blink.cpp @@ -1,5 +1,4 @@ #include "Particle.h" -#include "lib.h" // generic blink test @@ -34,7 +33,9 @@ void info_handler(const char *topic, const char *data) { } // enable sysstem treading +#ifndef SYSTEM_VERSION_v620 SYSTEM_THREAD(ENABLED); +#endif // manual mode SYSTEM_MODE(MANUAL); diff --git a/src/i2c_scanner/i2c_scanner.cpp b/src/i2c_scanner/i2c_scanner.cpp new file mode 100644 index 0000000..23e462a --- /dev/null +++ b/src/i2c_scanner/i2c_scanner.cpp @@ -0,0 +1,51 @@ +#include "Particle.h" +#include "Wire.h" + +// enable system treading +#ifndef SYSTEM_VERSION_v620 +SYSTEM_THREAD(ENABLED); +#endif + +// manual mode, no wifi +SYSTEM_MODE(MANUAL); + +// log handler +SerialLogHandler logHandler(LOG_LEVEL_TRACE); + +// setup +void setup() { + Wire.begin(); +} + +// loop +uint counter = 0; +unsigned long timer = 0; +const std::chrono::milliseconds wait = 2s; +const std::chrono::milliseconds timeout = 100ms; + +void loop() { + byte error, address; + int n_devices = 0; + + if (millis() - timer > wait.count()) { + + Log.info("I2C scan #%d...", ++counter); + + for(address = 1; address < 127; address++ ) { + timer = millis(); + Wire.beginTransmission(address); + error = Wire.endTransmission(); + if (error == 0) { + Log.info("I2C device #%d at address 0x%02X", ++n_devices, address); + } else if (error==4) { + Log.error("Unknown error at address 0x%02X", address); + } else if (millis() - timer > timeout.count()) { + Log.error("Timeout at address 0x%02X, there might be an I2C issue.", address); + } + } + if (n_devices == 0) + Log.info("No I2C devices found.\n"); + else + Log.info("Done.\n"); + } +} \ No newline at end of file diff --git a/src/i2c_scanner/project.properties b/src/i2c_scanner/project.properties new file mode 100644 index 0000000..065e230 --- /dev/null +++ b/src/i2c_scanner/project.properties @@ -0,0 +1 @@ +name=i2c_scanner \ No newline at end of file diff --git a/src/publish/project.properties b/src/publish/project.properties index f89a431..be3a5c8 100644 --- a/src/publish/project.properties +++ b/src/publish/project.properties @@ -1 +1,17 @@ -name=publish \ No newline at end of file +name=publish + +## DEPENDENCIES ## +# dependencies added in lib/ as submodules to include full codebase in repo +# these will be included in `rake PROGRA` compile as long as they are listed +# in .github/workflows/compile-PROGRAM.yaml under program -> lib +# if a dependency is not available locally in lib/, comment it in here + +#dependencies.DeviceNameHelperRK=0.0.1 + +#dependencies.FileHelperRK=0.0.3 + +#dependencies.PublishQueueExtRK=0.0.7 +#dependencies.SequentialFileRK=0.0.3 # dependency of PublishQueueExtRK + +#dependencies.SparkFun_Qwiic_OpenLog_Arduino_Library=3.0.1 +