Skip to content

Instantly share code, notes, and snippets.

@ladislas
Created September 14, 2020 10:26

Revisions

  1. ladislas created this gist Sep 14, 2020.
    324 changes: 324 additions & 0 deletions ioc_editor.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,324 @@
    #!/usr/bin/env ruby

    # Leka - LekaOS
    # Copyright 2020 APF France handicap
    # SPDX-License-Identifier: Apache-2.0

    require 'csv'

    #
    # MARK:- Deal with argv
    #

    def puts_help
    puts ""
    puts "Choose one of:"
    puts " --check-signals <path/to/ioc/file>"
    puts " --fix-signals <path/to/ioc/file>"
    puts " --check-labels <path/to/ioc/file>"
    puts " --fix-labels <path/to/ioc/file>"
    puts " --rm-scripts <path/to/ioc/file>"
    end

    arguments_available = ["--check-signals", "--check-labels", "--fix-signals", "--fix-labels", "--rm-scripts"]
    arguments_passed = ARGV

    $arg_action = arguments_passed[0]
    $arg_path = arguments_passed[1]

    if arguments_passed.include? "--help"
    puts_help
    exit
    end

    if arguments_passed.length != 2
    puts ""
    puts "❌ The script needs 2 arguments: <action> and <path>"
    puts_help
    exit
    end

    if !arguments_available.include? $arg_action
    puts ""
    puts "❌ #{$arg_action} not available..."
    puts_help
    exit
    end

    $check_signals = false
    $check_labels = false

    (arguments_passed.include? "--check-signals") ? $check_signals = true : $check_signals = false
    (arguments_passed.include? "--check-labels") ? $check_labels = true : $check_labels = false

    $fix_signals = false
    $fix_labels = false

    (arguments_passed.include? "--fix-signals") ? $fix_signals = true : $fix_signals = false
    (arguments_passed.include? "--fix-labels") ? $fix_labels = true : $fix_labels = false

    $rm_scripts = false
    (arguments_passed.include? "--rm-scripts") ? $rm_scripts = true : $rm_scripts = false


    #
    # MARK:- Variables
    #

    # .ioc File

    $ioc_file_path = $arg_path
    $ioc_file_prefix = "Leka-MCU_Pins"
    $ioc_file_version = File.basename(File.dirname($ioc_file_path))
    $ioc_file = File.basename($ioc_file_path)
    $ioc_dir_path = File.dirname($ioc_file_path)

    puts ""
    puts "Getting ioc file information..."
    puts " ioc file directory: #{$ioc_dir_path}"
    puts " ioc file name: #{$ioc_file}"
    puts " ioc file version: #{$ioc_file_version}"
    puts "Getting ioc file information... ✅"

    # CSV Files

    pin_csv_reference_file = "#{$ioc_dir_path}/#{$ioc_file_prefix}-v#{$ioc_file_version}-reference.csv"
    pin_csv_generated_file = "#{$ioc_dir_path}/#{$ioc_file_prefix}-v#{$ioc_file_version}-generated.csv"

    $pin_csv_reference = CSV.parse(File.read(pin_csv_reference_file), headers: true)
    $pin_csv_generated = CSV.parse(File.read(pin_csv_generated_file), headers: true)

    # CSV Headers - Position, Name, Type, Signal, Label

    $header_position = "Position"
    $header_name = "Name"
    $header_type = "Type"
    $header_signal = "Signal"
    $header_label = "Label"

    # Script files

    $fix_signals_file = "#{$ioc_dir_path}/fix_signals.txt"
    $fix_labels_file = "#{$ioc_dir_path}/fix_labels.txt"


    #
    # MARK:- Functions
    #

    # Helpers

    def not_power_or_reset ( string )
    if string == "Power" || string == "Reset_State"
    return false
    end
    return true
    end

    def puts_error(pin_number, pin_name, expected, found)
    puts "#{pin_number} / #{pin_name} - expected: #{expected} -- found: #{found.empty? ? "empty" : found}"
    end

    def puts_okay(pin_number, pin_name, expected, found)
    puts "#{pin_number} / #{pin_name} - expected: #{expected} -- found: #{found.empty? ? "empty" : found}"
    end

    def puts_script_instructions(file)
    puts "Generating script to fix pins' labels... ✅"
    puts ""
    puts "You can run the fix signal script with the following:"
    puts ""
    puts " $ stm32cubemx -i"
    puts ""
    puts " MX> config load #{$ioc_file_path}"
    puts " MX> script #{$ioc_dir_path}/#{File.basename(file)}"
    puts " MX> config save"
    puts " MX> csv pinout #{$pin_csv_generated_file}"
    puts ""
    end

    # Checkers

    def check_name_and_position
    error_name_position = false

    puts ""
    puts "Checking pins' positions & names..."

    $pin_csv_reference.each_with_index do |row, index|
    pin_number = index + 1

    # Check positions
    if row[$header_position] != $pin_csv_generated[index][$header_position]
    puts "#{pin_number} - ❌ position - reference: #{row[$header_position]} -- ioc: #{$pin_csv_generated[index][$header_position]}"
    error_name_position = true
    end

    # Check names
    if row[$header_name] != $pin_csv_generated[index][$header_name]
    puts "#{pin_number} - ❌ name - reference: #{row[$header_name]} -- ioc: #{$pin_csv_generated[index][$header_name]}"
    error_name_position = true
    end
    end

    if error_name_position
    puts "Checking pins' positions & names... ❌"
    exit
    else
    puts "Checking pins' positions & names... ✅"
    end
    end

    def compare_ref_and_ioc
    puts ""
    puts "Checking reference file and .ioc file have the same number of pins..."
    puts " ref: #{$pin_csv_reference.length}"
    puts " ioc: #{$pin_csv_generated.length}"
    if $pin_csv_reference.length == $pin_csv_generated.length
    puts "Checking reference file and .ioc file have the same number of pins... ✅"
    else
    puts "Checking reference file and .ioc file have the same number of pins... ❌"
    exit
    end
    end

    #
    # MARK:- Compare reference file and .ioc file
    #

    compare_ref_and_ioc

    #
    # MARK:- Check pins and positions are correct
    #

    check_name_and_position

    #
    # MARK:- Check signals
    #

    if $check_signals || $fix_signals
    puts ""
    puts "Checking pins' signals..."

    $error_signals = false

    $pin_csv_reference.each_with_index do |row, index|
    pin_number = index + 1
    if row[$header_signal] != $pin_csv_generated[index][$header_signal] && not_power_or_reset(row[$header_signal])
    puts_error(pin_number, row[$header_name], row[$header_signal], $pin_csv_generated[index][$header_signal])
    $error_signals = true
    end
    end

    if $error_signals
    puts "Checking pins' signals... ❌"
    $fix_signals_needed = true
    else
    puts "Checking pins' signals... ✅"
    end
    end

    #
    # MARK:- Fix signals
    #

    # set pin <pin name> <signal name>
    # set pin PA12 UART4_TX
    # def puts_error(pin_number, pin_name, expected, found)

    if $fix_signals
    puts ""
    puts "Generating script to fix pins' signals..."

    if !$fix_signals_needed
    puts "No need to generate a script to fix pins' signals... 🎉"
    return
    end

    file = File.new($fix_signals_file, "w")

    $pin_csv_reference.each_with_index do |row, index|
    pin_number = index + 1
    if row[$header_signal] != $pin_csv_generated[index][$header_signal] && not_power_or_reset(row[$header_signal])
    fix = "set pin #{row[$header_name]} #{row[$header_signal]}"
    puts fix
    file.puts fix
    end
    end

    file.close

    puts_script_instructions(file)
    end

    #
    # MARK:- Check labels
    #

    if $check_labels || $fix_labels
    puts ""
    puts "Checking pins' labels..."

    $error_labels = false

    $pin_csv_reference.each_with_index do |row, index|
    pin_number = index + 1
    if row[$header_label] != $pin_csv_generated[index][$header_label] && not_power_or_reset(row[$header_signal])
    puts_error(pin_number, row[$header_name], row[$header_label], $pin_csv_generated[index][$header_label])
    $error_labels = true
    end
    end

    if $error_labels
    puts "Checking pins' labels... ❌"
    $fix_labels_needed = true
    else
    puts "Checking pins' labels... ✅"
    end
    end

    #
    # MARK:- Fix labels
    #

    # set gpio parameters <matching pin> <param name> <param value>
    # set gpio parameters PE4 GPIO_Label MOTOR_RIGHT_DIRECTION

    if $fix_labels
    puts ""
    puts "Generating script to fix pins' labels..."

    if !$fix_labels_needed
    puts "No need to generate a script to fix pins' labels... 🎉"
    return
    end

    file = File.new($fix_labels_file, "w")

    $pin_csv_reference.each_with_index do |row, index|
    pin_number = index + 1
    if row[$header_label] != $pin_csv_generated[index][$header_label] && not_power_or_reset(row[$header_signal])
    fix = "set gpio parameters #{row[$header_name]} GPIO_Label #{row[$header_label]}"
    puts fix
    file.puts fix
    end
    end

    file.close

    puts_script_instructions(file)
    end

    #
    # MARK:- Remove scripts
    #

    if $rm_scripts
    puts ""
    puts "Removing script files..."
    File.delete($fix_labels_file) if File.exist?($fix_labels_file)
    File.delete($fix_signals_file) if File.exist?($fix_signals_file)
    puts "Removing script files... ✅"
    end
    166 changes: 166 additions & 0 deletions pin_names_generator.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,166 @@
    #!/usr/bin/env ruby

    # Leka - LekaOS
    # Copyright 2020 APF France handicap
    # SPDX-License-Identifier: Apache-2.0

    require 'csv'
    require 'fileutils'


    #
    # MARK:- Deal with argv
    #

    def puts_help
    puts ""
    end

    arguments_passed = ARGV

    if arguments_passed.length != 2
    puts ""
    puts "❌ The script needs 2 arguments: <input csv file> <output directory>"
    puts_help
    exit
    end


    #
    # MARK:- Variables
    #

    # CSV File

    $csv_file_path = arguments_passed[0]
    $csv_file_prefix = "Leka-MCU_Pins"
    $csv_file_version = File.basename(File.dirname($csv_file_path))
    $csv_file_name = File.basename($csv_file_path)
    $csv_dir_path = File.dirname($csv_file_path)

    if !$csv_file_name.include? "reference"
    puts ""
    puts "❌ The file chosen is not a reference file..."
    puts_help
    exit
    end

    # CSV Headers - Position, Name, Type, Signal, Label

    $header_position = "Position"
    $header_name = "Name"
    $header_type = "Type"
    $header_signal = "Signal"
    $header_label = "Label"

    # Leka Pin Names File

    $leka_pinmap_path = arguments_passed[1].chomp("/")
    $leka_pinmap_file_name = "LekaPinNames.h"
    $leka_pinmap_file_path = $leka_pinmap_path + "/" + $leka_pinmap_file_name


    #
    # MARK:- Process
    #

    # Output files information

    puts ""
    puts "Getting files information..."
    puts " csv file directory: #{$csv_dir_path}"
    puts " csv file name: #{$csv_file_name}"
    puts " csv file version: #{$csv_file_version}"
    puts " pinmap directory: #{$leka_pinmap_path}"
    puts " pinmap file name: #{$leka_pinmap_file_name}"
    puts "Getting file information... ✅"

    # Parse CSV file

    $pins = CSV.parse(File.read($csv_file_path), headers: true)

    # Create a sorted 2D array with the label and pin name: ["pin label", "pin name"]

    $pins_array = []

    $pins.each_with_index do |pin, index|
    unless pin[$header_label].to_s.strip.empty?
    output = [pin[$header_label], pin[$header_name].insert(2, "_")]
    $pins_array.append(output)
    end
    end

    $pins_array.sort!

    # Group pins by function (BLE, BT, SENSORS, etc.)

    $grouped_pins_array = []

    $pins_array.each_with_index do |pin, index|
    $grouped_pins_array.append(pin)
    if index + 1 < $pins_array.length
    unless pin[0].to_s[0..1] == $pins_array[index + 1][0].to_s[0..1]
    $grouped_pins_array.append(["", ""])
    end
    end
    end

    # Create LekaPinNames.h and create back-up if needed

    puts ""
    puts "Checking if #{$leka_pinmap_file_path} already exists..."

    if(File.exist?($leka_pinmap_file_path))
    puts " #{$leka_pinmap_file_path} already exists, creating a backup..."
    FileUtils.cp $leka_pinmap_file_path, "#{$leka_pinmap_file_path}.#{Time.now.strftime("%Y%m%d%H%M%S")}.bak"
    puts " #{$leka_pinmap_file_path} already exists, creating a backup... ✅"
    else
    puts " #{$leka_pinmap_file_path} doesn't exist, creating file..."
    FileUtils.touch $leka_pinmap_file_path
    puts " #{$leka_pinmap_file_path} doesn't exist, creating file... ✅"
    end

    puts "Checking if #{$leka_pinmap_file_path} already exists... ✅"

    # Add content to LekaPinNames.h

    puts ""
    puts "Writing content to #{$leka_pinmap_file_path}..."

    file = File.new($leka_pinmap_file_path, "w")

    file.puts """
    // Leka - LekaOS
    // Copyright #{Time.now.strftime("%Y")} APF France handicap
    // SPDX-License-Identifier: Apache-2.0
    #ifndef _LEKA_OS_LEKA_PIN_NAMES_H_
    #define _LEKA_OS_LEKA_PIN_NAMES_H_
    #include \"PinNames.h\"
    // LekaPinNames.h v#{$csv_file_version}
    // Generated on #{Time.now.strftime("%Y/%m/%d")}
    """

    output = ""
    $grouped_pins_array.each do |label, name|
    if [label, name] == ["", ""]
    unless output.empty?
    output = ""
    file.puts output
    end
    else
    unless label.include? "MIPI" or label.include? "FMC"
    output = "constexpr PinName " + label.ljust(28) + " = " + name + ";"
    file.puts output
    end
    end
    end

    file.puts """
    #endif // _LEKA_OS_LEKA_PIN_NAMES_H_
    """

    puts "Writing content to #{$leka_pinmap_file_path}... ✅"