Skip to content

Instantly share code, notes, and snippets.

@ladislas
Created September 14, 2020 10:26
Show Gist options
  • Save ladislas/c4c7071e22a18c1f2bbd6dd33c1dc0ee to your computer and use it in GitHub Desktop.
Save ladislas/c4c7071e22a18c1f2bbd6dd33c1dc0ee to your computer and use it in GitHub Desktop.
STM32CubeMX .ioc file editor and pin names generator
#!/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
#!/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}... ✅"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment